diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index eeb01086077dc..55487586fa9fb 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42738,6 +42738,8 @@ ORIGIN: ../../../flutter/impeller/core/texture_descriptor.cc + ../../../flutter/ ORIGIN: ../../../flutter/impeller/core/texture_descriptor.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/vertex_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/vertex_buffer.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/dl_atlas_geometry.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/dl_atlas_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_dispatcher.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_dispatcher.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_image_impeller.cc + ../../../flutter/LICENSE @@ -45603,6 +45605,8 @@ FILE: ../../../flutter/impeller/core/texture_descriptor.cc FILE: ../../../flutter/impeller/core/texture_descriptor.h FILE: ../../../flutter/impeller/core/vertex_buffer.cc FILE: ../../../flutter/impeller/core/vertex_buffer.h +FILE: ../../../flutter/impeller/display_list/dl_atlas_geometry.cc +FILE: ../../../flutter/impeller/display_list/dl_atlas_geometry.h FILE: ../../../flutter/impeller/display_list/dl_dispatcher.cc FILE: ../../../flutter/impeller/display_list/dl_dispatcher.h FILE: ../../../flutter/impeller/display_list/dl_image_impeller.cc diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 0a281215335fc..33aede58f1756 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -947,32 +947,14 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, AddRenderEntityToCurrentPass(entity); } -void Canvas::DrawAtlas(const std::shared_ptr& atlas, - std::vector transforms, - std::vector texture_coordinates, - std::vector colors, - BlendMode blend_mode, - SamplerDescriptor sampler, - std::optional cull_rect, +void Canvas::DrawAtlas(const std::shared_ptr& atlas_contents, const Paint& paint) { - if (!atlas) { - return; - } - - std::shared_ptr contents = std::make_shared(); - contents->SetColors(std::move(colors)); - contents->SetTransforms(std::move(transforms)); - contents->SetTextureCoordinates(std::move(texture_coordinates)); - contents->SetTexture(atlas); - contents->SetSamplerDescriptor(std::move(sampler)); - contents->SetBlendMode(blend_mode); - contents->SetCullRect(cull_rect); - contents->SetAlpha(paint.color.alpha); + atlas_contents->SetAlpha(paint.color.alpha); Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - entity.SetContents(paint.WithFilters(contents)); + entity.SetContents(paint.WithFilters(atlas_contents)); AddRenderEntityToCurrentPass(entity); } diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 983e2f994090c..d06853330094e 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -14,6 +14,7 @@ #include "impeller/aiks/image_filter.h" #include "impeller/aiks/paint.h" #include "impeller/core/sampler_descriptor.h" +#include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_pass_clip_stack.h" #include "impeller/entity/geometry/geometry.h" @@ -221,13 +222,7 @@ class Canvas { BlendMode blend_mode, const Paint& paint); - void DrawAtlas(const std::shared_ptr& atlas, - std::vector transforms, - std::vector texture_coordinates, - std::vector colors, - BlendMode blend_mode, - SamplerDescriptor sampler, - std::optional cull_rect, + void DrawAtlas(const std::shared_ptr& atlas_contents, const Paint& paint); void EndReplay(); diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index b74f3297f3fec..eca76dd74a551 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -22,6 +22,8 @@ impeller_component("skia_conversions") { impeller_component("display_list") { sources = [ + "dl_atlas_geometry.cc", + "dl_atlas_geometry.h", "dl_dispatcher.cc", "dl_dispatcher.h", "dl_image_impeller.cc", diff --git a/impeller/display_list/aiks_dl_atlas_unittests.cc b/impeller/display_list/aiks_dl_atlas_unittests.cc index 2b6456a423f7c..2d1c47340b30c 100644 --- a/impeller/display_list/aiks_dl_atlas_unittests.cc +++ b/impeller/display_list/aiks_dl_atlas_unittests.cc @@ -10,7 +10,11 @@ #include "flutter/display_list/dl_color.h" #include "flutter/display_list/dl_paint.h" #include "flutter/testing/testing.h" +#include "impeller/core/formats.h" +#include "impeller/display_list/dl_atlas_geometry.h" #include "impeller/display_list/dl_image_impeller.h" +#include "impeller/entity/contents/content_context.h" +#include "impeller/geometry/color.h" #include "impeller/geometry/scalar.h" #include "include/core/SkRSXform.h" #include "include/core/SkRefCnt.h" @@ -47,6 +51,28 @@ CreateTestData(const AiksTest* test) { return std::make_tuple(texture_coordinates, transforms, atlas); } +std::tuple, std::vector, sk_sp> +CreateDlTestData(const AiksTest* test) { + // Draws the image as four squares stiched together. + auto atlas = + DlImageImpeller::Make(test->CreateTextureForFixture("bay_bridge.jpg")); + auto size = atlas->impeller_texture()->GetSize(); + // Divide image into four quadrants. + Scalar half_width = size.width / 2; + Scalar half_height = size.height / 2; + std::vector texture_coordinates = { + DlRect::MakeLTRB(0, 0, half_width, half_height), + DlRect::MakeLTRB(half_width, 0, size.width, half_height), + DlRect::MakeLTRB(0, half_height, half_width, size.height), + DlRect::MakeLTRB(half_width, half_height, size.width, size.height)}; + // Position quadrants adjacent to eachother. + std::vector transforms = { + MakeTranslation(0, 0), MakeTranslation(half_width, 0), + MakeTranslation(0, half_height), + MakeTranslation(half_width, half_height)}; + return std::make_tuple(texture_coordinates, transforms, atlas); +} + } // namespace TEST_P(AiksTest, DrawAtlasNoColor) { @@ -172,5 +198,78 @@ TEST_P(AiksTest, DrawAtlasPlusWideGamut) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(AiksTest, DlAtlasGeometryNoBlend) { + auto [texture_coordinates, transforms, atlas] = CreateDlTestData(this); + + DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(), + texture_coordinates.data(), nullptr, transforms.size(), + BlendMode::kSourceOver, {}, std::nullopt); + + EXPECT_FALSE(geom.ShouldUseBlend()); + EXPECT_FALSE(geom.ShouldSkip()); + + ContentContext context(GetContext(), nullptr); + auto vertex_buffer = + geom.CreateSimpleVertexBuffer(context.GetTransientsBuffer()); + + EXPECT_EQ(vertex_buffer.index_type, IndexType::kNone); + EXPECT_EQ(vertex_buffer.vertex_count, texture_coordinates.size() * 6); +} + +TEST_P(AiksTest, DlAtlasGeometryBlend) { + auto [texture_coordinates, transforms, atlas] = CreateDlTestData(this); + + std::vector colors; + colors.reserve(texture_coordinates.size()); + for (auto i = 0u; i < texture_coordinates.size(); i++) { + colors.push_back(DlColor::ARGB(0.5, 1, 1, 1)); + } + DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(), + texture_coordinates.data(), colors.data(), + transforms.size(), BlendMode::kSourceOver, {}, + std::nullopt); + + EXPECT_TRUE(geom.ShouldUseBlend()); + EXPECT_FALSE(geom.ShouldSkip()); + + ContentContext context(GetContext(), nullptr); + auto vertex_buffer = + geom.CreateBlendVertexBuffer(context.GetTransientsBuffer()); + + EXPECT_EQ(vertex_buffer.index_type, IndexType::kNone); + EXPECT_EQ(vertex_buffer.vertex_count, texture_coordinates.size() * 6); +} + +TEST_P(AiksTest, DlAtlasGeometryColorButNoBlend) { + auto [texture_coordinates, transforms, atlas] = CreateDlTestData(this); + + std::vector colors; + colors.reserve(texture_coordinates.size()); + for (auto i = 0u; i < texture_coordinates.size(); i++) { + colors.push_back(DlColor::ARGB(0.5, 1, 1, 1)); + } + DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(), + texture_coordinates.data(), colors.data(), + transforms.size(), BlendMode::kSource, {}, std::nullopt); + + // Src blend mode means that colors would be ignored, even if provided. + EXPECT_FALSE(geom.ShouldUseBlend()); + EXPECT_FALSE(geom.ShouldSkip()); +} + +TEST_P(AiksTest, DlAtlasGeometrySkip) { + auto [texture_coordinates, transforms, atlas] = CreateDlTestData(this); + + std::vector colors; + colors.reserve(texture_coordinates.size()); + for (auto i = 0u; i < texture_coordinates.size(); i++) { + colors.push_back(DlColor::ARGB(0.5, 1, 1, 1)); + } + DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(), + texture_coordinates.data(), colors.data(), + transforms.size(), BlendMode::kClear, {}, std::nullopt); + EXPECT_TRUE(geom.ShouldSkip()); +} + } // namespace testing } // namespace impeller diff --git a/impeller/display_list/dl_atlas_geometry.cc b/impeller/display_list/dl_atlas_geometry.cc new file mode 100644 index 0000000000000..3d5e160833c89 --- /dev/null +++ b/impeller/display_list/dl_atlas_geometry.cc @@ -0,0 +1,144 @@ +// 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/display_list/dl_atlas_geometry.h" + +#include "impeller/core/formats.h" +#include "impeller/core/vertex_buffer.h" +#include "impeller/display_list/skia_conversions.h" +#include "impeller/entity/porter_duff_blend.vert.h" +#include "impeller/entity/texture_fill.vert.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/point.h" +#include "third_party/skia/include/core/SkPoint.h" + +namespace impeller { + +DlAtlasGeometry::DlAtlasGeometry(const std::shared_ptr& atlas, + const SkRSXform* xform, + const flutter::DlRect* tex, + const flutter::DlColor* colors, + size_t count, + BlendMode mode, + const SamplerDescriptor& sampling, + std::optional cull_rect) + : atlas_(atlas), + xform_(xform), + tex_(tex), + colors_(colors), + count_(count), + mode_(mode), + sampling_(sampling), + cull_rect_(cull_rect) {} + +DlAtlasGeometry::~DlAtlasGeometry() = default; + +bool DlAtlasGeometry::ShouldUseBlend() const { + return colors_ != nullptr && mode_ != BlendMode::kSource; +} + +bool DlAtlasGeometry::ShouldSkip() const { + return atlas_ == nullptr || (ShouldUseBlend() && mode_ == BlendMode::kClear); +} + +Rect DlAtlasGeometry::ComputeBoundingBox() const { + if (cull_rect_.has_value()) { + return cull_rect_.value(); + } + Rect bounding_box = {}; + for (size_t i = 0; i < count_; i++) { + auto matrix = skia_conversions::ToRSXForm(xform_[i]); + auto sample_rect = tex_[i]; + auto bounds = Rect::MakeSize(sample_rect.GetSize()).TransformBounds(matrix); + bounding_box = bounds.Union(bounding_box); + } + cull_rect_ = bounding_box; + return bounding_box; +} + +std::shared_ptr DlAtlasGeometry::GetAtlas() const { + return atlas_; +} + +const SamplerDescriptor& DlAtlasGeometry::GetSamplerDescriptor() const { + return sampling_; +} + +BlendMode DlAtlasGeometry::GetBlendMode() const { + return mode_; +} + +VertexBuffer DlAtlasGeometry::CreateSimpleVertexBuffer( + HostBuffer& host_buffer) const { + using VS = TextureFillVertexShader; + + constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; + + auto buffer_view = host_buffer.Emplace( + sizeof(VS::PerVertexData) * count_ * 6, alignof(VS::PerVertexData), + [&](uint8_t* raw_data) { + VS::PerVertexData* data = + reinterpret_cast(raw_data); + int offset = 0; + auto texture_size = atlas_->GetSize(); + for (auto i = 0u; i < count_; i++) { + flutter::DlRect sample_rect = tex_[i]; + Matrix matrix = skia_conversions::ToRSXForm(xform_[i]); + auto points = sample_rect.GetPoints(); + auto transformed_points = Rect::MakeSize(sample_rect.GetSize()) + .GetTransformedPoints(matrix); + for (size_t j = 0; j < 6; j++) { + data[offset].position = transformed_points[indices[j]]; + data[offset].texture_coords = points[indices[j]] / texture_size; + offset += 1; + } + } + }); + + return VertexBuffer{ + .vertex_buffer = buffer_view, + .index_buffer = {}, + .vertex_count = count_ * 6, + .index_type = IndexType::kNone, + }; +} + +VertexBuffer DlAtlasGeometry::CreateBlendVertexBuffer( + HostBuffer& host_buffer) const { + using VS = PorterDuffBlendVertexShader; + + constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; + + auto buffer_view = host_buffer.Emplace( + sizeof(VS::PerVertexData) * count_ * 6, alignof(VS::PerVertexData), + [&](uint8_t* raw_data) { + VS::PerVertexData* data = + reinterpret_cast(raw_data); + int offset = 0; + auto texture_size = atlas_->GetSize(); + for (auto i = 0u; i < count_; i++) { + flutter::DlRect sample_rect = tex_[i]; + Matrix matrix = skia_conversions::ToRSXForm(xform_[i]); + auto points = sample_rect.GetPoints(); + auto transformed_points = Rect::MakeSize(sample_rect.GetSize()) + .GetTransformedPoints(matrix); + for (size_t j = 0; j < 6; j++) { + data[offset].vertices = transformed_points[indices[j]]; + data[offset].texture_coords = points[indices[j]] / texture_size; + data[offset].color = + skia_conversions::ToColor(colors_[i]).Premultiply(); + offset += 1; + } + } + }); + + return VertexBuffer{ + .vertex_buffer = buffer_view, + .index_buffer = {}, + .vertex_count = count_ * 6, + .index_type = IndexType::kNone, + }; +} + +} // namespace impeller diff --git a/impeller/display_list/dl_atlas_geometry.h b/impeller/display_list/dl_atlas_geometry.h new file mode 100644 index 0000000000000..839df2b628712 --- /dev/null +++ b/impeller/display_list/dl_atlas_geometry.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_DISPLAY_LIST_DL_ATLAS_GEOMETRY_H_ +#define FLUTTER_IMPELLER_DISPLAY_LIST_DL_ATLAS_GEOMETRY_H_ + +#include "display_list/dl_color.h" +#include "display_list/image/dl_image.h" +#include "impeller/core/sampler_descriptor.h" +#include "impeller/entity/contents/atlas_contents.h" +#include "impeller/geometry/color.h" +#include "include/core/SkRSXform.h" + +namespace impeller { + +/// @brief A wrapper around data provided by a drawAtlas call. +class DlAtlasGeometry : public AtlasGeometry { + public: + DlAtlasGeometry(const std::shared_ptr& atlas, + const SkRSXform* xform, + const flutter::DlRect* tex, + const flutter::DlColor* colors, + size_t count, + BlendMode mode, + const SamplerDescriptor& sampling, + std::optional cull_rect); + + ~DlAtlasGeometry(); + + /// @brief Whether the blend shader should be used. + bool ShouldUseBlend() const override; + + bool ShouldSkip() const override; + + VertexBuffer CreateSimpleVertexBuffer(HostBuffer& host_buffer) const override; + + VertexBuffer CreateBlendVertexBuffer(HostBuffer& host_buffer) const override; + + Rect ComputeBoundingBox() const override; + + std::shared_ptr GetAtlas() const override; + + const SamplerDescriptor& GetSamplerDescriptor() const override; + + BlendMode GetBlendMode() const override; + + private: + const std::shared_ptr atlas_; + const SkRSXform* xform_; + const flutter::DlRect* tex_; + const flutter::DlColor* colors_; + size_t count_; + BlendMode mode_; + SamplerDescriptor sampling_; + mutable std::optional cull_rect_; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_DISPLAY_LIST_DL_ATLAS_GEOMETRY_H_ diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 1a544011aa4bb..3ecebfc352218 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -15,9 +15,11 @@ #include "impeller/aiks/aiks_context.h" #include "impeller/aiks/color_filter.h" #include "impeller/core/formats.h" +#include "impeller/display_list/dl_atlas_geometry.h" #include "impeller/display_list/dl_vertices_geometry.h" #include "impeller/display_list/nine_patch_converter.h" #include "impeller/display_list/skia_conversions.h" +#include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" @@ -324,17 +326,6 @@ void DlDispatcherBase::setStrokeJoin(flutter::DlStrokeJoin join) { } } -static std::vector ToColors(const flutter::DlColor colors[], int count) { - auto result = std::vector(); - if (colors == nullptr) { - return result; - } - for (int i = 0; i < count; i++) { - result.push_back(skia_conversions::ToColor(colors[i])); - } - return result; -} - static std::optional ToColorSourceType( flutter::DlColorSourceType type) { switch (type) { @@ -1154,11 +1145,20 @@ void DlDispatcherBase::drawAtlas(const sk_sp atlas, const DlRect* cull_rect, bool render_with_attributes) { AUTO_DEPTH_WATCHER(1u); - GetCanvas().DrawAtlas( - atlas->impeller_texture(), skia_conversions::ToRSXForms(xform, count), - skia_conversions::ToRects(tex, count), ToColors(colors, count), - ToBlendMode(mode), ToSamplerDescriptor(sampling), - skia_conversions::ToRect(cull_rect), paint_); + + auto geometry = DlAtlasGeometry(atlas->impeller_texture(), // + xform, // + tex, // + colors, // + static_cast(count), // + ToBlendMode(mode), // + ToSamplerDescriptor(sampling), // + skia_conversions::ToRect(cull_rect) // + ); + auto atlas_contents = std::make_shared(); + atlas_contents->SetGeometry(&geometry); + + GetCanvas().DrawAtlas(atlas_contents, paint_); } // |flutter::DlOpReceiver| diff --git a/impeller/display_list/skia_conversions.cc b/impeller/display_list/skia_conversions.cc index 911814f399795..d1e2ef247cafe 100644 --- a/impeller/display_list/skia_conversions.cc +++ b/impeller/display_list/skia_conversions.cc @@ -114,21 +114,15 @@ Color ToColor(const flutter::DlColor& color) { }; } -std::vector ToRSXForms(const SkRSXform xform[], int count) { - auto result = std::vector(); - for (int i = 0; i < count; i++) { - auto form = xform[i]; - // clang-format off - auto matrix = Matrix{ +Matrix ToRSXForm(const SkRSXform& form) { + // clang-format off + return Matrix{ form.fSCos, form.fSSin, 0, 0, -form.fSSin, form.fSCos, 0, 0, 0, 0, 1, 0, form.fTx, form.fTy, 0, 1 }; - // clang-format on - result.push_back(matrix); - } - return result; + // clang-format on } std::optional ToPixelFormat(SkColorType type) { diff --git a/impeller/display_list/skia_conversions.h b/impeller/display_list/skia_conversions.h index 8aa3604bad7f5..7b54ad174c965 100644 --- a/impeller/display_list/skia_conversions.h +++ b/impeller/display_list/skia_conversions.h @@ -47,7 +47,7 @@ Size ToSize(const SkPoint& point); Color ToColor(const flutter::DlColor& color); -std::vector ToRSXForms(const SkRSXform xform[], int count); +Matrix ToRSXForm(const SkRSXform& form); PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect); diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 6d0439405828c..19053b00371bc 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -3,17 +3,16 @@ // found in the LICENSE file. #include -#include #include "impeller/core/formats.h" #include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/blend_filter_contents.h" -#include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/entity.h" +#include "impeller/entity/texture_fill.frag.h" +#include "impeller/entity/texture_fill.vert.h" #include "impeller/geometry/color.h" #include "impeller/renderer/render_pass.h" -#include "impeller/renderer/vertex_buffer_builder.h" namespace impeller { @@ -21,122 +20,29 @@ AtlasContents::AtlasContents() = default; AtlasContents::~AtlasContents() = default; -void AtlasContents::SetTexture(std::shared_ptr texture) { - texture_ = std::move(texture); -} - -std::shared_ptr AtlasContents::GetTexture() const { - return texture_; -} - -void AtlasContents::SetTransforms(std::vector transforms) { - transforms_ = std::move(transforms); - bounding_box_cache_.reset(); -} - -void AtlasContents::SetTextureCoordinates(std::vector texture_coords) { - texture_coords_ = std::move(texture_coords); - bounding_box_cache_.reset(); -} - -void AtlasContents::SetColors(std::vector colors) { - colors_ = std::move(colors); -} - -void AtlasContents::SetAlpha(Scalar alpha) { - alpha_ = alpha; -} - -void AtlasContents::SetBlendMode(BlendMode blend_mode) { - blend_mode_ = blend_mode; -} - -void AtlasContents::SetCullRect(std::optional cull_rect) { - cull_rect_ = cull_rect; -} - std::optional AtlasContents::GetCoverage(const Entity& entity) const { - if (cull_rect_.has_value()) { - return cull_rect_.value().TransformBounds(entity.GetTransform()); - } - return ComputeBoundingBox().TransformBounds(entity.GetTransform()); -} - -Rect AtlasContents::ComputeBoundingBox() const { - if (!bounding_box_cache_.has_value()) { - Rect bounding_box = {}; - for (size_t i = 0; i < texture_coords_.size(); i++) { - auto matrix = transforms_[i]; - auto sample_rect = texture_coords_[i]; - auto bounds = - Rect::MakeSize(sample_rect.GetSize()).TransformBounds(matrix); - bounding_box = bounds.Union(bounding_box); - } - bounding_box_cache_ = bounding_box; + if (!geometry_) { + return std::nullopt; } - return bounding_box_cache_.value(); -} - -void AtlasContents::SetSamplerDescriptor(SamplerDescriptor desc) { - sampler_descriptor_ = std::move(desc); -} - -const SamplerDescriptor& AtlasContents::GetSamplerDescriptor() const { - return sampler_descriptor_; -} - -const std::vector& AtlasContents::GetTransforms() const { - return transforms_; + return geometry_->ComputeBoundingBox().TransformBounds(entity.GetTransform()); } -const std::vector& AtlasContents::GetTextureCoordinates() const { - return texture_coords_; +void AtlasContents::SetGeometry(AtlasGeometry* geometry) { + geometry_ = geometry; } -const std::vector& AtlasContents::GetColors() const { - return colors_; +void AtlasContents::SetAlpha(Scalar alpha) { + alpha_ = alpha; } bool AtlasContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - if (texture_ == nullptr || blend_mode_ == BlendMode::kClear || - alpha_ <= 0.0) { + if (geometry_->ShouldSkip() || alpha_ <= 0.0) { return true; } - BlendMode blend_mode = blend_mode_; - if (colors_.empty()) { - blend_mode = BlendMode::kSource; - } - - constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; - - using VS = PorterDuffBlendPipeline::VertexShader; - - VertexBufferBuilder vtx_builder; - vtx_builder.Reserve(texture_coords_.size() * 6); - const auto texture_size = texture_->GetSize(); - auto& host_buffer = renderer.GetTransientsBuffer(); - bool has_colors = !colors_.empty(); - for (size_t i = 0; i < texture_coords_.size(); i++) { - auto sample_rect = texture_coords_[i]; - auto matrix = transforms_[i]; - auto points = sample_rect.GetPoints(); - auto transformed_points = - Rect::MakeSize(sample_rect.GetSize()).GetTransformedPoints(matrix); - Color color = - has_colors ? colors_[i].Premultiply() : Color::BlackTransparent(); - for (size_t j = 0; j < 6; j++) { - VS::PerVertexData data; - data.vertices = transformed_points[indices[j]]; - data.texture_coords = points[indices[j]] / texture_size; - data.color = color; - vtx_builder.AppendVertex(data); - } - } - - auto dst_sampler_descriptor = sampler_descriptor_; + auto dst_sampler_descriptor = geometry_->GetSamplerDescriptor(); if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) { dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; @@ -145,22 +51,62 @@ bool AtlasContents::Render(const ContentContext& renderer, renderer.GetContext()->GetSamplerLibrary()->GetSampler( dst_sampler_descriptor); + auto& host_buffer = renderer.GetTransientsBuffer(); + if (!geometry_->ShouldUseBlend()) { + using VS = TextureFillVertexShader; + using FS = TextureFillFragmentShader; + + auto dst_sampler_descriptor = geometry_->GetSamplerDescriptor(); + + const std::unique_ptr& dst_sampler = + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + dst_sampler_descriptor); + + auto pipeline_options = OptionsFromPassAndEntity(pass, entity); + pipeline_options.primitive_type = PrimitiveType::kTriangle; + pipeline_options.depth_write_enabled = + pipeline_options.blend_mode == BlendMode::kSource; + + pass.SetPipeline(renderer.GetTexturePipeline(pipeline_options)); + pass.SetVertexBuffer(geometry_->CreateSimpleVertexBuffer(host_buffer)); +#ifdef IMPELLER_DEBUG + pass.SetCommandLabel("DrawAtlas"); +#endif // IMPELLER_DEBUG + + VS::FrameInfo frame_info; + frame_info.mvp = entity.GetShaderTransform(pass); + frame_info.texture_sampler_y_coord_scale = + geometry_->GetAtlas()->GetYCoordScale(); + + VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); + + FS::FragInfo frag_info; + frag_info.alpha = alpha_; + FS::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info))); + FS::BindTextureSampler(pass, geometry_->GetAtlas(), dst_sampler); + return pass.Draw().ok(); + } + + BlendMode blend_mode = geometry_->GetBlendMode(); + if (blend_mode <= BlendMode::kModulate) { + using VS = PorterDuffBlendPipeline::VertexShader; using FS = PorterDuffBlendPipeline::FragmentShader; #ifdef IMPELLER_DEBUG pass.SetCommandLabel( SPrintF("DrawAtlas Blend (%s)", BlendModeToString(blend_mode))); #endif // IMPELLER_DEBUG - pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer)); + pass.SetVertexBuffer(geometry_->CreateBlendVertexBuffer(host_buffer)); pass.SetPipeline( renderer.GetPorterDuffBlendPipeline(OptionsFromPass(pass))); FS::FragInfo frag_info; VS::FrameInfo frame_info; - FS::BindTextureSamplerDst(pass, texture_, dst_sampler); - frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); + FS::BindTextureSamplerDst(pass, geometry_->GetAtlas(), dst_sampler); + frame_info.texture_sampler_y_coord_scale = + geometry_->GetAtlas()->GetYCoordScale(); frag_info.output_alpha = alpha_; frag_info.input_alpha = 1.0; @@ -195,15 +141,16 @@ bool AtlasContents::Render(const ContentContext& renderer, pass.SetCommandLabel( SPrintF("DrawAtlas Advanced Blend (%s)", BlendModeToString(blend_mode))); #endif // IMPELLER_DEBUG - pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer)); + pass.SetVertexBuffer(geometry_->CreateBlendVertexBuffer(host_buffer)); pass.SetPipeline(renderer.GetDrawVerticesUberShader(OptionsFromPass(pass))); - FS::BindTextureSampler(pass, texture_, dst_sampler); + FS::BindTextureSampler(pass, geometry_->GetAtlas(), dst_sampler); VUS::FrameInfo frame_info; FS::FragInfo frag_info; - frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); + frame_info.texture_sampler_y_coord_scale = + geometry_->GetAtlas()->GetYCoordScale(); frame_info.mvp = entity.GetShaderTransform(pass); frag_info.alpha = alpha_; @@ -214,7 +161,7 @@ bool AtlasContents::Render(const ContentContext& renderer, frag_info.tmy = static_cast(Entity::TileMode::kDecal); FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); - VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); + VUS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); return pass.Draw().ok(); } diff --git a/impeller/entity/contents/atlas_contents.h b/impeller/entity/contents/atlas_contents.h index 07ade19adbeb2..a0c00467846c6 100644 --- a/impeller/entity/contents/atlas_contents.h +++ b/impeller/entity/contents/atlas_contents.h @@ -5,47 +5,47 @@ #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_ATLAS_CONTENTS_H_ #define FLUTTER_IMPELLER_ENTITY_CONTENTS_ATLAS_CONTENTS_H_ -#include #include -#include #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/entity.h" +#include "impeller/geometry/color.h" namespace impeller { -class AtlasContents final : public Contents { +// Interface wrapper to allow usage of DL pointer data without copying (or +// circular imports). +class AtlasGeometry { public: - explicit AtlasContents(); - - ~AtlasContents() override; + virtual bool ShouldUseBlend() const = 0; - void SetTexture(std::shared_ptr texture); + virtual bool ShouldSkip() const = 0; - std::shared_ptr GetTexture() const; + virtual VertexBuffer CreateSimpleVertexBuffer( + HostBuffer& host_buffer) const = 0; - void SetTransforms(std::vector transforms); + virtual VertexBuffer CreateBlendVertexBuffer( + HostBuffer& host_buffer) const = 0; - void SetBlendMode(BlendMode blend_mode); + virtual Rect ComputeBoundingBox() const = 0; - void SetTextureCoordinates(std::vector texture_coords); + virtual std::shared_ptr GetAtlas() const = 0; - void SetColors(std::vector colors); + virtual const SamplerDescriptor& GetSamplerDescriptor() const = 0; - void SetCullRect(std::optional cull_rect); - - void SetSamplerDescriptor(SamplerDescriptor desc); - - void SetAlpha(Scalar alpha); + virtual BlendMode GetBlendMode() const = 0; +}; - const SamplerDescriptor& GetSamplerDescriptor() const; +class AtlasContents final : public Contents { + public: + explicit AtlasContents(); - const std::vector& GetTransforms() const; + ~AtlasContents() override; - const std::vector& GetTextureCoordinates() const; + void SetGeometry(AtlasGeometry* geometry); - const std::vector& GetColors() const; + void SetAlpha(Scalar alpha); // |Contents| std::optional GetCoverage(const Entity& entity) const override; @@ -56,17 +56,8 @@ class AtlasContents final : public Contents { RenderPass& pass) const override; private: - Rect ComputeBoundingBox() const; - - std::shared_ptr texture_; - std::vector texture_coords_; - std::vector colors_; - std::vector transforms_; - BlendMode blend_mode_; - std::optional cull_rect_; + AtlasGeometry* geometry_ = nullptr; Scalar alpha_ = 1.0; - SamplerDescriptor sampler_descriptor_ = {}; - mutable std::optional bounding_box_cache_; AtlasContents(const AtlasContents&) = delete;