diff --git a/impeller/fixtures/stroke.comp b/impeller/fixtures/stroke.comp index 57d9555546d29..5a48a29c61e1e 100644 --- a/impeller/fixtures/stroke.comp +++ b/impeller/fixtures/stroke.comp @@ -17,11 +17,15 @@ layout(binding = 0) buffer Polyline { polyline; layout(binding = 1) buffer VertexBuffer { - uint count; vec2 position[]; } vertex_buffer; +layout(binding = 2) buffer VertexBufferCount { + uint count; +} +vertex_buffer_count; + uniform Config { float width; uint cap; @@ -41,7 +45,7 @@ void main() { return; } - atomicAdd(vertex_buffer.count, 4); + atomicAdd(vertex_buffer_count.count, 4); vec2 offset = compute_offset(ident); uint index = ident - 1; diff --git a/impeller/playground/compute_playground_test.cc b/impeller/playground/compute_playground_test.cc index 165a6f9ca882d..eda0b2ca6c619 100644 --- a/impeller/playground/compute_playground_test.cc +++ b/impeller/playground/compute_playground_test.cc @@ -24,6 +24,7 @@ void ComputePlaygroundTest::SetUp() { } SetupContext(GetParam()); + SetupWindow(); start_time_ = fml::TimePoint::Now().ToEpochDelta(); } diff --git a/impeller/playground/compute_playground_test.h b/impeller/playground/compute_playground_test.h index 06c480b5bed63..af9edf71a83bc 100644 --- a/impeller/playground/compute_playground_test.h +++ b/impeller/playground/compute_playground_test.h @@ -11,6 +11,7 @@ #include "flutter/testing/testing.h" #include "impeller/geometry/scalar.h" #include "impeller/playground/playground.h" +#include "impeller/renderer/device_buffer.h" namespace impeller { @@ -36,6 +37,18 @@ class ComputePlaygroundTest // |Playground| std::string GetWindowTitle() const override; + template + std::shared_ptr CreateHostVisibleDeviceBuffer( + std::shared_ptr context, + const std::string& label) { + DeviceBufferDescriptor desc; + desc.storage_mode = StorageMode::kHostVisible; + desc.size = sizeof(T); + auto buffer = context->GetResourceAllocator()->CreateBuffer(desc); + buffer->SetLabel(label); + return buffer; + } + private: fml::TimeDelta start_time_; diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 2ac5e90b745fb..792fc8ed85ff9 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -121,6 +121,7 @@ impeller_component("renderer_unittests") { deps = [ ":renderer", + "../entity", "../fixtures", "../playground:playground_test", "//flutter/testing:testing_lib", diff --git a/impeller/renderer/compute_subgroup_unittests.cc b/impeller/renderer/compute_subgroup_unittests.cc index 5ebcb339ce466..1b93ae66ec243 100644 --- a/impeller/renderer/compute_subgroup_unittests.cc +++ b/impeller/renderer/compute_subgroup_unittests.cc @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/time/time_point.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "impeller/base/strings.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/fixtures/cubic_to_quads.comp.h" #include "impeller/fixtures/golden_heart.h" #include "impeller/fixtures/quad_polyline.comp.h" @@ -22,6 +25,7 @@ #include "impeller/renderer/compute_pipeline_builder.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/pipeline_library.h" +#include "impeller/renderer/render_pass.h" namespace impeller { namespace testing { @@ -44,27 +48,21 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { static constexpr size_t kCubicCount = 6; static constexpr Scalar kAccuracy = .1; - DeviceBufferDescriptor quad_buffer_desc; - quad_buffer_desc.storage_mode = StorageMode::kHostVisible; - quad_buffer_desc.size = sizeof(CS::Quads); - auto quads = context->GetResourceAllocator()->CreateBuffer(quad_buffer_desc); - quads->SetLabel("Quads"); + auto quads = CreateHostVisibleDeviceBuffer>( + context, "Quads"); - DeviceBufferDescriptor point_buffer_desc; - point_buffer_desc.storage_mode = StorageMode::kHostVisible; // TODO(dnfield): Size this buffer more accurately. - point_buffer_desc.size = sizeof(QS::Polyline); auto polyline = - context->GetResourceAllocator()->CreateBuffer(point_buffer_desc); - polyline->SetLabel("polyline"); + CreateHostVisibleDeviceBuffer>( + context, "polyline"); + + auto vertex_buffer_count = + CreateHostVisibleDeviceBuffer(context, + "VertexBufferCount"); - DeviceBufferDescriptor vertex_buffer_desc; - vertex_buffer_desc.storage_mode = StorageMode::kHostVisible; // TODO(dnfield): Size this buffer more accurately. - vertex_buffer_desc.size = sizeof(SS::VertexBuffer); - auto vertex_buffer = - context->GetResourceAllocator()->CreateBuffer(vertex_buffer_desc); - vertex_buffer->SetLabel("VertexBuffer"); + auto vertex_buffer = CreateHostVisibleDeviceBuffer< + SS::VertexBuffer>(context, "VertexBuffer"); { using CubicPipelineBuilder = ComputePipelineBuilder; @@ -138,13 +136,14 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { pass->SetThreadGroupSize(ISize(1024, 1)); ComputeCommand cmd; - cmd.label = "Stroke"; + cmd.label = "Draw Stroke"; cmd.pipeline = compute_pipeline; SS::Config config{.width = 1.0f, .cap = 1, .join = 1, .miter_limit = 4.0f}; SS::BindConfig(cmd, pass->GetTransientsBuffer().EmplaceUniform(config)); SS::BindPolyline(cmd, polyline->AsBufferView()); + SS::BindVertexBufferCount(cmd, vertex_buffer_count->AsBufferView()); SS::BindVertexBuffer(cmd, vertex_buffer->AsBufferView()); ASSERT_TRUE(pass->AddCommand(std::move(cmd))); @@ -154,7 +153,7 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { fml::AutoResetWaitableEvent latch; ASSERT_TRUE(cmd_buffer->SubmitCommands([&latch, quads, polyline, - vertex_buffer]( + vertex_buffer_count, vertex_buffer]( CommandBuffer::Status status) { EXPECT_EQ(status, CommandBuffer::Status::kCompleted); @@ -183,7 +182,9 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { auto* v = reinterpret_cast*>( vertex_buffer->AsBufferView().contents); - EXPECT_EQ(v->count, golden_heart_vertices.size()); + auto* v_count = reinterpret_cast( + vertex_buffer_count->AsBufferView().contents); + EXPECT_EQ(v_count->count, golden_heart_vertices.size()); for (size_t i = 0; i < golden_heart_vertices.size(); i += 1) { EXPECT_LT(std::abs(golden_heart_vertices[i].x - v->position[i].x), 1e-3); EXPECT_LT(std::abs(golden_heart_vertices[i].y - v->position[i].y), 1e-3); @@ -193,6 +194,64 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { })); latch.Wait(); + + auto callback = [&](RenderPass& pass) -> bool { + ContentContext renderer(context); + if (!renderer.IsValid()) { + return false; + } + + using VS = SolidFillPipeline::VertexShader; + using FS = SolidFillPipeline::FragmentShader; + + Command cmd; + cmd.label = "Draw Stroke"; + cmd.stencil_reference = 0; // entity.GetStencilDepth(); + + ContentContextOptions options; + options.sample_count = pass.GetRenderTarget().GetSampleCount(); + options.color_attachment_pixel_format = + pass.GetRenderTarget().GetRenderTargetPixelFormat(); + options.has_stencil_attachment = + pass.GetRenderTarget().GetStencilAttachment().has_value(); + options.blend_mode = BlendMode::kSourceIn; // entity.GetBlendMode(); + options.primitive_type = PrimitiveType::kTriangleStrip; + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + + cmd.pipeline = renderer.GetSolidFillPipeline(options); + + auto count = golden_heart_vertices.size(); + auto& host_buffer = pass.GetTransientsBuffer(); + std::vector indices(count); + std::iota(std::begin(indices), std::end(indices), 0); + + VertexBuffer render_vertex_buffer{ + .vertex_buffer = vertex_buffer->AsBufferView(), + .index_buffer = host_buffer.Emplace( + indices.data(), count * sizeof(uint16_t), alignof(uint16_t)), + .index_count = count, + .index_type = IndexType::k16bit}; + cmd.BindVertices(render_vertex_buffer); + + VS::FrameInfo frame_info; + auto world_matrix = Matrix::MakeScale(GetContentScale()); + frame_info.mvp = + Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * world_matrix; + VS::BindFrameInfo(cmd, + pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + FS::FragInfo frag_info; + frag_info.color = Color::Red().Premultiply(); + FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + return true; + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); } TEST_P(ComputeTest, QuadsToPolyline) { @@ -215,12 +274,8 @@ TEST_P(ComputeTest, QuadsToPolyline) { golden_heart_quads[i].p2}; } - DeviceBufferDescriptor point_buffer_desc; - point_buffer_desc.storage_mode = StorageMode::kHostVisible; - point_buffer_desc.size = sizeof(QS::Polyline); - auto polyline = - context->GetResourceAllocator()->CreateBuffer(point_buffer_desc); - polyline->SetLabel("polyline"); + auto polyline = CreateHostVisibleDeviceBuffer>( + context, "polyline"); { using QuadPipelineBuilder = ComputePipelineBuilder; diff --git a/impeller/renderer/compute_unittests.cc b/impeller/renderer/compute_unittests.cc index cfa50e042d8e8..3cf22b961da72 100644 --- a/impeller/renderer/compute_unittests.cc +++ b/impeller/renderer/compute_unittests.cc @@ -64,13 +64,8 @@ TEST_P(ComputeTest, CanCreateComputePass) { input_0.some_int = 5; input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42}; - DeviceBufferDescriptor buffer_desc; - buffer_desc.storage_mode = StorageMode::kHostVisible; - buffer_desc.size = sizeof(CS::Output); - - auto output_buffer = - context->GetResourceAllocator()->CreateBuffer(buffer_desc); - output_buffer->SetLabel("Output Buffer"); + auto output_buffer = CreateHostVisibleDeviceBuffer>( + context, "Output Buffer"); CS::BindInfo(cmd, pass->GetTransientsBuffer().EmplaceUniform(info)); CS::BindInput0(cmd, @@ -154,21 +149,10 @@ TEST_P(ComputeTest, MultiStageInputAndOutput) { input_2.elements[i] = i; } - DeviceBufferDescriptor output_desc_1; - output_desc_1.storage_mode = StorageMode::kHostVisible; - output_desc_1.size = sizeof(CS1::Output); - - auto output_buffer_1 = - context->GetResourceAllocator()->CreateBuffer(output_desc_1); - output_buffer_1->SetLabel("Output Buffer Stage 1"); - - DeviceBufferDescriptor output_desc_2; - output_desc_2.storage_mode = StorageMode::kHostVisible; - output_desc_2.size = sizeof(CS2::Output); - - auto output_buffer_2 = - context->GetResourceAllocator()->CreateBuffer(output_desc_2); - output_buffer_2->SetLabel("Output Buffer Stage 2"); + auto output_buffer_1 = CreateHostVisibleDeviceBuffer>( + context, "Output Buffer Stage 1"); + auto output_buffer_2 = CreateHostVisibleDeviceBuffer>( + context, "Output Buffer Stage 2"); { ComputeCommand cmd;