diff --git a/garnet/bin/ui/meta/gfx_unittests.cmx b/garnet/bin/ui/meta/gfx_unittests.cmx index 14675aaafb0cec7a887e68ef49dfb77ea7d4eda5..ce55b9f4c87c914e4cc1819f7b1e2724b3bd5272 100644 --- a/garnet/bin/ui/meta/gfx_unittests.cmx +++ b/garnet/bin/ui/meta/gfx_unittests.cmx @@ -2,6 +2,7 @@ "facets": { "fuchsia.test": { "injected-services": { + "fuchsia.sysmem.Allocator": "fuchsia-pkg://fuchsia.com/sysmem_connector#meta/sysmem_connector.cmx", "fuchsia.vulkan.loader.Loader": "fuchsia-pkg://fuchsia.com/vulkan_loader#meta/vulkan_loader.cmx" } } @@ -16,6 +17,7 @@ "services": [ "fuchsia.process.Launcher", "fuchsia.scheduler.ProfileProvider", + "fuchsia.sysmem.Allocator", "fuchsia.tracelink.Registry", "fuchsia.vulkan.loader.Loader" ] diff --git a/garnet/lib/ui/gfx/resources/buffer.cc b/garnet/lib/ui/gfx/resources/buffer.cc index 4bd0ef28c88fa2dd27c3e00a7efff7f5cbfbb618..40716c2160fed5d69e1973e9c78b035dc6b481a0 100644 --- a/garnet/lib/ui/gfx/resources/buffer.cc +++ b/garnet/lib/ui/gfx/resources/buffer.cc @@ -19,6 +19,8 @@ Buffer::Buffer(Session* session, ResourceId id, escher::GpuMemPtr gpu_mem, escher_buffer_(escher::impl::NaiveBuffer::New( session->resource_context().escher_resource_recycler, std::move(gpu_mem), + // TODO(SCN-1369): Clients have no way to know this set of bits, and + // yet our code assumes that the imported VMO will bind successfully. vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eStorageTexelBuffer | diff --git a/garnet/lib/ui/gfx/tests/session_unittest.cc b/garnet/lib/ui/gfx/tests/session_unittest.cc index 22b823b52f3806cfa5e7d0812c2f50bc30ec029b..9062db5ef97bff84935b61bc0f1f15fafb152780 100644 --- a/garnet/lib/ui/gfx/tests/session_unittest.cc +++ b/garnet/lib/ui/gfx/tests/session_unittest.cc @@ -8,11 +8,9 @@ #include "garnet/lib/ui/gfx/resources/shapes/circle_shape.h" #include "garnet/lib/ui/gfx/tests/session_test.h" #include "garnet/lib/ui/gfx/tests/vk_session_test.h" -#include "public/lib/escher/test/gtest_vulkan.h" - -#include "lib/ui/scenic/cpp/commands.h" - #include "gtest/gtest.h" +#include "lib/ui/scenic/cpp/commands.h" +#include "public/lib/escher/test/gtest_vulkan.h" namespace scenic_impl { namespace gfx { @@ -106,23 +104,52 @@ TEST_F(SessionTest, Labeling) { using BufferSessionTest = VkSessionTest; VK_TEST_F(BufferSessionTest, BufferAliasing) { - size_t vmo_size = 1024; - size_t offset = 512; - - zx::vmo vmo; - zx_status_t status = zx::vmo::create(vmo_size, 0u, &vmo); - EXPECT_TRUE(status == ZX_OK); + const size_t kVmoSize = 1024; + const size_t kOffset = 512; + + auto vulkan_queues = CreateVulkanDeviceQueues(); + auto device = vulkan_queues->vk_device(); + auto physical_device = vulkan_queues->vk_physical_device(); + + // TODO(SCN-1369): Scenic may use a different set of bits when creating a + // buffer, resulting in a memory pool mismatch. + const vk::BufferUsageFlags kUsageFlags = + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst | + vk::BufferUsageFlagBits::eStorageTexelBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eVertexBuffer; + + auto memory_requirements = + GetBufferRequirements(device, kVmoSize, kUsageFlags); + auto memory = + AllocateExportableMemory(device, physical_device, memory_requirements, + vk::MemoryPropertyFlagBits::eDeviceLocal | + vk::MemoryPropertyFlagBits::eHostVisible); + + // If we can't make memory that is both host-visible and device-local, we + // can't run this test. + if (!memory) { + device.freeMemory(memory); + FXL_LOG(INFO) + << "Could not find UMA compatible memory pool, aborting test."; + return; + } + + zx::vmo vmo = + ExportMemoryAsVmo(device, vulkan_queues->dispatch_loader(), memory); zx::vmo dup_vmo; - status = vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_vmo); - EXPECT_TRUE(status == ZX_OK); + zx_status_t status = vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_vmo); + ASSERT_EQ(ZX_OK, status); EXPECT_TRUE(Apply( - scenic::NewCreateMemoryCmd(1, std::move(dup_vmo), vmo_size, + scenic::NewCreateMemoryCmd(1, std::move(dup_vmo), kVmoSize, fuchsia::images::MemoryType::HOST_MEMORY))); - EXPECT_TRUE(Apply(scenic::NewCreateBufferCmd(2, 1, 0, vmo_size))); + EXPECT_TRUE(Apply(scenic::NewCreateBufferCmd(2, 1, 0, kVmoSize))); EXPECT_TRUE( - Apply(scenic::NewCreateBufferCmd(3, 1, offset, vmo_size - offset))); + Apply(scenic::NewCreateBufferCmd(3, 1, kOffset, kVmoSize - kOffset))); auto base_buffer = FindResource<Buffer>(2); auto offset_buffer = FindResource<Buffer>(3); @@ -140,11 +167,12 @@ VK_TEST_F(BufferSessionTest, BufferAliasing) { uint8_t* raw_memory = static_cast<uint8_t*>(shared_vmo->Map()); EXPECT_TRUE(raw_memory); - memset(raw_memory, 0, vmo_size); - raw_memory[512] = 1; + memset(raw_memory, 0, kVmoSize); + raw_memory[kOffset] = 1; EXPECT_EQ(base_buffer->escher_buffer()->host_ptr()[0], 0); - EXPECT_EQ(base_buffer->escher_buffer()->host_ptr()[512], 1); + EXPECT_EQ(base_buffer->escher_buffer()->host_ptr()[kOffset], 1); EXPECT_EQ(offset_buffer->escher_buffer()->host_ptr()[0], 1); + device.freeMemory(memory); } // TODO: diff --git a/garnet/lib/ui/gfx/tests/vk_session_test.cc b/garnet/lib/ui/gfx/tests/vk_session_test.cc index 60be432ba4183174c1ed5935e3d56bbedd42e212..a7ec3efdb5630b78813e21863c349daa453d00f9 100644 --- a/garnet/lib/ui/gfx/tests/vk_session_test.cc +++ b/garnet/lib/ui/gfx/tests/vk_session_test.cc @@ -3,30 +3,93 @@ // found in the LICENSE file. #include "garnet/lib/ui/gfx/tests/vk_session_test.h" + #include "garnet/lib/ui/gfx/util/vulkan_utils.h" +#include "garnet/public/lib/escher/impl/vulkan_utils.h" + +using namespace escher; namespace scenic_impl { namespace gfx { namespace test { -std::unique_ptr<SessionForTest> VkSessionTest::CreateSession() { - SessionContext session_context = CreateBarebonesSessionContext(); +VulkanDeviceQueuesPtr VkSessionTest::CreateVulkanDeviceQueues() { + VulkanInstance::Params instance_params( + {{"VK_LAYER_LUNARG_standard_validation"}, + {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME}, + false}); - // Initialize Vulkan. - escher::VulkanInstance::Params instance_params( - {{}, {VK_EXT_DEBUG_REPORT_EXTENSION_NAME}, false}); + auto vulkan_instance = VulkanInstance::New(std::move(instance_params)); + // This extension is necessary to support exporting Vulkan memory to a VMO. + return VulkanDeviceQueues::New( + vulkan_instance, {{VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, + VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, + VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME}, + vk::SurfaceKHR()}); +} + +vk::DeviceMemory VkSessionTest::AllocateExportableMemory( + vk::Device device, vk::PhysicalDevice physical_device, + vk::MemoryRequirements requirements, vk::MemoryPropertyFlags flags) { + uint32_t memory_type_index = impl::GetMemoryTypeIndex( + physical_device, requirements.memoryTypeBits, flags); + vk::PhysicalDeviceMemoryProperties memory_types = + physical_device.getMemoryProperties(); + if (memory_type_index == memory_types.memoryTypeCount) { + return nullptr; + } - instance_params.layer_names.insert("VK_LAYER_LUNARG_standard_validation"); - auto vulkan_instance = - escher::VulkanInstance::New(std::move(instance_params)); - auto vulkan_device = escher::VulkanDeviceQueues::New( - vulkan_instance, - {{VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME}, vk::SurfaceKHR()}); + vk::ExportMemoryAllocateInfoKHR export_info; + export_info.handleTypes = + vk::ExternalMemoryHandleTypeFlagBits::eTempZirconVmoFUCHSIA; - escher_ = std::make_unique<escher::Escher>(vulkan_device); - release_fence_signaller_ = std::make_unique<escher::ReleaseFenceSignaller>( + vk::MemoryAllocateInfo info; + info.pNext = &export_info; + info.allocationSize = requirements.size; + info.memoryTypeIndex = memory_type_index; + + vk::DeviceMemory memory = + ESCHER_CHECKED_VK_RESULT(device.allocateMemory(info)); + return memory; +} + +zx::vmo VkSessionTest::ExportMemoryAsVmo( + vk::Device device, vk::DispatchLoaderDynamic dispatch_loader, + vk::DeviceMemory memory) { + vk::MemoryGetZirconHandleInfoFUCHSIA export_memory_info( + memory, vk::ExternalMemoryHandleTypeFlagBits::eTempZirconVmoFUCHSIA); + auto result = + device.getMemoryZirconHandleFUCHSIA(export_memory_info, dispatch_loader); + if (result.result != vk::Result::eSuccess) { + FXL_LOG(ERROR) << "Failed to export vk::DeviceMemory as zx::vmo"; + return zx::vmo(); + } + return zx::vmo(result.value); +} + +vk::MemoryRequirements VkSessionTest::GetBufferRequirements( + vk::Device device, vk::DeviceSize size, vk::BufferUsageFlags usage_flags) { + // Create a temp buffer to find out memory requirements. + vk::BufferCreateInfo buffer_create_info; + buffer_create_info.size = size; + buffer_create_info.usage = usage_flags; + buffer_create_info.sharingMode = vk::SharingMode::eExclusive; + auto vk_buffer = + escher::ESCHER_CHECKED_VK_RESULT(device.createBuffer(buffer_create_info)); + auto retval = device.getBufferMemoryRequirements(vk_buffer); + device.destroyBuffer(vk_buffer); + return retval; +} + +std::unique_ptr<SessionForTest> VkSessionTest::CreateSession() { + SessionContext session_context = CreateBarebonesSessionContext(); + auto vulkan_device = CreateVulkanDeviceQueues(); + escher_ = std::make_unique<Escher>(vulkan_device); + release_fence_signaller_ = std::make_unique<ReleaseFenceSignaller>( escher_->command_buffer_sequencer()); - image_factory_ = std::make_unique<escher::ImageFactoryAdapter>( + image_factory_ = std::make_unique<ImageFactoryAdapter>( escher_->gpu_allocator(), escher_->resource_recycler()); session_context.vk_device = escher_->vk_device(); diff --git a/garnet/lib/ui/gfx/tests/vk_session_test.h b/garnet/lib/ui/gfx/tests/vk_session_test.h index 7eb8b7db6cca14c8208757b9659f726d630a3207..b42540cfac2ea21b9f028f55303b1fd5eb9add85 100644 --- a/garnet/lib/ui/gfx/tests/vk_session_test.h +++ b/garnet/lib/ui/gfx/tests/vk_session_test.h @@ -13,6 +13,16 @@ namespace test { class VkSessionTest : public SessionTest { public: + static escher::VulkanDeviceQueuesPtr CreateVulkanDeviceQueues(); + static vk::DeviceMemory AllocateExportableMemory( + vk::Device device, vk::PhysicalDevice physical_device, + vk::MemoryRequirements requirements, vk::MemoryPropertyFlags flags); + static zx::vmo ExportMemoryAsVmo(vk::Device device, + vk::DispatchLoaderDynamic dispatch_loader, + vk::DeviceMemory memory); + static vk::MemoryRequirements GetBufferRequirements( + vk::Device device, vk::DeviceSize size, vk::BufferUsageFlags usage_flags); + // |SessionTest| std::unique_ptr<SessionForTest> CreateSession() override; diff --git a/garnet/public/lib/escher/test/vk/buffer_unittest.cc b/garnet/public/lib/escher/test/vk/buffer_unittest.cc index e587b83e656e0495e8cc73d8dea49b599f7b7d70..0a4ed5c525ea4f36de1c8f0c6fdd39764cdef6ce 100644 --- a/garnet/public/lib/escher/test/vk/buffer_unittest.cc +++ b/garnet/public/lib/escher/test/vk/buffer_unittest.cc @@ -15,6 +15,8 @@ VK_TEST(BufferTest, CreateWithPreExistingMemory) { auto recycler = escher->resource_recycler(); constexpr vk::DeviceSize kDummyBufferSize = 10000; + // TODO(SCN-1369): Scenic may use a different set of bits when creating a + // buffer, resulting in a memory pool mismatch. const auto kBufferUsageFlags = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; const auto kMemoryPropertyFlags = vk::MemoryPropertyFlagBits::eHostVisible |