| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/lib/ui/gfx/resources/buffer.h" |
| #include "garnet/lib/ui/gfx/resources/material.h" |
| #include "garnet/lib/ui/gfx/resources/nodes/shape_node.h" |
| #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 "gtest/gtest.h" |
| #include "lib/ui/scenic/cpp/commands.h" |
| #include "src/ui/lib/escher/test/gtest_vulkan.h" |
| |
| namespace scenic_impl { |
| namespace gfx { |
| namespace test { |
| |
| TEST_F(SessionTest, ScheduleUpdateOutOfOrder) { |
| EXPECT_TRUE(session_->ScheduleUpdate( |
| /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(), |
| std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {})); |
| EXPECT_FALSE(session_->ScheduleUpdate( |
| /*presentation_time*/ 0, std::vector<::fuchsia::ui::gfx::Command>(), |
| std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {})); |
| ExpectLastReportedError( |
| "scenic_impl::gfx::Session: Present called with out-of-order " |
| "presentation " |
| "time. requested presentation time=0, last scheduled presentation " |
| "time=1."); |
| } |
| |
| TEST_F(SessionTest, ScheduleUpdateInOrder) { |
| EXPECT_TRUE(session_->ScheduleUpdate( |
| /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(), |
| std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {})); |
| EXPECT_TRUE(session_->ScheduleUpdate( |
| /*presentation_time*/ 1, std::vector<::fuchsia::ui::gfx::Command>(), |
| std::vector<zx::event>(), std::vector<zx::event>(), [](auto) {})); |
| ExpectLastReportedError(nullptr); |
| } |
| |
| TEST_F(SessionTest, ResourceIdAlreadyUsed) { |
| EXPECT_TRUE(Apply(scenic::NewCreateEntityNodeCmd(1))); |
| EXPECT_TRUE(Apply(scenic::NewCreateShapeNodeCmd(2))); |
| ExpectLastReportedError(nullptr); |
| EXPECT_FALSE(Apply(scenic::NewCreateShapeNodeCmd(2))); |
| ExpectLastReportedError( |
| "scenic::gfx::ResourceMap::AddResource(): resource with ID 2 already " |
| "exists."); |
| } |
| |
| TEST_F(SessionTest, AddAndRemoveResource) { |
| EXPECT_TRUE(Apply(scenic::NewCreateEntityNodeCmd(1))); |
| EXPECT_TRUE(Apply(scenic::NewCreateShapeNodeCmd(2))); |
| EXPECT_TRUE(Apply(scenic::NewCreateShapeNodeCmd(3))); |
| EXPECT_TRUE(Apply(scenic::NewCreateShapeNodeCmd(4))); |
| EXPECT_TRUE(Apply(scenic::NewAddChildCmd(1, 2))); |
| EXPECT_TRUE(Apply(scenic::NewAddPartCmd(1, 3))); |
| EXPECT_EQ(4U, session_->GetTotalResourceCount()); |
| EXPECT_EQ(4U, session_->GetMappedResourceCount()); |
| |
| // Even though we release node 2 and 3, they continue to exist because they |
| // referenced by node 1. Only node 4 is destroyed. |
| EXPECT_TRUE(Apply(scenic::NewReleaseResourceCmd(2))); |
| EXPECT_TRUE(Apply(scenic::NewReleaseResourceCmd(3))); |
| EXPECT_TRUE(Apply(scenic::NewReleaseResourceCmd(4))); |
| EXPECT_EQ(3U, session_->GetTotalResourceCount()); |
| EXPECT_EQ(1U, session_->GetMappedResourceCount()); |
| |
| // Releasing node 1 causes nodes 1-3 to be destroyed. |
| EXPECT_TRUE(Apply(scenic::NewReleaseResourceCmd(1))); |
| EXPECT_EQ(0U, session_->GetTotalResourceCount()); |
| EXPECT_EQ(0U, session_->GetMappedResourceCount()); |
| } |
| |
| TEST_F(SessionTest, Labeling) { |
| const ResourceId kNodeId = 1; |
| const std::string kShortLabel = "test!"; |
| const std::string kLongLabel = |
| std::string(::fuchsia::ui::gfx::kLabelMaxLength, 'x'); |
| const std::string kTooLongLabel = |
| std::string(::fuchsia::ui::gfx::kLabelMaxLength + 1, '?'); |
| |
| EXPECT_TRUE(Apply(scenic::NewCreateShapeNodeCmd(kNodeId))); |
| auto shape_node = FindResource<ShapeNode>(kNodeId); |
| EXPECT_TRUE(shape_node->label().empty()); |
| EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, kShortLabel))); |
| EXPECT_EQ(kShortLabel, shape_node->label()); |
| EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, kLongLabel))); |
| EXPECT_EQ(kLongLabel, shape_node->label()); |
| EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, kTooLongLabel))); |
| EXPECT_EQ(kTooLongLabel.substr(0, fuchsia::ui::gfx::kLabelMaxLength), |
| shape_node->label()); |
| EXPECT_TRUE(Apply(scenic::NewSetLabelCmd(kNodeId, ""))); |
| EXPECT_TRUE(shape_node->label().empty()); |
| |
| // Bypass the truncation performed by session helpers. |
| shape_node->SetLabel(kTooLongLabel); |
| EXPECT_EQ(kTooLongLabel.substr(0, fuchsia::ui::gfx::kLabelMaxLength), |
| shape_node->label()); |
| } |
| |
| using BufferSessionTest = VkSessionTest; |
| |
| VK_TEST_F(BufferSessionTest, BufferAliasing) { |
| 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; |
| 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), kVmoSize, |
| fuchsia::images::MemoryType::HOST_MEMORY))); |
| EXPECT_TRUE(Apply(scenic::NewCreateBufferCmd(2, 1, 0, kVmoSize))); |
| EXPECT_TRUE( |
| Apply(scenic::NewCreateBufferCmd(3, 1, kOffset, kVmoSize - kOffset))); |
| |
| auto base_buffer = FindResource<Buffer>(2); |
| auto offset_buffer = FindResource<Buffer>(3); |
| |
| EXPECT_TRUE(base_buffer); |
| EXPECT_TRUE(base_buffer->escher_buffer()); |
| EXPECT_TRUE(base_buffer->escher_buffer()->host_ptr()); |
| |
| EXPECT_TRUE(offset_buffer); |
| EXPECT_TRUE(offset_buffer->escher_buffer()); |
| EXPECT_TRUE(offset_buffer->escher_buffer()->host_ptr()); |
| |
| auto shared_vmo = fxl::AdoptRef( |
| new fsl::SharedVmo(std::move(vmo), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE)); |
| uint8_t* raw_memory = static_cast<uint8_t*>(shared_vmo->Map()); |
| EXPECT_TRUE(raw_memory); |
| |
| 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()[kOffset], 1); |
| EXPECT_EQ(offset_buffer->escher_buffer()->host_ptr()[0], 1); |
| device.freeMemory(memory); |
| } |
| |
| // TODO: |
| // - test that FindResource() cannot return resources that have the wrong |
| // type. |
| |
| } // namespace test |
| } // namespace gfx |
| } // namespace scenic_impl |