diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 2d281c6069e08..6ba4d872f619b 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -378,7 +378,7 @@ void Canvas::DrawTextFrame(const TextFrame& text_frame, GetCurrentPass().AddEntity(entity); } -void Canvas::DrawVertices(std::unique_ptr vertices, +void Canvas::DrawVertices(const std::shared_ptr& vertices, BlendMode blend_mode, const Paint& paint) { Entity entity; @@ -386,21 +386,24 @@ void Canvas::DrawVertices(std::unique_ptr vertices, entity.SetStencilDepth(GetStencilDepth()); entity.SetBlendMode(paint.blend_mode); - if (paint.color_source.has_value()) { - auto& source = paint.color_source.value(); - auto contents = source(); - contents->SetGeometry(std::move(vertices)); - contents->SetAlpha(paint.color.alpha); - entity.SetContents(paint.WithFilters(std::move(contents), true)); - } else { - std::shared_ptr contents = - std::make_shared(); - contents->SetColor(paint.color); - contents->SetBlendMode(blend_mode); - contents->SetGeometry(std::move(vertices)); - entity.SetContents(paint.WithFilters(std::move(contents), true)); + if (!vertices->HasVertexColors()) { + auto contents = paint.CreateContentsForGeometry(vertices); + entity.SetContents(paint.WithFilters(std::move(contents))); + GetCurrentPass().AddEntity(entity); + return; } + auto src_paint = paint; + src_paint.color = paint.color.WithAlpha(1.0); + auto src_contents = src_paint.CreateContentsForGeometry(vertices); + + auto contents = std::make_shared(); + contents->SetAlpha(paint.color.alpha); + contents->SetBlendMode(blend_mode); + contents->SetGeometry(vertices); + contents->SetSourceContents(std::move(src_contents)); + entity.SetContents(paint.WithFilters(std::move(contents))); + GetCurrentPass().AddEntity(entity); } @@ -415,11 +418,6 @@ void Canvas::DrawAtlas(const std::shared_ptr& atlas, if (!atlas) { return; } - auto size = atlas->GetSize(); - - if (size.IsEmpty()) { - return; - } std::shared_ptr contents = std::make_shared(); contents->SetColors(std::move(colors)); diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index aacbe513b2e99..35144e61a4aec 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -97,7 +97,7 @@ class Canvas { Point position, const Paint& paint); - void DrawVertices(std::unique_ptr vertices, + void DrawVertices(const std::shared_ptr& vertices, BlendMode blend_mode, const Paint& paint); diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 1d94c8ce85618..d0cbc7b0a1c4f 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -40,6 +40,21 @@ std::shared_ptr Paint::CreateContentsForGeometry( return solid_color; } +std::shared_ptr Paint::CreateContentsForGeometry( + const std::shared_ptr& geometry) const { + if (color_source.has_value()) { + auto& source = color_source.value(); + auto contents = source(); + contents->SetGeometry(geometry); + contents->SetAlpha(color.alpha); + return contents; + } + auto solid_color = std::make_shared(); + solid_color->SetGeometry(geometry); + solid_color->SetColor(color); + return solid_color; +} + std::shared_ptr Paint::WithFilters( std::shared_ptr input, std::optional is_solid_color, diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 60699f96f56d1..f18aca1953c3e 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -106,6 +106,9 @@ struct Paint { std::shared_ptr CreateContentsForGeometry( std::unique_ptr geometry) const; + std::shared_ptr CreateContentsForGeometry( + const std::shared_ptr& geometry) const; + /// @brief Whether this paint has a color filter that can apply opacity bool HasColorFilter() const; diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index b1c535badbd34..84991756d3a2f 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -34,6 +34,15 @@ namespace impeller { namespace testing { +flutter::DlColor toColor(const float* components) { + auto value = (((std::lround(components[3] * 255) & 0xff) << 24) | + ((std::lround(components[0] * 255) & 0xff) << 16) | + ((std::lround(components[1] * 255) & 0xff) << 8) | + ((std::lround(components[2] * 255) & 0xff) << 0)) & + 0xFFFFFFFF; + return flutter::DlColor(value); +} + using DisplayListTest = DisplayListPlayground; INSTANTIATE_PLAYGROUND_SUITE(DisplayListTest); @@ -1164,6 +1173,97 @@ TEST_P(DisplayListTest, DrawShapes) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, DrawVerticesBlendModes) { + std::vector blend_mode_names; + std::vector blend_mode_values; + { + const std::vector> blends = { + // Pipeline blends (Porter-Duff alpha compositing) + {"Clear", flutter::DlBlendMode::kClear}, + {"Source", flutter::DlBlendMode::kSrc}, + {"Destination", flutter::DlBlendMode::kDst}, + {"SourceOver", flutter::DlBlendMode::kSrcOver}, + {"DestinationOver", flutter::DlBlendMode::kDstOver}, + {"SourceIn", flutter::DlBlendMode::kSrcIn}, + {"DestinationIn", flutter::DlBlendMode::kDstIn}, + {"SourceOut", flutter::DlBlendMode::kSrcOut}, + {"DestinationOut", flutter::DlBlendMode::kDstOut}, + {"SourceATop", flutter::DlBlendMode::kSrcATop}, + {"DestinationATop", flutter::DlBlendMode::kDstATop}, + {"Xor", flutter::DlBlendMode::kXor}, + {"Plus", flutter::DlBlendMode::kPlus}, + {"Modulate", flutter::DlBlendMode::kModulate}, + // Advanced blends (color component blends) + {"Screen", flutter::DlBlendMode::kScreen}, + {"Overlay", flutter::DlBlendMode::kOverlay}, + {"Darken", flutter::DlBlendMode::kDarken}, + {"Lighten", flutter::DlBlendMode::kLighten}, + {"ColorDodge", flutter::DlBlendMode::kColorDodge}, + {"ColorBurn", flutter::DlBlendMode::kColorBurn}, + {"HardLight", flutter::DlBlendMode::kHardLight}, + {"SoftLight", flutter::DlBlendMode::kSoftLight}, + {"Difference", flutter::DlBlendMode::kDifference}, + {"Exclusion", flutter::DlBlendMode::kExclusion}, + {"Multiply", flutter::DlBlendMode::kMultiply}, + {"Hue", flutter::DlBlendMode::kHue}, + {"Saturation", flutter::DlBlendMode::kSaturation}, + {"Color", flutter::DlBlendMode::kColor}, + {"Luminosity", flutter::DlBlendMode::kLuminosity}, + }; + assert(blends.size() == + static_cast(flutter::DlBlendMode::kLastMode) + 1); + for (const auto& [name, mode] : blends) { + blend_mode_names.push_back(name); + blend_mode_values.push_back(mode); + } + } + + auto callback = [&]() { + static int current_blend_index = 3; + static float dst_alpha = 1; + static float src_alpha = 1; + static float color0[4] = {1.0f, 0.0f, 0.0f, 1.0f}; + static float color1[4] = {0.0f, 1.0f, 0.0f, 1.0f}; + static float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f}; + static float src_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + { + ImGui::ListBox("Blending mode", ¤t_blend_index, + blend_mode_names.data(), blend_mode_names.size()); + ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1); + ImGui::ColorEdit4("Color A", color0); + ImGui::ColorEdit4("Color B", color1); + ImGui::ColorEdit4("Color C", color2); + ImGui::ColorEdit4("Source Color", src_color); + ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1); + } + ImGui::End(); + + std::vector positions = {SkPoint::Make(100, 300), + SkPoint::Make(200, 100), + SkPoint::Make(300, 300)}; + std::vector colors = { + toColor(color0).modulateOpacity(dst_alpha), + toColor(color1).modulateOpacity(dst_alpha), + toColor(color2).modulateOpacity(dst_alpha)}; + + auto vertices = flutter::DlVertices::Make( + flutter::DlVertexMode::kTriangles, 3, positions.data(), + /*texture_coorindates=*/nullptr, colors.data()); + + flutter::DisplayListBuilder builder; + flutter::DlPaint paint; + + paint.setColor(toColor(src_color).modulateOpacity(src_alpha)); + builder.drawVertices(vertices, blend_mode_values[current_blend_index], + paint); + return builder.Build(); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + #ifdef IMPELLER_ENABLE_3D TEST_P(DisplayListTest, SceneColorSource) { // Load up the scene. diff --git a/impeller/display_list/display_list_vertices_geometry.cc b/impeller/display_list/display_list_vertices_geometry.cc index e7ddf3a1a4923..52caeea8be218 100644 --- a/impeller/display_list/display_list_vertices_geometry.cc +++ b/impeller/display_list/display_list_vertices_geometry.cc @@ -58,9 +58,9 @@ static std::vector fromFanIndices( /////// Vertices Geometry /////// // static -std::unique_ptr DLVerticesGeometry::MakeVertices( +std::shared_ptr DLVerticesGeometry::MakeVertices( const flutter::DlVertices* vertices) { - return std::make_unique(vertices); + return std::make_shared(vertices); } DLVerticesGeometry::DLVerticesGeometry(const flutter::DlVertices* vertices) @@ -100,6 +100,10 @@ static PrimitiveType GetPrimitiveType(const flutter::DlVertices* vertices) { } } +bool DLVerticesGeometry::HasVertexColors() const { + return vertices_->colors() != nullptr; +} + GeometryResult DLVerticesGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, @@ -154,9 +158,7 @@ GeometryResult DLVerticesGeometry::GetPositionBuffer( GeometryResult DLVerticesGeometry::GetPositionColorBuffer( const ContentContext& renderer, const Entity& entity, - RenderPass& pass, - Color paint_color, - BlendMode blend_mode) { + RenderPass& pass) { using VS = GeometryColorPipeline::VertexShader; auto index_count = normalized_indices_.size() == 0 @@ -173,9 +175,9 @@ GeometryResult DLVerticesGeometry::GetPositionColorBuffer( { for (auto i = 0; i < vertex_count; i++) { auto dl_color = dl_colors[i]; - auto pre_color = Color(dl_color.getRedF(), dl_color.getGreenF(), - dl_color.getBlueF(), dl_color.getAlphaF()); - auto color = Color::BlendColor(paint_color, pre_color, blend_mode); + auto color = Color(dl_color.getRedF(), dl_color.getGreenF(), + dl_color.getBlueF(), dl_color.getAlphaF()) + .Premultiply(); auto sk_point = dl_vertices[i]; vertex_data[i] = { .position = Point(sk_point.x(), sk_point.y()), diff --git a/impeller/display_list/display_list_vertices_geometry.h b/impeller/display_list/display_list_vertices_geometry.h index 510f496a30110..3ebfa897800f3 100644 --- a/impeller/display_list/display_list_vertices_geometry.h +++ b/impeller/display_list/display_list_vertices_geometry.h @@ -23,15 +23,13 @@ class DLVerticesGeometry : public VerticesGeometry { ~DLVerticesGeometry(); - static std::unique_ptr MakeVertices( + static std::shared_ptr MakeVertices( const flutter::DlVertices* vertices); // |VerticesGeometry| GeometryResult GetPositionColorBuffer(const ContentContext& renderer, const Entity& entity, - RenderPass& pass, - Color paint_color, - BlendMode blend_mode) override; + RenderPass& pass) override; // |VerticesGeometry| GeometryResult GetPositionUVBuffer(const ContentContext& renderer, @@ -49,6 +47,9 @@ class DLVerticesGeometry : public VerticesGeometry { // |Geometry| GeometryVertexType GetVertexType() const override; + // |VerticesGeometry| + bool HasVertexColors() const override; + private: void NormalizeIndices(); diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 69a4f07679c94..26268a1c2f2f9 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -126,8 +126,6 @@ bool AtlasContents::Render(const ContentContext& renderer, auto dst_contents = std::make_shared(*this); dst_contents->SetCoverage(coverage); - // For some reason this looks backwards compared to Skia unless - // we reverse the src/dst. auto contents = ColorFilterContents::MakeBlend( blend_mode_, {FilterInput::Make(dst_contents), FilterInput::Make(src_contents)}); diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index fe6d231d1586a..984d9b8095f22 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -260,11 +260,12 @@ bool ContentContext::IsValid() const { std::shared_ptr ContentContext::MakeSubpass( ISize texture_size, - const SubpassCallback& subpass_callback) const { + const SubpassCallback& subpass_callback, + bool msaa_enabled) const { auto context = GetContext(); RenderTarget subpass_target; - if (context->SupportsOffscreenMSAA()) { + if (context->SupportsOffscreenMSAA() && msaa_enabled) { subpass_target = RenderTarget::CreateOffscreenMSAA(*context, texture_size); } else { subpass_target = RenderTarget::CreateOffscreen(*context, texture_size); diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 9be86fb5193cb..e109ae4aad2db 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -432,9 +432,9 @@ class ContentContext { /// @brief Creates a new texture of size `texture_size` and calls /// `subpass_callback` with a `RenderPass` for drawing to the texture. - std::shared_ptr MakeSubpass( - ISize texture_size, - const SubpassCallback& subpass_callback) const; + std::shared_ptr MakeSubpass(ISize texture_size, + const SubpassCallback& subpass_callback, + bool msaa_enabled = true) const; private: std::shared_ptr context_; diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc index dc841cf1cb9fd..5de83a10b4c4f 100644 --- a/impeller/entity/contents/contents.cc +++ b/impeller/entity/contents/contents.cc @@ -40,7 +40,8 @@ Contents::StencilCoverage Contents::GetStencilCoverage( std::optional Contents::RenderToSnapshot( const ContentContext& renderer, - const Entity& entity) const { + const Entity& entity, + bool msaa_enabled) const { auto coverage = GetCoverage(entity); if (!coverage.has_value()) { return std::nullopt; @@ -56,7 +57,8 @@ std::optional Contents::RenderToSnapshot( Matrix::MakeTranslation(Vector3(-coverage->origin)) * entity.GetTransformation()); return contents.Render(renderer, sub_entity, pass); - }); + }, + msaa_enabled); if (!texture) { return std::nullopt; diff --git a/impeller/entity/contents/contents.h b/impeller/entity/contents/contents.h index 6d7b6edd55524..78ccc3fc7d324 100644 --- a/impeller/entity/contents/contents.h +++ b/impeller/entity/contents/contents.h @@ -60,7 +60,8 @@ class Contents { /// `GetCoverage(entity)`. virtual std::optional RenderToSnapshot( const ContentContext& renderer, - const Entity& entity) const; + const Entity& entity, + bool msaa_enabled = true) const; virtual bool ShouldRender(const Entity& entity, const std::optional& stencil_coverage) const; diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index a46af9635be01..e363158782afe 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -205,7 +205,7 @@ static std::optional PipelineBlend( FS::FragInfo frag_info; frag_info.texture_sampler_y_coord_scale = input->texture->GetYCoordScale(); - frag_info.input_alpha = absorb_opacity ? input->opacity : 1.0f; + frag_info.input_alpha = absorb_opacity ? input->opacity : 1.0; FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index d43e4298c8845..d1d76f3a4babb 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -236,7 +236,8 @@ std::optional FilterContents::GetFilterCoverage( std::optional FilterContents::RenderToSnapshot( const ContentContext& renderer, - const Entity& entity) const { + const Entity& entity, + bool msaa_enabled) const { Entity entity_with_local_transform = entity; entity_with_local_transform.SetTransformation( GetTransform(entity.GetTransformation())); diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 9387e7ce7d014..779cfb07f19cc 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -116,8 +116,10 @@ class FilterContents : public Contents { std::optional GetCoverage(const Entity& entity) const override; // |Contents| - std::optional RenderToSnapshot(const ContentContext& renderer, - const Entity& entity) const override; + std::optional RenderToSnapshot( + const ContentContext& renderer, + const Entity& entity, + bool msaa_enabled = true) const override; virtual Matrix GetLocalTransform(const Matrix& parent_transform) const; diff --git a/impeller/entity/contents/filters/inputs/contents_filter_input.cc b/impeller/entity/contents/filters/inputs/contents_filter_input.cc index fda5df7760efa..749515798aebc 100644 --- a/impeller/entity/contents/filters/inputs/contents_filter_input.cc +++ b/impeller/entity/contents/filters/inputs/contents_filter_input.cc @@ -8,8 +8,9 @@ namespace impeller { -ContentsFilterInput::ContentsFilterInput(std::shared_ptr contents) - : contents_(std::move(contents)) {} +ContentsFilterInput::ContentsFilterInput(std::shared_ptr contents, + bool msaa_enabled) + : contents_(std::move(contents)), msaa_enabled_(msaa_enabled) {} ContentsFilterInput::~ContentsFilterInput() = default; @@ -21,7 +22,7 @@ std::optional ContentsFilterInput::GetSnapshot( const ContentContext& renderer, const Entity& entity) const { if (!snapshot_.has_value()) { - snapshot_ = contents_->RenderToSnapshot(renderer, entity); + snapshot_ = contents_->RenderToSnapshot(renderer, entity, msaa_enabled_); } return snapshot_; } diff --git a/impeller/entity/contents/filters/inputs/contents_filter_input.h b/impeller/entity/contents/filters/inputs/contents_filter_input.h index 7309c17ffa5f0..61254a9fba692 100644 --- a/impeller/entity/contents/filters/inputs/contents_filter_input.h +++ b/impeller/entity/contents/filters/inputs/contents_filter_input.h @@ -23,10 +23,11 @@ class ContentsFilterInput final : public FilterInput { std::optional GetCoverage(const Entity& entity) const override; private: - ContentsFilterInput(std::shared_ptr contents); + ContentsFilterInput(std::shared_ptr contents, bool msaa_enabled); std::shared_ptr contents_; mutable std::optional snapshot_; + bool msaa_enabled_; friend FilterInput; }; diff --git a/impeller/entity/contents/filters/inputs/filter_input.cc b/impeller/entity/contents/filters/inputs/filter_input.cc index 4f61ba49fa9d5..3a50a44b48465 100644 --- a/impeller/entity/contents/filters/inputs/filter_input.cc +++ b/impeller/entity/contents/filters/inputs/filter_input.cc @@ -15,7 +15,7 @@ namespace impeller { -FilterInput::Ref FilterInput::Make(Variant input) { +FilterInput::Ref FilterInput::Make(Variant input, bool msaa_enabled) { if (auto filter = std::get_if>(&input)) { return std::static_pointer_cast( std::shared_ptr( @@ -25,7 +25,7 @@ FilterInput::Ref FilterInput::Make(Variant input) { if (auto contents = std::get_if>(&input)) { return std::static_pointer_cast( std::shared_ptr( - new ContentsFilterInput(*contents))); + new ContentsFilterInput(*contents, msaa_enabled))); } if (auto texture = std::get_if>(&input)) { diff --git a/impeller/entity/contents/filters/inputs/filter_input.h b/impeller/entity/contents/filters/inputs/filter_input.h index 7bd631f600e44..38090d679052c 100644 --- a/impeller/entity/contents/filters/inputs/filter_input.h +++ b/impeller/entity/contents/filters/inputs/filter_input.h @@ -36,7 +36,7 @@ class FilterInput { virtual ~FilterInput(); - static FilterInput::Ref Make(Variant input); + static FilterInput::Ref Make(Variant input, bool msaa_enabled = true); static FilterInput::Ref Make(std::shared_ptr input, Matrix local_transform); diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index 032b06ed12488..afc55af0d9ba7 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -24,7 +24,7 @@ const Color& SolidColorContents::GetColor() const { return color_; } -void SolidColorContents::SetGeometry(std::unique_ptr geometry) { +void SolidColorContents::SetGeometry(std::shared_ptr geometry) { geometry_ = std::move(geometry); } diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h index e43e7292a7452..81148b133232a 100644 --- a/impeller/entity/contents/solid_color_contents.h +++ b/impeller/entity/contents/solid_color_contents.h @@ -29,7 +29,7 @@ class SolidColorContents final : public Contents { static std::unique_ptr Make(const Path& path, Color color); - void SetGeometry(std::unique_ptr geometry); + void SetGeometry(std::shared_ptr geometry); void SetColor(Color color); @@ -48,7 +48,7 @@ class SolidColorContents final : public Contents { RenderPass& pass) const override; private: - std::unique_ptr geometry_; + std::shared_ptr geometry_; Color color_; diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 754396bbd78a1..f5b44e5402ec5 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -66,7 +66,8 @@ std::optional TextureContents::GetCoverage(const Entity& entity) const { std::optional TextureContents::RenderToSnapshot( const ContentContext& renderer, - const Entity& entity) const { + const Entity& entity, + bool msaa_enabled) const { auto bounds = path_.GetBoundingBox(); if (!bounds.has_value()) { return std::nullopt; diff --git a/impeller/entity/contents/texture_contents.h b/impeller/entity/contents/texture_contents.h index 9502881cca3f6..06ef9244b6e23 100644 --- a/impeller/entity/contents/texture_contents.h +++ b/impeller/entity/contents/texture_contents.h @@ -52,8 +52,10 @@ class TextureContents final : public Contents { std::optional GetCoverage(const Entity& entity) const override; // |Contents| - std::optional RenderToSnapshot(const ContentContext& renderer, - const Entity& entity) const override; + std::optional RenderToSnapshot( + const ContentContext& renderer, + const Entity& entity, + bool msaa_enabled = true) const override; // |Contents| bool Render(const ContentContext& renderer, diff --git a/impeller/entity/contents/vertices_contents.cc b/impeller/entity/contents/vertices_contents.cc index 65b8c88762b48..3c5dcedf00782 100644 --- a/impeller/entity/contents/vertices_contents.cc +++ b/impeller/entity/contents/vertices_contents.cc @@ -5,6 +5,9 @@ #include "vertices_contents.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.vert.h" #include "impeller/entity/position_color.vert.h" #include "impeller/entity/position_uv.vert.h" @@ -25,12 +28,20 @@ std::optional VerticesContents::GetCoverage(const Entity& entity) const { return geometry_->GetCoverage(entity.GetTransformation()); }; -void VerticesContents::SetGeometry(std::unique_ptr geometry) { +void VerticesContents::SetGeometry(std::shared_ptr geometry) { geometry_ = std::move(geometry); } -void VerticesContents::SetColor(Color color) { - color_ = color.Premultiply(); +void VerticesContents::SetSourceContents(std::shared_ptr contents) { + src_contents_ = std::move(contents); +} + +std::shared_ptr VerticesContents::GetGeometry() const { + return geometry_; +} + +void VerticesContents::SetAlpha(Scalar alpha) { + alpha_ = alpha; } void VerticesContents::SetBlendMode(BlendMode blend_mode) { @@ -40,57 +51,65 @@ void VerticesContents::SetBlendMode(BlendMode blend_mode) { bool VerticesContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - auto& host_buffer = pass.GetTransientsBuffer(); - auto vertex_type = geometry_->GetVertexType(); + if (blend_mode_ == BlendMode::kClear) { + return true; + } + auto dst_contents = std::make_shared(*this); + + auto contents = ColorFilterContents::MakeBlend( + blend_mode_, {FilterInput::Make(dst_contents, false), + FilterInput::Make(src_contents_, false)}); + contents->SetAlpha(alpha_); + + return contents->Render(renderer, entity, pass); +} + +//------------------------------------------------------ +// VerticesColorContents + +VerticesColorContents::VerticesColorContents(const VerticesContents& parent) + : parent_(parent) {} + +VerticesColorContents::~VerticesColorContents() {} + +// |Contents| +std::optional VerticesColorContents::GetCoverage( + const Entity& entity) const { + return parent_.GetCoverage(entity); +} + +void VerticesColorContents::SetAlpha(Scalar alpha) { + alpha_ = alpha; +} + +// |Contents| +bool VerticesColorContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = GeometryColorPipeline::VertexShader; + using FS = GeometryColorPipeline::FragmentShader; Command cmd; - cmd.label = "Vertices"; - cmd.stencil_reference = entity.GetStencilDepth(); + cmd.label = "VerticesColors"; + auto& host_buffer = pass.GetTransientsBuffer(); + auto geometry = parent_.GetGeometry(); + auto geometry_result = + geometry->GetPositionColorBuffer(renderer, entity, pass); auto opts = OptionsFromPassAndEntity(pass, entity); + opts.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetGeometryColorPipeline(opts); + cmd.BindVertices(geometry_result.vertex_buffer); - switch (vertex_type) { - case GeometryVertexType::kColor: { - using VS = GeometryColorPipeline::VertexShader; - - auto geometry_result = geometry_->GetPositionColorBuffer( - renderer, entity, pass, color_, blend_mode_); - opts.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetGeometryColorPipeline(opts); - cmd.BindVertices(geometry_result.vertex_buffer); - - VS::VertInfo vert_info; - vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); - VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info)); - break; - } - case GeometryVertexType::kUV: - case GeometryVertexType::kPosition: { - using VS = GeometryPositionPipeline::VertexShader; - - auto geometry_result = - geometry_->GetPositionBuffer(renderer, entity, pass); - opts.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetGeometryPositionPipeline(opts); - cmd.BindVertices(geometry_result.vertex_buffer); - - VS::VertInfo vert_info; - vert_info.mvp = geometry_result.transform; - vert_info.color = color_.Premultiply(); - VS::BindVertInfo(cmd, - pass.GetTransientsBuffer().EmplaceUniform(vert_info)); - break; - } - } - using FS = GeometryColorPipeline::FragmentShader; - FS::FragInfo frag_info; - frag_info.alpha = 1.0; - FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); + VS::VertInfo vert_info; + vert_info.mvp = geometry_result.transform; + VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info)); - pass.AddCommand(std::move(cmd)); + FS::FragInfo frag_info; + frag_info.alpha = alpha_; + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); - return true; + return pass.AddCommand(std::move(cmd)); } } // namespace impeller diff --git a/impeller/entity/contents/vertices_contents.h b/impeller/entity/contents/vertices_contents.h index 0f754c4c8ea25..b2459d549f6c3 100644 --- a/impeller/entity/contents/vertices_contents.h +++ b/impeller/entity/contents/vertices_contents.h @@ -25,12 +25,16 @@ class VerticesContents final : public Contents { ~VerticesContents() override; - void SetGeometry(std::unique_ptr geometry); + void SetGeometry(std::shared_ptr geometry); - void SetColor(Color color); + void SetAlpha(Scalar alpha); void SetBlendMode(BlendMode blend_mode); + void SetSourceContents(std::shared_ptr contents); + + std::shared_ptr GetGeometry() const; + // |Contents| std::optional GetCoverage(const Entity& entity) const override; @@ -39,12 +43,36 @@ class VerticesContents final : public Contents { const Entity& entity, RenderPass& pass) const override; - public: - Color color_; - std::unique_ptr geometry_; + private: + Scalar alpha_; + std::shared_ptr geometry_; BlendMode blend_mode_ = BlendMode::kSource; + std::shared_ptr src_contents_; FML_DISALLOW_COPY_AND_ASSIGN(VerticesContents); }; +class VerticesColorContents final : public Contents { + public: + explicit VerticesColorContents(const VerticesContents& parent); + + ~VerticesColorContents() override; + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + void SetAlpha(Scalar alpha); + + private: + const VerticesContents& parent_; + Scalar alpha_ = 1.0; + + FML_DISALLOW_COPY_AND_ASSIGN(VerticesColorContents); +}; + } // namespace impeller diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index dabab1d1dc42a..d3070a6e0fc08 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -75,13 +75,13 @@ class VerticesGeometry : public Geometry { public: virtual GeometryResult GetPositionColorBuffer(const ContentContext& renderer, const Entity& entity, - RenderPass& pass, - Color paint_color, - BlendMode blend_mode) = 0; + RenderPass& pass) = 0; virtual GeometryResult GetPositionUVBuffer(const ContentContext& renderer, const Entity& entity, RenderPass& pass) = 0; + + virtual bool HasVertexColors() const = 0; }; /// @brief A geometry that is created from a filled path object.