| // Copyright 2018 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 "src/ui/lib/escher/paper/paper_shape_cache.h" |
| |
| #include "src/ui/lib/escher/paper/paper_render_funcs.h" |
| #include "src/ui/lib/escher/renderer/batch_gpu_uploader.h" |
| #include "src/ui/lib/escher/shape/mesh.h" |
| #include "src/ui/lib/escher/shape/rounded_rect.h" |
| #include "src/ui/lib/escher/test/common/gtest_escher.h" |
| #include "src/ui/lib/escher/vk/texture.h" |
| |
| namespace { |
| using namespace escher; |
| |
| using PaperShapeCacheTest = escher::test::TestWithVkValidationLayer; |
| |
| // Make sure that the PaperShapeCache properly creates |
| // a box mesh. |
| VK_TEST_F(PaperShapeCacheTest, TestBoundingBox) { |
| EscherWeakPtr escher = test::GetEscher()->GetWeakPtr(); |
| PaperShapeCache cache(escher, PaperRendererConfig()); |
| |
| // Request a bounding box. |
| uint64_t frame_number = 1; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| const auto& entry = cache.GetBoxMesh(nullptr, 0); |
| EXPECT_NE(entry.mesh, MeshPtr()); |
| EXPECT_EQ(cache.size(), 1U); |
| |
| // A box has 36 indices and 8 vertices. |
| EXPECT_EQ(entry.num_indices, 36U); |
| EXPECT_EQ(entry.mesh->num_vertices(), 8U); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| } |
| |
| EXPECT_VK_SUCCESS(escher->vk_device().waitIdle()); |
| ASSERT_TRUE(escher->Cleanup()); |
| } |
| |
| VK_TEST_F(PaperShapeCacheTest, TestCaching) { |
| EscherWeakPtr escher = test::GetEscher()->GetWeakPtr(); |
| |
| plane3 planes[2] = {plane3(vec3(1, 0, 0), -1.f), plane3(vec3(0, 1, 0), -1.f)}; |
| |
| PaperShapeCache cache(escher, PaperRendererConfig()); |
| |
| // Request two different rectangles. |
| uint64_t frame_number = 1; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| const auto& entry0 = cache.GetRectMesh(3, 3, &planes[0], 1); |
| EXPECT_NE(entry0.mesh, MeshPtr()); |
| EXPECT_EQ(cache.size(), 1U); |
| |
| const auto& entry0a = cache.GetRectMesh(3, 3, &planes[0], 1); |
| EXPECT_EQ(entry0.mesh, entry0a.mesh); |
| EXPECT_EQ(cache.size(), 1U); |
| |
| const auto& entry1 = cache.GetRectMesh(3, 3, &planes[1], 1); |
| EXPECT_NE(entry1.mesh, MeshPtr()); |
| EXPECT_NE(entry1.mesh, entry0.mesh); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| |
| EXPECT_EQ(cache.size(), 2U); |
| } |
| |
| // Request one of the two rectangles from the previous frame, and a different |
| // rectangle. |
| frame_number = 2; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| const auto& entry0 = cache.GetRectMesh(3, 3, &planes[0], 1); |
| EXPECT_NE(entry0.mesh, MeshPtr()); |
| |
| const auto& entry2 = cache.GetRectMesh(3, 3, planes, 2); |
| EXPECT_NE(entry2.mesh, MeshPtr()); |
| EXPECT_NE(entry2.mesh, entry0.mesh); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| |
| EXPECT_EQ(cache.size(), 3U); |
| } |
| |
| // Request no rectangles. All three should still be cached. |
| frame_number = 3; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| |
| EXPECT_EQ(cache.size(), 3U); |
| } |
| |
| // Request no rectangles. Only two should remain cached. |
| frame_number = 4; |
| EXPECT_EQ(frame_number, 1 + PaperShapeCache::kNumFramesBeforeEviction); |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| |
| EXPECT_EQ(cache.size(), 2U); |
| } |
| |
| // Request no rectangles. None should remain cached. |
| frame_number = 5; |
| EXPECT_EQ(frame_number, 2 + PaperShapeCache::kNumFramesBeforeEviction); |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| |
| EXPECT_EQ(cache.size(), 0U); |
| } |
| } |
| |
| // Test that generated/cached mesh has the expected number of vertices when stencil shadows are |
| // are enabled. This is necessary because be generate different geometry in this case than in other |
| // shadow modes. |
| VK_TEST_F(PaperShapeCacheTest, TestShadowCaching) { |
| EscherWeakPtr escher = test::GetEscher()->GetWeakPtr(); |
| |
| PaperRendererConfig config; |
| |
| PaperShapeCache cache(escher, config); |
| |
| constexpr float kRectWidth = 300.f; |
| constexpr float kRectHeight = 200.f; |
| |
| // A rectangle has 6 indices and 4 vertices. |
| constexpr uint32_t kRectIndexCount = 6U; |
| constexpr uint32_t kRectVertexCount = 4U; |
| |
| // When rendering a rectangle for shadow volumes, we render 6 rectangles: the original rectangle |
| // plus one for each face of the shadow frustum (4 side faces and one bottom face). |
| constexpr uint32_t kShadowRectIndexCount = kRectIndexCount * 6U; |
| // The shadow volume rect has twice as many vertices: the additional vertices form the rectangle |
| // at the bottom face of the shadow frustum. |
| constexpr uint32_t kShadowRectVertexCount = kRectVertexCount * 2U; |
| |
| uint64_t frame_number = 1; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| const auto& entry = cache.GetRectMesh(kRectWidth, kRectHeight, nullptr, 0); |
| EXPECT_NE(entry.mesh, MeshPtr()); |
| EXPECT_EQ(cache.size(), 1U); |
| |
| EXPECT_EQ(entry.num_indices, kRectIndexCount); |
| EXPECT_EQ(entry.num_shadow_volume_indices, 0U); |
| EXPECT_EQ(entry.mesh->num_vertices(), kRectVertexCount); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| } |
| |
| config.shadow_type = PaperRendererShadowType::kShadowVolume; |
| cache.SetConfig(config); |
| frame_number = 2; |
| { |
| auto frame = escher->NewFrame("PaperShapeCache unit-test", frame_number); |
| |
| auto uploader = BatchGpuUploader::New(escher); |
| |
| cache.BeginFrame(uploader.get(), frame_number); |
| |
| const auto& entry = cache.GetRectMesh(kRectWidth, kRectHeight, nullptr, 0); |
| EXPECT_NE(entry.mesh, MeshPtr()); |
| EXPECT_EQ(cache.size(), 1U); |
| |
| EXPECT_EQ(entry.num_indices, kRectIndexCount); |
| EXPECT_EQ(entry.num_shadow_volume_indices, kShadowRectIndexCount); |
| EXPECT_EQ(entry.mesh->num_vertices(), kShadowRectVertexCount); |
| |
| uploader->Submit(); |
| cache.EndFrame(); |
| |
| frame->EndFrame(SemaphorePtr(), []() {}); |
| } |
| |
| EXPECT_VK_SUCCESS(escher->vk_device().waitIdle()); |
| ASSERT_TRUE(escher->Cleanup()); |
| } |
| |
| } // namespace |