diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 3e061375ff79d..be4039d561fdb 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -136,6 +136,8 @@ ../../../flutter/impeller/docs ../../../flutter/impeller/entity/contents/checkerboard_contents_unittests.cc ../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc +../../../flutter/impeller/entity/contents/test +../../../flutter/impeller/entity/contents/vertices_contents_unittests.cc ../../../flutter/impeller/entity/entity_unittests.cc ../../../flutter/impeller/entity/geometry/geometry_unittests.cc ../../../flutter/impeller/entity/render_target_cache_unittests.cc diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 3ad9b09136979..bf4c88139c141 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -264,12 +264,24 @@ impeller_component("entity") { deps = [ "//flutter/fml" ] } +impeller_component("entity_test_helpers") { + testonly = true + + sources = [ + "contents/test/contents_test_helpers.cc", + "contents/test/contents_test_helpers.h", + ] + + deps = [ ":entity" ] +} + impeller_component("entity_unittests") { testonly = true sources = [ "contents/checkerboard_contents_unittests.cc", "contents/filters/inputs/filter_input_unittests.cc", + "contents/vertices_contents_unittests.cc", "entity_playground.cc", "entity_playground.h", "entity_unittests.cc", @@ -278,6 +290,7 @@ impeller_component("entity_unittests") { deps = [ ":entity", + ":entity_test_helpers", "../geometry:geometry_asserts", "../playground:playground_test", "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", diff --git a/impeller/entity/contents/test/contents_test_helpers.cc b/impeller/entity/contents/test/contents_test_helpers.cc new file mode 100644 index 0000000000000..4ec4301d19346 --- /dev/null +++ b/impeller/entity/contents/test/contents_test_helpers.cc @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter 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 "impeller/entity/contents/test/contents_test_helpers.h" + +namespace impeller { + +// + +} \ No newline at end of file diff --git a/impeller/entity/contents/test/contents_test_helpers.h b/impeller/entity/contents/test/contents_test_helpers.h new file mode 100644 index 0000000000000..6d3803ef9969d --- /dev/null +++ b/impeller/entity/contents/test/contents_test_helpers.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "impeller/renderer/command.h" + +namespace impeller { + +/// @brief Retrieve the [VertInfo] struct data from the provided [command]. +template +typename T::VertInfo* GetVertInfo(const Command& command) { + auto resource = command.vertex_bindings.buffers.find(0u); + if (resource == command.vertex_bindings.buffers.end()) { + return nullptr; + } + + auto data = (resource->second.view.resource.contents + + resource->second.view.resource.range.offset); + return reinterpret_cast(data); +} + +/// @brief Retrieve the [FragInfo] struct data from the provided [command]. +template +typename T::FragInfo* GetFragInfo(const Command& command) { + auto resource = command.fragment_bindings.buffers.find(0u); + if (resource == command.fragment_bindings.buffers.end()) { + return nullptr; + } + + auto data = (resource->second.view.resource.contents + + resource->second.view.resource.range.offset); + return reinterpret_cast(data); +} + +} // namespace impeller diff --git a/impeller/entity/contents/vertices_contents.cc b/impeller/entity/contents/vertices_contents.cc index 41d8432a71dda..20b8d09618f94 100644 --- a/impeller/entity/contents/vertices_contents.cc +++ b/impeller/entity/contents/vertices_contents.cc @@ -4,12 +4,8 @@ #include "vertices_contents.h" -#include "impeller/core/formats.h" -#include "impeller/core/vertex_buffer.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/color_filter_contents.h" -#include "impeller/entity/contents/filters/filter_contents.h" -#include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/position_color.vert.h" #include "impeller/entity/vertices.frag.h" #include "impeller/geometry/color.h" @@ -73,6 +69,7 @@ bool VerticesContents::Render(const ContentContext& renderer, std::shared_ptr contents; if (blend_mode_ == BlendMode::kDestination) { + dst_contents->SetAlpha(alpha_); contents = dst_contents; } else { auto color_filter_contents = ColorFilterContents::MakeBlend( diff --git a/impeller/entity/contents/vertices_contents_unittests.cc b/impeller/entity/contents/vertices_contents_unittests.cc new file mode 100644 index 0000000000000..ee05885ca0303 --- /dev/null +++ b/impeller/entity/contents/vertices_contents_unittests.cc @@ -0,0 +1,78 @@ +// Copyright 2013 The Flutter 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 +#include + +#include "gtest/gtest.h" + +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/contents/solid_color_contents.h" +#include "impeller/entity/contents/test/contents_test_helpers.h" +#include "impeller/entity/contents/vertices_contents.h" +#include "impeller/entity/entity.h" +#include "impeller/entity/entity_playground.h" +#include "impeller/entity/vertices.frag.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/renderer/render_target.h" + +namespace impeller { +namespace testing { + +using EntityTest = EntityPlayground; +INSTANTIATE_PLAYGROUND_SUITE(EntityTest); + +std::shared_ptr CreateColorVertices( + const std::vector& vertices, + const std::vector& colors) { + auto bounds = Rect::MakePointBounds(vertices.begin(), vertices.end()); + std::vector indices = {}; + for (auto i = 0u; i < vertices.size(); i++) { + indices.emplace_back(i); + } + std::vector texture_coordinates = {}; + + return std::make_shared( + vertices, indices, texture_coordinates, colors, + bounds.value_or(Rect::MakeLTRB(0, 0, 0, 0)), + VerticesGeometry::VertexMode::kTriangles); +} + +// Verifies that the destination blend fast path still sets an alpha value. +TEST_P(EntityTest, RendersDstPerColorWithAlpha) { + using FS = GeometryColorPipeline::FragmentShader; + + auto contents = std::make_shared(); + auto vertices = CreateColorVertices( + {{0, 0}, {100, 0}, {0, 100}, {100, 0}, {0, 100}, {100, 100}}, + {Color::Red(), Color::Red(), Color::Red(), Color::Red(), Color::Red(), + Color::Red()}); + auto src_contents = SolidColorContents::Make( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath(), + Color::Red()); + + contents->SetGeometry(vertices); + contents->SetAlpha(0.5); + contents->SetBlendMode(BlendMode::kDestination); + contents->SetSourceContents(std::move(src_contents)); + + auto content_context = GetContentContext(); + auto buffer = content_context->GetContext()->CreateCommandBuffer(); + auto render_target = RenderTarget::CreateOffscreenMSAA( + *content_context->GetContext(), + *GetContentContext()->GetRenderTargetCache(), {100, 100}); + auto render_pass = buffer->CreateRenderPass(render_target); + Entity entity; + + ASSERT_TRUE(render_pass->GetCommands().empty()); + ASSERT_TRUE(contents->Render(*content_context, entity, *render_pass)); + + const auto& cmd = render_pass->GetCommands()[0]; + auto* frag_uniforms = GetFragInfo(cmd); + + ASSERT_EQ(frag_uniforms->alpha, 0.5); +} + +} // namespace testing +} // namespace impeller