diff --git a/android/framework/encode/CMakeLists.txt b/android/framework/encode/CMakeLists.txt index 79a48ca26..935bbfde6 100644 --- a/android/framework/encode/CMakeLists.txt +++ b/android/framework/encode/CMakeLists.txt @@ -38,6 +38,8 @@ target_sources(gfxrecon_encode ${GFXRECON_SOURCE_DIR}/framework/encode/vulkan_state_writer.h ${GFXRECON_SOURCE_DIR}/framework/encode/vulkan_state_writer.cpp ${GFXRECON_SOURCE_DIR}/framework/encode/vulkan_track_struct.h + ${GFXRECON_SOURCE_DIR}/framework/encode/vulkan_capture_common.cpp + ${GFXRECON_SOURCE_DIR}/framework/encode/vulkan_capture_common.h ${GFXRECON_SOURCE_DIR}/framework/generated/generated_encode_pnext_struct.cpp ${GFXRECON_SOURCE_DIR}/framework/generated/generated_vulkan_api_call_encoders.h ${GFXRECON_SOURCE_DIR}/framework/generated/generated_vulkan_api_call_encoders.cpp diff --git a/framework/encode/CMakeLists.txt b/framework/encode/CMakeLists.txt index c615b545e..5616f7f4e 100644 --- a/framework/encode/CMakeLists.txt +++ b/framework/encode/CMakeLists.txt @@ -93,6 +93,8 @@ target_sources(gfxrecon_encode ${CMAKE_CURRENT_LIST_DIR}/struct_pointer_encoder.h ${CMAKE_CURRENT_LIST_DIR}/vulkan_capture_manager.h ${CMAKE_CURRENT_LIST_DIR}/vulkan_capture_manager.cpp + ${CMAKE_CURRENT_LIST_DIR}/vulkan_capture_common.h + ${CMAKE_CURRENT_LIST_DIR}/vulkan_capture_common.cpp ${CMAKE_CURRENT_LIST_DIR}/vulkan_device_address_tracker.h ${CMAKE_CURRENT_LIST_DIR}/vulkan_device_address_tracker.cpp ${CMAKE_CURRENT_LIST_DIR}/vulkan_handle_wrappers.h diff --git a/framework/encode/vulkan_capture_common.cpp b/framework/encode/vulkan_capture_common.cpp new file mode 100644 index 000000000..b012a22b0 --- /dev/null +++ b/framework/encode/vulkan_capture_common.cpp @@ -0,0 +1,260 @@ +/* + ** Copyright (c) 2024 LunarG, Inc. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a + ** copy of this software and associated documentation files (the "Software"), + ** to deal in the Software without restriction, including without limitation + ** the rights to use, copy, modify, merge, publish, distribute, sublicense, + ** and/or sell copies of the Software, and to permit persons to whom the + ** Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in + ** all copies or substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ** DEALINGS IN THE SOFTWARE. + */ + +#include "vulkan_capture_common.h" + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#include +#endif + +GFXRECON_BEGIN_NAMESPACE(gfxrecon) +GFXRECON_BEGIN_NAMESPACE(encode) + +void CommonWriteCreateHardwareBufferCmd(format::ThreadId thread_id, + format::HandleId memory_id, + AHardwareBuffer* hardware_buffer, + const std::vector& plane_info, + VulkanCaptureManager* vulkan_capture_manager, + VulkanStateWriter* vulkan_state_writer) +{ +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + if (vulkan_capture_manager && !vulkan_capture_manager->IsCaptureModeWrite()) + { + return; + } + assert(hardware_buffer != nullptr); + + format::CreateHardwareBufferCommandHeader create_buffer_cmd; + + create_buffer_cmd.meta_header.block_header.type = format::BlockType::kMetaDataBlock; + create_buffer_cmd.meta_header.block_header.size = format::GetMetaDataBlockBaseSize(create_buffer_cmd); + create_buffer_cmd.meta_header.meta_data_id = format::MakeMetaDataId( + format::ApiFamilyId::ApiFamily_Vulkan, format::MetaDataType::kCreateHardwareBufferCommand); + create_buffer_cmd.thread_id = thread_id; + create_buffer_cmd.memory_id = memory_id; + create_buffer_cmd.buffer_id = reinterpret_cast(hardware_buffer); + + // Get AHB description data. + AHardwareBuffer_Desc ahb_desc = {}; + AHardwareBuffer_describe(hardware_buffer, &ahb_desc); + + create_buffer_cmd.format = ahb_desc.format; + create_buffer_cmd.width = ahb_desc.width; + create_buffer_cmd.height = ahb_desc.height; + create_buffer_cmd.stride = ahb_desc.stride; + create_buffer_cmd.usage = ahb_desc.usage; + create_buffer_cmd.layers = ahb_desc.layers; + + size_t planes_size = 0; + + if (plane_info.empty()) + { + create_buffer_cmd.planes = 0; + } + else + { + create_buffer_cmd.planes = static_cast(plane_info.size()); + // Update size of packet with compressed or uncompressed data size. + planes_size = sizeof(plane_info[0]) * plane_info.size(); + create_buffer_cmd.meta_header.block_header.size += planes_size; + } + + if (vulkan_capture_manager) + { + if (planes_size > 0) + { + vulkan_capture_manager->CombineAndWriteToFile( + { { &create_buffer_cmd, sizeof(create_buffer_cmd) }, { plane_info.data(), planes_size } }); + } + else + { + vulkan_capture_manager->WriteToFile(&create_buffer_cmd, sizeof(create_buffer_cmd)); + } + } + else if (vulkan_state_writer) + { + vulkan_state_writer->OutputStreamWrite(&create_buffer_cmd, sizeof(create_buffer_cmd)); + + if (planes_size > 0) + { + vulkan_state_writer->OutputStreamWrite(plane_info.data(), planes_size); + } + } +#else + GFXRECON_UNREFERENCED_PARAMETER(thread_id); + GFXRECON_UNREFERENCED_PARAMETER(memory_id); + GFXRECON_UNREFERENCED_PARAMETER(hardware_buffer); + GFXRECON_UNREFERENCED_PARAMETER(plane_info); + GFXRECON_UNREFERENCED_PARAMETER(vulkan_capture_manager); + GFXRECON_UNREFERENCED_PARAMETER(vulkan_state_writer); + + GFXRECON_LOG_ERROR("Skipping create AHardwareBuffer command write for unsupported platform"); +#endif +} + +static void CommonWriteFillMemoryCmd(format::HandleId memory_id, + uint64_t size, + const void* data, + VulkanCaptureManager* vulkan_capture_manager, + VulkanStateWriter* vulkan_state_writer) +{ + if (vulkan_capture_manager) + { + vulkan_capture_manager->WriteFillMemoryCmd(memory_id, 0u, size, data); + } + else + { + vulkan_state_writer->WriteFillMemoryCmd(memory_id, 0u, size, data); + } +} + +void CommonProcessHardwareBuffer(format::ThreadId thread_id, + format::HandleId memory_id, + AHardwareBuffer* hardware_buffer, + size_t allocation_size, + VulkanCaptureManager* vulkan_capture_manager, + VulkanStateWriter* vulkan_state_writer) +{ +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + assert(hardware_buffer != nullptr); + + // If this is the first device memory object to reference the hardware buffer, write a buffer creation + // command to the capture file and setup memory tracking. + + std::vector plane_info; + + AHardwareBuffer_Desc desc; + AHardwareBuffer_describe(hardware_buffer, &desc); + + if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) != 0) + { + void* data = nullptr; + int result = -1; + + // The multi-plane functions are declared for API 26, but are only available to link with API 29. So, this + // could be turned into a run-time check dependent on dlsym returning a valid pointer for + // AHardwareBuffer_lockPlanes. +#if __ANDROID_API__ >= 29 + AHardwareBuffer_Planes ahb_planes; + result = + AHardwareBuffer_lockPlanes(hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &ahb_planes); + if (result == 0) + { + data = ahb_planes.planes[0].data; + + for (uint32_t i = 0; i < ahb_planes.planeCount; ++i) + { + format::HardwareBufferPlaneInfo ahb_plane_info; + ahb_plane_info.offset = + reinterpret_cast(ahb_planes.planes[i].data) - reinterpret_cast(data); + ahb_plane_info.pixel_stride = ahb_planes.planes[i].pixelStride; + ahb_plane_info.row_pitch = ahb_planes.planes[i].rowStride; + plane_info.emplace_back(std::move(ahb_plane_info)); + } + } + else + { + GFXRECON_LOG_WARNING("AHardwareBuffer_lockPlanes failed: AHardwareBuffer_lock will be used instead"); + } +#endif + + // Write CreateHardwareBufferCmd with or without the AHB payload + CommonWriteCreateHardwareBufferCmd( + thread_id, memory_id, hardware_buffer, plane_info, vulkan_capture_manager, vulkan_state_writer); + + // If AHardwareBuffer_lockPlanes failed (or is not available) try AHardwareBuffer_lock + if (result != 0) + { + result = AHardwareBuffer_lock(hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &data); + } + + if (result == 0 && data != nullptr) + { + CommonWriteFillMemoryCmd(memory_id, allocation_size, data, vulkan_capture_manager, vulkan_state_writer); + + if (vulkan_capture_manager) + { + // Track the memory with the PageGuardManager + const auto tracking_mode = vulkan_capture_manager->GetMemoryTrackingMode(); + if ((tracking_mode == CaptureSettings::MemoryTrackingMode::kPageGuard || + tracking_mode == CaptureSettings::MemoryTrackingMode::kUserfaultfd) && + vulkan_capture_manager->GetPageGuardTrackAhbMemory()) + { + GFXRECON_CHECK_CONVERSION_DATA_LOSS(size_t, allocation_size); + + util::PageGuardManager* manager = util::PageGuardManager::Get(); + assert(manager != nullptr); + + manager->AddTrackedMemory(memory_id, + data, + 0, + static_cast(allocation_size), + util::PageGuardManager::kNullShadowHandle, + false, // No shadow memory for the imported AHB memory. + false); // Write watch is not supported for this case. + } + } + + result = AHardwareBuffer_unlock(hardware_buffer, nullptr); + if (result != 0) + { + GFXRECON_LOG_ERROR("AHardwareBuffer_unlock failed"); + } + } + else + { + GFXRECON_LOG_ERROR( + "AHardwareBuffer_lock failed: hardware buffer data will be omitted from the capture file"); + + // Dump zeros for AHB payload. + std::vector zeros(allocation_size, 0); + CommonWriteFillMemoryCmd( + memory_id, zeros.size(), zeros.data(), vulkan_capture_manager, vulkan_state_writer); + } + } + else + { + // The AHB is not CPU-readable + + // Write CreateHardwareBufferCmd without the AHB payload + CommonWriteCreateHardwareBufferCmd( + thread_id, memory_id, hardware_buffer, plane_info, vulkan_capture_manager, vulkan_state_writer); + + // Dump zeros for AHB payload. + std::vector zeros(allocation_size, 0); + CommonWriteFillMemoryCmd(memory_id, zeros.size(), zeros.data(), vulkan_capture_manager, vulkan_state_writer); + + GFXRECON_LOG_WARNING("AHardwareBuffer cannot be read: hardware buffer data will be omitted " + "from the capture file"); + } +#else + GFXRECON_UNREFERENCED_PARAMETER(thread_id); + GFXRECON_UNREFERENCED_PARAMETER(memory_id); + GFXRECON_UNREFERENCED_PARAMETER(hardware_buffer); + GFXRECON_UNREFERENCED_PARAMETER(allocation_size); + GFXRECON_UNREFERENCED_PARAMETER(vulkan_capture_manager); + GFXRECON_UNREFERENCED_PARAMETER(vulkan_state_writer); +#endif +} + +GFXRECON_END_NAMESPACE(encode) +GFXRECON_END_NAMESPACE(gfxrecon) diff --git a/framework/encode/vulkan_capture_common.h b/framework/encode/vulkan_capture_common.h new file mode 100644 index 000000000..76bc5a0c2 --- /dev/null +++ b/framework/encode/vulkan_capture_common.h @@ -0,0 +1,53 @@ +/* + ** Copyright (c) 2024 LunarG, Inc. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a + ** copy of this software and associated documentation files (the "Software"), + ** to deal in the Software without restriction, including without limitation + ** the rights to use, copy, modify, merge, publish, distribute, sublicense, + ** and/or sell copies of the Software, and to permit persons to whom the + ** Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in + ** all copies or substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ** DEALINGS IN THE SOFTWARE. + */ + +#ifndef GFXRECON_ENCODE_VULKAN_CAPTURE_COMMON_H +#define GFXRECON_ENCODE_VULKAN_CAPTURE_COMMON_H + +#include "encode/parameter_encoder.h" +#include "vulkan/vulkan.h" +#include "format/format.h" +#include "format/platform_types.h" +#include "vulkan_capture_manager.h" +#include "vulkan_state_writer.h" + +GFXRECON_BEGIN_NAMESPACE(gfxrecon) +GFXRECON_BEGIN_NAMESPACE(encode) + +void CommonWriteCreateHardwareBufferCmd(format::ThreadId thread_id, + format::HandleId memory_id, + AHardwareBuffer* hardware_buffer, + const std::vector& plane_info, + VulkanCaptureManager* vulkan_capture_manager, + VulkanStateWriter* vulkan_state_writer); + +void CommonProcessHardwareBuffer(format::ThreadId thread_id, + format::HandleId memory_id, + AHardwareBuffer* hardware_buffer, + size_t allocation_size, + VulkanCaptureManager* vulkan_capture_manager, + VulkanStateWriter* vulkan_state_writer); + +GFXRECON_END_NAMESPACE(encode) +GFXRECON_END_NAMESPACE(gfxrecon) + +#endif // GFXRECON_ENCODE_VULKAN_CAPTURE_COMMON_H diff --git a/framework/encode/vulkan_capture_manager.cpp b/framework/encode/vulkan_capture_manager.cpp index 04640f9db..87ff3e523 100644 --- a/framework/encode/vulkan_capture_manager.cpp +++ b/framework/encode/vulkan_capture_manager.cpp @@ -33,6 +33,7 @@ #include "encode/vulkan_handle_wrapper_util.h" #include "encode/vulkan_state_writer.h" +#include "encode/vulkan_capture_common.h" #include "format/format_util.h" #include "generated/generated_vulkan_struct_handle_wrappers.h" #include "graphics/vulkan_check_buffer_references.h" @@ -219,74 +220,6 @@ void VulkanCaptureManager::WriteResizeWindowCmd2(format::HandleId s } } -void VulkanCaptureManager::WriteCreateHardwareBufferCmd(format::HandleId memory_id, - AHardwareBuffer* buffer, - const std::vector& plane_info) -{ - if (IsCaptureModeWrite()) - { -#if defined(VK_USE_PLATFORM_ANDROID_KHR) - assert(buffer != nullptr); - - format::CreateHardwareBufferCommandHeader create_buffer_cmd; - - auto thread_data = GetThreadData(); - assert(thread_data != nullptr); - - create_buffer_cmd.meta_header.block_header.type = format::BlockType::kMetaDataBlock; - create_buffer_cmd.meta_header.block_header.size = format::GetMetaDataBlockBaseSize(create_buffer_cmd); - create_buffer_cmd.meta_header.meta_data_id = format::MakeMetaDataId( - format::ApiFamilyId::ApiFamily_Vulkan, format::MetaDataType::kCreateHardwareBufferCommand); - create_buffer_cmd.thread_id = thread_data->thread_id_; - create_buffer_cmd.memory_id = memory_id; - create_buffer_cmd.buffer_id = reinterpret_cast(buffer); - - // Get AHB description data. - AHardwareBuffer_Desc ahb_desc = {}; - AHardwareBuffer_describe(buffer, &ahb_desc); - - create_buffer_cmd.format = ahb_desc.format; - create_buffer_cmd.width = ahb_desc.width; - create_buffer_cmd.height = ahb_desc.height; - create_buffer_cmd.stride = ahb_desc.stride; - create_buffer_cmd.usage = ahb_desc.usage; - create_buffer_cmd.layers = ahb_desc.layers; - - size_t planes_size = 0; - - if (plane_info.empty()) - { - create_buffer_cmd.planes = 0; - } - else - { - create_buffer_cmd.planes = static_cast(plane_info.size()); - // Update size of packet with size of plane info. - planes_size = sizeof(plane_info[0]) * plane_info.size(); - create_buffer_cmd.meta_header.block_header.size += planes_size; - } - - { - if (planes_size > 0) - { - CombineAndWriteToFile( - { { &create_buffer_cmd, sizeof(create_buffer_cmd) }, { plane_info.data(), planes_size } }); - } - else - { - WriteToFile(&create_buffer_cmd, sizeof(create_buffer_cmd)); - } - } -#else - GFXRECON_UNREFERENCED_PARAMETER(memory_id); - GFXRECON_UNREFERENCED_PARAMETER(buffer); - GFXRECON_UNREFERENCED_PARAMETER(plane_info); - - GFXRECON_LOG_ERROR("Skipping create AHardwareBuffer command write for unsupported platform"); -#endif - } -} - void VulkanCaptureManager::WriteDestroyHardwareBufferCmd(AHardwareBuffer* buffer) { if (IsCaptureModeWrite()) @@ -1720,179 +1653,51 @@ VkMemoryPropertyFlags VulkanCaptureManager::GetMemoryProperties(vulkan_wrappers: return memory_properties->memoryTypes[memory_type_index].propertyFlags; } -void VulkanCaptureManager::ProcessReferenceToAndroidHardwareBuffer(VkDevice device, AHardwareBuffer* hardware_buffer) +void VulkanCaptureManager::ProcessHardwareBuffer(format::ThreadId thread_id, + AHardwareBuffer* hardware_buffer, + VkDevice device) { #if defined(VK_USE_PLATFORM_ANDROID_KHR) - assert(hardware_buffer != nullptr); - auto device_wrapper = vulkan_wrappers::GetWrapper(device); - VkDevice device_unwrapped = device_wrapper->handle; - auto device_table = vulkan_wrappers::GetDeviceTable(device); - auto entry = hardware_buffers_.find(hardware_buffer); - if (entry == hardware_buffers_.end()) + if (entry != hardware_buffers_.end()) { - // If this is the first device memory object to reference the hardware buffer, write a buffer creation - // command to the capture file and setup memory tracking. - - std::vector plane_info; - - AHardwareBuffer_Desc desc; - AHardwareBuffer_describe(hardware_buffer, &desc); - - if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) != 0) - { - void* data = nullptr; - int result = -1; - - // The multi-plane functions are declared for API 26, but are only available to link with API 29. So, this - // could be turned into a run-time check dependent on dlsym returning a valid pointer for - // AHardwareBuffer_lockPlanes. -#if __ANDROID_API__ >= 29 - AHardwareBuffer_Planes ahb_planes; - result = AHardwareBuffer_lockPlanes( - hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &ahb_planes); - if (result == 0) - { - data = ahb_planes.planes[0].data; - - for (uint32_t i = 0; i < ahb_planes.planeCount; ++i) - { - format::HardwareBufferPlaneInfo ahb_plane_info; - ahb_plane_info.offset = - reinterpret_cast(ahb_planes.planes[i].data) - reinterpret_cast(data); - ahb_plane_info.pixel_stride = ahb_planes.planes[i].pixelStride; - ahb_plane_info.row_pitch = ahb_planes.planes[i].rowStride; - plane_info.emplace_back(std::move(ahb_plane_info)); - } - } - else - { - GFXRECON_LOG_WARNING("AHardwareBuffer_lockPlanes failed: AHardwareBuffer_lock will be used instead"); - } -#endif - - // Only store buffer IDs and reference count if a creation command is written to the capture file. - format::HandleId memory_id = GetUniqueId(); - - HardwareBufferInfo& ahb_info = hardware_buffers_[hardware_buffer]; - ahb_info.memory_id = memory_id; - ahb_info.reference_count = 0; - - // Write CreateHardwareBufferCmd with or without the AHB payload - WriteCreateHardwareBufferCmd(memory_id, hardware_buffer, plane_info); - - // Query the AHB size - VkAndroidHardwareBufferPropertiesANDROID properties = { - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID - }; - properties.pNext = nullptr; - - VkResult vk_result = - device_table->GetAndroidHardwareBufferPropertiesANDROID(device_unwrapped, hardware_buffer, &properties); - - if (vk_result == VK_SUCCESS) - { - const size_t ahb_size = properties.allocationSize; - assert(ahb_size); - - // If AHardwareBuffer_lockPlanes() failed (or is not available) try AHardwareBuffer_lock() - if (result != 0) - { - result = - AHardwareBuffer_lock(hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &data); - } - - if (result == 0 && data != nullptr) - { - WriteFillMemoryCmd(memory_id, 0, ahb_size, data); - - // Track the memory with the PageGuardManager - if ((GetMemoryTrackingMode() == CaptureSettings::MemoryTrackingMode::kPageGuard || - GetMemoryTrackingMode() == CaptureSettings::MemoryTrackingMode::kUserfaultfd) && - GetPageGuardTrackAhbMemory()) - { - GFXRECON_CHECK_CONVERSION_DATA_LOSS(size_t, ahb_size); - - util::PageGuardManager* manager = util::PageGuardManager::Get(); - assert(manager != nullptr); - - manager->AddTrackedMemory(memory_id, - data, - 0, - static_cast(ahb_size), - util::PageGuardManager::kNullShadowHandle, - false, // No shadow memory for the imported AHB memory. - false); // Write watch is not supported for this case. - } - - result = AHardwareBuffer_unlock(hardware_buffer, nullptr); - if (result != 0) - { - GFXRECON_LOG_ERROR("AHardwareBuffer_unlock failed"); - } - } - else - { - GFXRECON_LOG_ERROR( - "AHardwareBuffer_lock failed: hardware buffer data will be omitted from the capture file"); - - // Dump zeros for AHB payload. - std::vector zeros(ahb_size, 0); - WriteFillMemoryCmd(memory_id, 0, ahb_size, zeros.data()); - } - } - else - { - GFXRECON_LOG_ERROR( - "GetAndroidHardwareBufferPropertiesANDROID failed: hardware buffer data will be omitted " - "from the capture file"); - - // In case AHardwareBuffer_lockPlanes() succeeded - if (result == 0) - { - result = AHardwareBuffer_unlock(hardware_buffer, nullptr); - if (result != 0) - { - GFXRECON_LOG_ERROR("AHardwareBuffer_unlock failed"); - } - } - } - } - else - { - // The AHB is not CPU-readable - // Only store buffer IDs and reference count if a creation command is written to the capture file. - format::HandleId memory_id = GetUniqueId(); - - HardwareBufferInfo& ahb_info = hardware_buffers_[hardware_buffer]; - ahb_info.memory_id = memory_id; - ahb_info.reference_count = 0; + return; + } - WriteCreateHardwareBufferCmd(memory_id, hardware_buffer, plane_info); + format::HandleId memory_id = GetUniqueId(); - GFXRECON_LOG_WARNING("AHardwareBuffer cannot be read: hardware buffer data will be omitted " - "from the capture file"); + HardwareBufferInfo& ahb_info = hardware_buffers_[hardware_buffer]; + ahb_info.memory_id = memory_id; + ahb_info.reference_count = 0; - VkAndroidHardwareBufferPropertiesANDROID properties = { - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID - }; - properties.pNext = nullptr; + auto device_wrapper = vulkan_wrappers::GetWrapper(device); + VkDevice device_unwrapped = device_wrapper->handle; + auto device_table = vulkan_wrappers::GetDeviceTable(device); - VkResult vk_result = - device_table->GetAndroidHardwareBufferPropertiesANDROID(device_unwrapped, hardware_buffer, &properties); + // Query the AHB size + VkAndroidHardwareBufferPropertiesANDROID properties = { + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID + }; + properties.pNext = nullptr; - if (vk_result == VK_SUCCESS) - { - const size_t ahb_size = properties.allocationSize; + VkResult vk_result = + device_table->GetAndroidHardwareBufferPropertiesANDROID(device_unwrapped, hardware_buffer, &properties); - // Dump zeros for AHB payload. - std::vector zeros(ahb_size, 0); - WriteFillMemoryCmd(memory_id, 0, zeros.size(), zeros.data()); - } - } + if (vk_result == VK_SUCCESS) + { + const size_t ahb_size = properties.allocationSize; + assert(ahb_size); + CommonProcessHardwareBuffer(thread_id, memory_id, hardware_buffer, ahb_size, this, nullptr); + } + else + { + GFXRECON_LOG_ERROR("GetAndroidHardwareBufferPropertiesANDROID failed: hardware buffer data will be omitted " + "from the capture file"); } #else + GFXRECON_UNREFERENCED_PARAMETER(thread_id); GFXRECON_UNREFERENCED_PARAMETER(hardware_buffer); + GFXRECON_UNREFERENCED_PARAMETER(device); #endif } @@ -1906,7 +1711,10 @@ void VulkanCaptureManager::ProcessImportAndroidHardwareBuffer(VkDevice d auto memory_wrapper = vulkan_wrappers::GetWrapper(memory); assert((memory_wrapper != nullptr) && (hardware_buffer != nullptr)); - ProcessReferenceToAndroidHardwareBuffer(device, hardware_buffer); + auto thread_data = GetThreadData(); + assert(thread_data != nullptr); + + ProcessHardwareBuffer(thread_data->thread_id_, hardware_buffer, device); auto entry = hardware_buffers_.find(hardware_buffer); GFXRECON_ASSERT(entry != hardware_buffers_.end()); @@ -2699,9 +2507,13 @@ void VulkanCaptureManager::PreProcess_vkGetAndroidHardwareBufferPropertiesANDROI GFXRECON_UNREFERENCED_PARAMETER(pProperties); #if defined(VK_USE_PLATFORM_ANDROID_KHR) auto device_wrapper = vulkan_wrappers::GetWrapper(device); + + auto thread_data = GetThreadData(); + assert(thread_data != nullptr); + if (hardware_buffer != nullptr) { - ProcessReferenceToAndroidHardwareBuffer(device, const_cast(hardware_buffer)); + ProcessHardwareBuffer(thread_data->thread_id_, const_cast(hardware_buffer), device); } #else GFXRECON_UNREFERENCED_PARAMETER(device); diff --git a/framework/encode/vulkan_capture_manager.h b/framework/encode/vulkan_capture_manager.h index c5cd10211..02cbae96d 100644 --- a/framework/encode/vulkan_capture_manager.h +++ b/framework/encode/vulkan_capture_manager.h @@ -1625,9 +1625,6 @@ class VulkanCaptureManager : public ApiCaptureManager uint32_t width, uint32_t height, VkSurfaceTransformFlagBitsKHR pre_transform); - void WriteCreateHardwareBufferCmd(format::HandleId memory_id, - AHardwareBuffer* buffer, - const std::vector& plane_info); void WriteDestroyHardwareBufferCmd(AHardwareBuffer* buffer); void WriteSetDevicePropertiesCommand(format::HandleId physical_device_id, const VkPhysicalDeviceProperties& properties); @@ -1653,7 +1650,7 @@ class VulkanCaptureManager : public ApiCaptureManager VkMemoryPropertyFlags GetMemoryProperties(vulkan_wrappers::DeviceWrapper* device_wrapper, uint32_t memory_type_index); - void ProcessReferenceToAndroidHardwareBuffer(VkDevice device, AHardwareBuffer* hardware_buffer); + void ProcessHardwareBuffer(format::ThreadId thread_id, AHardwareBuffer* hardware_buffer, VkDevice device); void ProcessImportAndroidHardwareBuffer(VkDevice device, VkDeviceMemory memory, AHardwareBuffer* hardware_buffer); void ReleaseAndroidHardwareBuffer(AHardwareBuffer* hardware_buffer); bool CheckBindAlignment(VkDeviceSize memoryOffset); diff --git a/framework/encode/vulkan_state_writer.cpp b/framework/encode/vulkan_state_writer.cpp index fd2356b9b..0e7277c35 100644 --- a/framework/encode/vulkan_state_writer.cpp +++ b/framework/encode/vulkan_state_writer.cpp @@ -26,6 +26,7 @@ #include "encode/struct_pointer_encoder.h" #include "encode/vulkan_handle_wrappers.h" #include "encode/vulkan_state_info.h" +#include "encode/vulkan_capture_common.h" #include "format/format.h" #include "format/format_util.h" #include "util/logging.h" @@ -1314,7 +1315,14 @@ void VulkanStateWriter::WriteDeviceMemoryState(const VulkanStateTable& state_tab for (auto hardware_buffer : hardware_buffers) { const vulkan_wrappers::DeviceMemoryWrapper* wrapper = hardware_buffer.second; - ProcessHardwareBuffer(wrapper->hardware_buffer_memory_id, wrapper->hardware_buffer, wrapper->allocation_size); + CommonProcessHardwareBuffer(thread_id_, + wrapper->hardware_buffer_memory_id, + wrapper->hardware_buffer, + wrapper->allocation_size, + nullptr, + this); + + ++blocks_written_; } #endif @@ -1939,105 +1947,9 @@ void VulkanStateWriter::WriteDeferredOperationJoinCommand(format::HandleId devic parameter_stream_.Clear(); } -void VulkanStateWriter::ProcessHardwareBuffer(format::HandleId memory_id, - AHardwareBuffer* hardware_buffer, - VkDeviceSize allocation_size) +bool VulkanStateWriter::OutputStreamWrite(const void* data, size_t len) { -#if defined(VK_USE_PLATFORM_ANDROID_KHR) - void* data = nullptr; - int result = -1; - - std::vector plane_info; - - AHardwareBuffer_Desc desc; - AHardwareBuffer_describe(hardware_buffer, &desc); - - if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) != 0) - { - // The multi-plane functions are declared for API 26, but are only available to link with API 29. So, this - // could be turned into a run-time check dependent on dlsym returning a valid pointer for - // AHardwareBuffer_lockPlanes. -#if __ANDROID_API__ >= 29 - AHardwareBuffer_Planes ahb_planes; - result = - AHardwareBuffer_lockPlanes(hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &ahb_planes); - if (result == 0) - { - data = ahb_planes.planes[0].data; - - for (uint32_t i = 0; i < ahb_planes.planeCount; ++i) - { - format::HardwareBufferPlaneInfo ahb_plane_info; - ahb_plane_info.offset = - reinterpret_cast(ahb_planes.planes[i].data) - reinterpret_cast(data); - ahb_plane_info.pixel_stride = ahb_planes.planes[i].pixelStride; - ahb_plane_info.row_pitch = ahb_planes.planes[i].rowStride; - plane_info.emplace_back(std::move(ahb_plane_info)); - } - } - else - { - GFXRECON_LOG_WARNING("AHardwareBuffer_lockPlanes failed: AHardwareBuffer_lock will be used instead"); - } -#endif - - // Write CreateHardwareBufferCmd with or without the AHB payload - WriteCreateHardwareBufferCmd(memory_id, hardware_buffer, plane_info); - - // If AHardwareBuffer_lockPlanes failed (or is not available) try AHardwareBuffer_lock - if (result != 0) - { - result = AHardwareBuffer_lock(hardware_buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &data); - } - - if (result == 0) - { - if (data == nullptr) - { - GFXRECON_LOG_WARNING("AHardwareBuffer_lock returned nullptr for data pointer"); - - // Dump zeros for AHB payload. - std::vector zeros(allocation_size, 0); - WriteFillMemoryCmd(memory_id, 0, zeros.size(), zeros.data()); - } - else - { - WriteFillMemoryCmd(memory_id, 0, allocation_size, data); - } - - result = AHardwareBuffer_unlock(hardware_buffer, nullptr); - if (result != 0) - { - GFXRECON_LOG_ERROR("AHardwareBuffer_unlock failed"); - } - } - else - { - GFXRECON_LOG_ERROR( - "AHardwareBuffer_lock failed: hardware buffer data will be omitted from the capture file"); - - // Dump zeros for AHB payload. - std::vector zeros(allocation_size, 0); - WriteFillMemoryCmd(memory_id, 0, zeros.size(), zeros.data()); - } - } - else - { - // Write CreateHardwareBufferCmd without the AHB payload - WriteCreateHardwareBufferCmd(memory_id, hardware_buffer, plane_info); - - // The AHB is not CPU-readable - // Dump zeros for AHB payload. - std::vector zeros(allocation_size, 0); - WriteFillMemoryCmd(memory_id, 0, zeros.size(), zeros.data()); - - GFXRECON_LOG_WARNING("AHardwareBuffer cannot be read: hardware buffer data will be omitted " - "from the capture file"); - } -#else - GFXRECON_UNREFERENCED_PARAMETER(memory_id); - GFXRECON_UNREFERENCED_PARAMETER(hardware_buffer); -#endif + return output_stream_->Write(data, len); } void VulkanStateWriter::ProcessBufferMemory(const vulkan_wrappers::DeviceWrapper* device_wrapper, @@ -3950,65 +3862,6 @@ void VulkanStateWriter::WriteResizeWindowCmd2(format::HandleId surf ++blocks_written_; } -// TODO: This is the same code used by CaptureManager to write command data. It could be moved to a format -// utility. -void VulkanStateWriter::WriteCreateHardwareBufferCmd(format::HandleId memory_id, - AHardwareBuffer* hardware_buffer, - const std::vector& plane_info) -{ -#if defined(VK_USE_PLATFORM_ANDROID_KHR) - assert(hardware_buffer != nullptr); - - format::CreateHardwareBufferCommandHeader create_buffer_cmd; - - create_buffer_cmd.meta_header.block_header.type = format::BlockType::kMetaDataBlock; - create_buffer_cmd.meta_header.block_header.size = format::GetMetaDataBlockBaseSize(create_buffer_cmd); - create_buffer_cmd.meta_header.meta_data_id = format::MakeMetaDataId( - format::ApiFamilyId::ApiFamily_Vulkan, format::MetaDataType::kCreateHardwareBufferCommand); - create_buffer_cmd.thread_id = thread_id_; - create_buffer_cmd.memory_id = memory_id; - create_buffer_cmd.buffer_id = reinterpret_cast(hardware_buffer); - - // Get AHB description data. - AHardwareBuffer_Desc ahb_desc = {}; - AHardwareBuffer_describe(hardware_buffer, &ahb_desc); - - create_buffer_cmd.format = ahb_desc.format; - create_buffer_cmd.width = ahb_desc.width; - create_buffer_cmd.height = ahb_desc.height; - create_buffer_cmd.stride = ahb_desc.stride; - create_buffer_cmd.usage = ahb_desc.usage; - create_buffer_cmd.layers = ahb_desc.layers; - - size_t planes_size = 0; - - if (plane_info.empty()) - { - create_buffer_cmd.planes = 0; - } - else - { - create_buffer_cmd.planes = static_cast(plane_info.size()); - // Update size of packet with compressed or uncompressed data size. - planes_size = sizeof(plane_info[0]) * plane_info.size(); - create_buffer_cmd.meta_header.block_header.size += planes_size; - } - - output_stream_->Write(&create_buffer_cmd, sizeof(create_buffer_cmd)); - - if (planes_size > 0) - { - output_stream_->Write(plane_info.data(), planes_size); - } - - ++blocks_written_; -#else - GFXRECON_UNREFERENCED_PARAMETER(memory_id); - GFXRECON_UNREFERENCED_PARAMETER(hardware_buffer); - GFXRECON_UNREFERENCED_PARAMETER(plane_info); -#endif -} - void VulkanStateWriter::WriteSetDevicePropertiesCommand(format::HandleId physical_device_id, const VkPhysicalDeviceProperties& properties) { diff --git a/framework/encode/vulkan_state_writer.h b/framework/encode/vulkan_state_writer.h index 4747ee67a..97efb4351 100644 --- a/framework/encode/vulkan_state_writer.h +++ b/framework/encode/vulkan_state_writer.h @@ -64,6 +64,10 @@ class VulkanStateWriter uint64_t WriteAssets(const VulkanStateTable& state_table); + bool OutputStreamWrite(const void* data, size_t len); + + void WriteFillMemoryCmd(format::HandleId memory_id, VkDeviceSize offset, VkDeviceSize size, const void* data); + private: // Data structures for processing resource memory snapshots. struct BufferSnapshotInfo @@ -158,9 +162,6 @@ class VulkanStateWriter void WriteDeferredOperationJoinCommand(format::HandleId device_id, format::HandleId deferred_operation_id); - void - ProcessHardwareBuffer(format::HandleId memory_id, AHardwareBuffer* hardware_buffer, VkDeviceSize allocation_size); - void ProcessBufferMemory(const vulkan_wrappers::DeviceWrapper* device_wrapper, const std::vector& buffer_snapshot_info, graphics::VulkanResourcesUtil& resource_util); @@ -298,8 +299,6 @@ class VulkanStateWriter util::MemoryOutputStream* parameter_buffer, util::FileOutputStream* output_stream = nullptr); - void WriteFillMemoryCmd(format::HandleId memory_id, VkDeviceSize offset, VkDeviceSize size, const void* data); - void WriteResizeWindowCmd(format::HandleId surface_id, uint32_t width, uint32_t height); void WriteResizeWindowCmd2(format::HandleId surface_id, @@ -307,10 +306,6 @@ class VulkanStateWriter uint32_t height, VkSurfaceTransformFlagBitsKHR pre_transform); - void WriteCreateHardwareBufferCmd(format::HandleId memory_id, - AHardwareBuffer* hardware_buffer, - const std::vector& plane_info); - void WriteSetDevicePropertiesCommand(format::HandleId physical_device_id, const VkPhysicalDeviceProperties& properties);