diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index f8171692f2d8b..6d0439405828c 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -3,18 +3,14 @@ // found in the LICENSE file. #include -#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/filters/color_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" @@ -59,87 +55,6 @@ void AtlasContents::SetCullRect(std::optional cull_rect) { cull_rect_ = cull_rect; } -struct AtlasBlenderKey { - Color color; - Rect rect; - uint32_t color_key; - - struct Hash { - std::size_t operator()(const AtlasBlenderKey& key) const { - return fml::HashCombine(key.color_key, key.rect.GetWidth(), - key.rect.GetHeight(), key.rect.GetX(), - key.rect.GetY()); - } - }; - - struct Equal { - bool operator()(const AtlasBlenderKey& lhs, - const AtlasBlenderKey& rhs) const { - return lhs.rect == rhs.rect && lhs.color_key == rhs.color_key; - } - }; -}; - -std::shared_ptr AtlasContents::GenerateSubAtlas() const { - FML_DCHECK(colors_.size() > 0 && blend_mode_ != BlendMode::kSource && - blend_mode_ != BlendMode::kDestination); - - std::unordered_map, - AtlasBlenderKey::Hash, AtlasBlenderKey::Equal> - sub_atlas = {}; - - for (auto i = 0u; i < texture_coords_.size(); i++) { - AtlasBlenderKey key = {.color = colors_[i], - .rect = texture_coords_[i], - .color_key = Color::ToIColor(colors_[i])}; - if (sub_atlas.find(key) == sub_atlas.end()) { - sub_atlas[key] = {transforms_[i]}; - } else { - sub_atlas[key].push_back(transforms_[i]); - } - } - - auto result = std::make_shared(); - Scalar x_offset = 0.0; - Scalar y_offset = 0.0; - Scalar x_extent = 0.0; - Scalar y_extent = 0.0; - - for (auto it = sub_atlas.begin(); it != sub_atlas.end(); it++) { - // This size was arbitrarily chosen to keep the textures from getting too - // wide. We could instead use a more generic rect packer but in the majority - // of cases the sample rects will be fairly close in size making this a good - // enough approximation. - if (x_offset >= 1000) { - y_offset = y_extent + 1; - x_offset = 0.0; - } - - auto key = it->first; - auto transforms = it->second; - - auto new_rect = Rect::MakeXYWH(x_offset, y_offset, key.rect.GetWidth(), - key.rect.GetHeight()); - auto sub_transform = Matrix::MakeTranslation(Vector2(x_offset, y_offset)); - - x_offset += std::ceil(key.rect.GetWidth()) + 1.0; - - result->sub_texture_coords.push_back(key.rect); - result->sub_colors.push_back(key.color); - result->sub_transforms.push_back(sub_transform); - - x_extent = std::max(x_extent, x_offset); - y_extent = std::max(y_extent, std::ceil(y_offset + key.rect.GetHeight())); - - for (auto transform : transforms) { - result->result_texture_coords.push_back(new_rect); - result->result_transforms.push_back(transform); - } - } - result->size = ISize(std::ceil(x_extent), std::ceil(y_extent)); - return result; -} - std::optional AtlasContents::GetCoverage(const Entity& entity) const { if (cull_rect_.has_value()) { return cull_rect_.value().TransformBounds(entity.GetTransform()); @@ -190,54 +105,52 @@ bool AtlasContents::Render(const ContentContext& renderer, return true; } - // Ensure that we use the actual computed bounds and not a cull-rect - // approximation of them. - auto coverage = ComputeBoundingBox(); - - if (blend_mode_ == BlendMode::kSource || colors_.size() == 0) { - auto child_contents = AtlasTextureContents(*this); - child_contents.SetAlpha(alpha_); - child_contents.SetCoverage(coverage); - return child_contents.Render(renderer, entity, pass); - } - if (blend_mode_ == BlendMode::kDestination) { - auto child_contents = AtlasColorContents(*this); - child_contents.SetAlpha(alpha_); - child_contents.SetCoverage(coverage); - return child_contents.Render(renderer, entity, pass); + BlendMode blend_mode = blend_mode_; + if (colors_.empty()) { + blend_mode = BlendMode::kSource; } constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; - if (blend_mode_ <= BlendMode::kModulate) { - // Simple Porter-Duff blends can be accomplished without a subpass. - using VS = PorterDuffBlendPipeline::VertexShader; - using FS = PorterDuffBlendPipeline::FragmentShader; - - VertexBufferBuilder vtx_builder; - vtx_builder.Reserve(texture_coords_.size() * 6); - const auto texture_size = texture_->GetSize(); - auto& host_buffer = renderer.GetTransientsBuffer(); + using VS = PorterDuffBlendPipeline::VertexShader; - 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); - auto color = colors_[i].Premultiply(); - 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); - } + 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_; + if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) { + dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; + dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; + } + const std::unique_ptr& dst_sampler = + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + dst_sampler_descriptor); + + if (blend_mode <= BlendMode::kModulate) { + using FS = PorterDuffBlendPipeline::FragmentShader; #ifdef IMPELLER_DEBUG pass.SetCommandLabel( - SPrintF("DrawAtlas Blend (%s)", BlendModeToString(blend_mode_))); + SPrintF("DrawAtlas Blend (%s)", BlendModeToString(blend_mode))); #endif // IMPELLER_DEBUG pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer)); pass.SetPipeline( @@ -246,14 +159,6 @@ bool AtlasContents::Render(const ContentContext& renderer, FS::FragInfo frag_info; VS::FrameInfo frame_info; - auto dst_sampler_descriptor = sampler_descriptor_; - if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) { - dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; - dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; - } - const std::unique_ptr& dst_sampler = - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - dst_sampler_descriptor); FS::BindTextureSamplerDst(pass, texture_, dst_sampler); frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); @@ -261,7 +166,7 @@ bool AtlasContents::Render(const ContentContext& renderer, frag_info.input_alpha = 1.0; auto inverted_blend_mode = - InvertPorterDuffBlend(blend_mode_).value_or(BlendMode::kSource); + InvertPorterDuffBlend(blend_mode).value_or(BlendMode::kSource); auto blend_coefficients = kPorterDuffCoefficients[static_cast(inverted_blend_mode)]; frag_info.src_coeff = blend_coefficients[0]; @@ -269,6 +174,9 @@ bool AtlasContents::Render(const ContentContext& renderer, frag_info.dst_coeff = blend_coefficients[2]; frag_info.dst_coeff_src_alpha = blend_coefficients[3]; frag_info.dst_coeff_src_color = blend_coefficients[4]; + // These values are ignored on platforms that natively support decal. + frag_info.tmx = static_cast(Entity::TileMode::kDecal); + frag_info.tmy = static_cast(Entity::TileMode::kDecal); FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); @@ -280,229 +188,34 @@ bool AtlasContents::Render(const ContentContext& renderer, return pass.Draw().ok(); } - // Advanced blends. - - auto sub_atlas = GenerateSubAtlas(); - auto sub_coverage = Rect::MakeSize(sub_atlas->size); - - auto src_contents = std::make_shared(*this); - src_contents->SetSubAtlas(sub_atlas); - src_contents->SetCoverage(sub_coverage); - - auto dst_contents = std::make_shared(*this); - dst_contents->SetSubAtlas(sub_atlas); - dst_contents->SetCoverage(sub_coverage); - - Entity untransformed_entity; - auto contents = ColorFilterContents::MakeBlend( - blend_mode_, - {FilterInput::Make(dst_contents), FilterInput::Make(src_contents)}); - auto snapshot = - contents->RenderToSnapshot(renderer, // renderer - untransformed_entity, // entity - std::nullopt, // coverage_limit - std::nullopt, // sampler_descriptor - true, // msaa_enabled - /*mip_count=*/1, - "AtlasContents Snapshot"); // label - if (!snapshot.has_value()) { - return false; - } - - auto child_contents = AtlasTextureContents(*this); - child_contents.SetAlpha(alpha_); - child_contents.SetCoverage(coverage); - child_contents.SetTexture(snapshot.value().texture); - child_contents.SetUseDestination(true); - child_contents.SetSubAtlas(sub_atlas); - return child_contents.Render(renderer, entity, pass); -} - -// AtlasTextureContents -// --------------------------------------------------------- - -AtlasTextureContents::AtlasTextureContents(const AtlasContents& parent) - : parent_(parent) {} - -AtlasTextureContents::~AtlasTextureContents() {} - -std::optional AtlasTextureContents::GetCoverage( - const Entity& entity) const { - return coverage_.TransformBounds(entity.GetTransform()); -} - -void AtlasTextureContents::SetAlpha(Scalar alpha) { - alpha_ = alpha; -} - -void AtlasTextureContents::SetCoverage(Rect coverage) { - coverage_ = coverage; -} - -void AtlasTextureContents::SetUseDestination(bool value) { - use_destination_ = value; -} - -void AtlasTextureContents::SetSubAtlas( - const std::shared_ptr& subatlas) { - subatlas_ = subatlas; -} - -void AtlasTextureContents::SetTexture(std::shared_ptr texture) { - texture_ = std::move(texture); -} - -bool AtlasTextureContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = TextureFillVertexShader; - using FS = TextureFillFragmentShader; - - auto texture = texture_ ? texture_ : parent_.GetTexture(); - if (texture == nullptr) { - return true; - } - - std::vector texture_coords; - std::vector transforms; - if (subatlas_) { - texture_coords = use_destination_ ? subatlas_->result_texture_coords - : subatlas_->sub_texture_coords; - transforms = use_destination_ ? subatlas_->result_transforms - : subatlas_->sub_transforms; - } else { - texture_coords = parent_.GetTextureCoordinates(); - transforms = parent_.GetTransforms(); - } - - const Size texture_size(texture->GetSize()); - VertexBufferBuilder vertex_builder; - vertex_builder.Reserve(texture_coords.size() * 6); - constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; - 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); - - for (size_t j = 0; j < 6; j++) { - VS::PerVertexData data; - data.position = transformed_points[indices[j]]; - data.texture_coords = points[indices[j]] / texture_size; - vertex_builder.AppendVertex(data); - } - } - - if (!vertex_builder.HasVertices()) { - return true; - } + using VUS = VerticesUberShader::VertexShader; + using FS = VerticesUberShader::FragmentShader; - pass.SetCommandLabel("AtlasTexture"); - - auto& host_buffer = renderer.GetTransientsBuffer(); - - VS::FrameInfo frame_info; - frame_info.mvp = entity.GetShaderTransform(pass); - frame_info.texture_sampler_y_coord_scale = texture->GetYCoordScale(); +#ifdef IMPELLER_DEBUG + pass.SetCommandLabel( + SPrintF("DrawAtlas Advanced Blend (%s)", BlendModeToString(blend_mode))); +#endif // IMPELLER_DEBUG + pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer)); - auto options = OptionsFromPassAndEntity(pass, entity); - pass.SetPipeline(renderer.GetTexturePipeline(options)); - pass.SetVertexBuffer(vertex_builder.CreateVertexBuffer(host_buffer)); - VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); + pass.SetPipeline(renderer.GetDrawVerticesUberShader(OptionsFromPass(pass))); + FS::BindTextureSampler(pass, texture_, dst_sampler); + VUS::FrameInfo frame_info; FS::FragInfo frag_info; - frag_info.alpha = alpha_; - - FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); - FS::BindTextureSampler(pass, texture, - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - parent_.GetSamplerDescriptor())); - return pass.Draw().ok(); -} - -// AtlasColorContents -// --------------------------------------------------------- - -AtlasColorContents::AtlasColorContents(const AtlasContents& parent) - : parent_(parent) {} - -AtlasColorContents::~AtlasColorContents() {} -std::optional AtlasColorContents::GetCoverage( - const Entity& entity) const { - return coverage_.TransformBounds(entity.GetTransform()); -} - -void AtlasColorContents::SetAlpha(Scalar alpha) { - alpha_ = alpha; -} - -void AtlasColorContents::SetCoverage(Rect coverage) { - coverage_ = coverage; -} - -void AtlasColorContents::SetSubAtlas( - const std::shared_ptr& subatlas) { - subatlas_ = subatlas; -} - -bool AtlasColorContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = GeometryColorPipeline::VertexShader; - using FS = GeometryColorPipeline::FragmentShader; - - std::vector texture_coords; - std::vector transforms; - std::vector colors; - if (subatlas_) { - texture_coords = subatlas_->sub_texture_coords; - colors = subatlas_->sub_colors; - transforms = subatlas_->sub_transforms; - } else { - texture_coords = parent_.GetTextureCoordinates(); - transforms = parent_.GetTransforms(); - colors = parent_.GetColors(); - } - - VertexBufferBuilder vertex_builder; - vertex_builder.Reserve(texture_coords.size() * 6); - constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; - for (size_t i = 0; i < texture_coords.size(); i++) { - auto sample_rect = texture_coords[i]; - auto matrix = transforms[i]; - auto transformed_points = - Rect::MakeSize(sample_rect.GetSize()).GetTransformedPoints(matrix); - - for (size_t j = 0; j < 6; j++) { - VS::PerVertexData data; - data.position = transformed_points[indices[j]]; - data.color = colors[i].Premultiply(); - vertex_builder.AppendVertex(data); - } - } - - if (!vertex_builder.HasVertices()) { - return true; - } - - pass.SetCommandLabel("AtlasColors"); - - auto& host_buffer = renderer.GetTransientsBuffer(); - - VS::FrameInfo frame_info; + frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); frame_info.mvp = entity.GetShaderTransform(pass); - FS::FragInfo frag_info; frag_info.alpha = alpha_; + frag_info.blend_mode = static_cast(blend_mode); + + // These values are ignored on platforms that natively support decal. + frag_info.tmx = static_cast(Entity::TileMode::kDecal); + frag_info.tmy = static_cast(Entity::TileMode::kDecal); - auto opts = OptionsFromPassAndEntity(pass, entity); - opts.blend_mode = BlendMode::kSourceOver; - pass.SetPipeline(renderer.GetGeometryColorPipeline(opts)); - pass.SetVertexBuffer(vertex_builder.CreateVertexBuffer(host_buffer)); - VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); + VS::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 12e5e232d3f25..07ade19adbeb2 100644 --- a/impeller/entity/contents/atlas_contents.h +++ b/impeller/entity/contents/atlas_contents.h @@ -9,27 +9,12 @@ #include #include -#include "flutter/fml/macros.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/entity.h" namespace impeller { -struct SubAtlasResult { - // Sub atlas values. - std::vector sub_texture_coords; - std::vector sub_colors; - std::vector sub_transforms; - - // Result atlas values. - std::vector result_texture_coords; - std::vector result_transforms; - - // Size of the sub-atlass. - ISize size; -}; - class AtlasContents final : public Contents { public: explicit AtlasContents(); @@ -62,11 +47,6 @@ class AtlasContents final : public Contents { const std::vector& GetColors() const; - /// @brief Compress a drawAtlas call with blending into a smaller sized atlas. - /// This atlas has no overlapping to ensure - /// blending behaves as if it were done in the fragment shader. - std::shared_ptr GenerateSubAtlas() const; - // |Contents| std::optional GetCoverage(const Entity& entity) const override; @@ -93,74 +73,6 @@ class AtlasContents final : public Contents { AtlasContents& operator=(const AtlasContents&) = delete; }; -class AtlasTextureContents final : public Contents { - public: - explicit AtlasTextureContents(const AtlasContents& parent); - - ~AtlasTextureContents() 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); - - void SetCoverage(Rect coverage); - - void SetTexture(std::shared_ptr texture); - - void SetUseDestination(bool value); - - void SetSubAtlas(const std::shared_ptr& subatlas); - - private: - const AtlasContents& parent_; - Scalar alpha_ = 1.0; - Rect coverage_; - std::shared_ptr texture_; - bool use_destination_ = false; - std::shared_ptr subatlas_; - - AtlasTextureContents(const AtlasTextureContents&) = delete; - - AtlasTextureContents& operator=(const AtlasTextureContents&) = delete; -}; - -class AtlasColorContents final : public Contents { - public: - explicit AtlasColorContents(const AtlasContents& parent); - - ~AtlasColorContents() 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); - - void SetCoverage(Rect coverage); - - void SetSubAtlas(const std::shared_ptr& subatlas); - - private: - const AtlasContents& parent_; - Scalar alpha_ = 1.0; - Rect coverage_; - std::shared_ptr subatlas_; - - AtlasColorContents(const AtlasColorContents&) = delete; - - AtlasColorContents& operator=(const AtlasColorContents&) = delete; -}; - } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_ATLAS_CONTENTS_H_ diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 6735ce4786e89..30ed5395695a9 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2027,69 +2027,6 @@ TEST_P(EntityTest, SrgbToLinearFilter) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } -TEST_P(EntityTest, AtlasContentsSubAtlas) { - auto boston = CreateTextureForFixture("boston.jpg"); - - { - auto contents = std::make_shared(); - contents->SetBlendMode(BlendMode::kSourceOver); - contents->SetTexture(boston); - contents->SetColors({ - Color::Red(), - Color::Red(), - Color::Red(), - }); - contents->SetTextureCoordinates({ - Rect::MakeLTRB(0, 0, 10, 10), - Rect::MakeLTRB(0, 0, 10, 10), - Rect::MakeLTRB(0, 0, 10, 10), - }); - contents->SetTransforms({ - Matrix::MakeTranslation(Vector2(0, 0)), - Matrix::MakeTranslation(Vector2(100, 100)), - Matrix::MakeTranslation(Vector2(200, 200)), - }); - - // Since all colors and sample rects are the same, there should - // only be a single entry in the sub atlas. - auto subatlas = contents->GenerateSubAtlas(); - ASSERT_EQ(subatlas->sub_texture_coords.size(), 1u); - } - - { - auto contents = std::make_shared(); - contents->SetBlendMode(BlendMode::kSourceOver); - contents->SetTexture(boston); - contents->SetColors({ - Color::Red(), - Color::Green(), - Color::Blue(), - }); - contents->SetTextureCoordinates({ - Rect::MakeLTRB(0, 0, 10, 10), - Rect::MakeLTRB(0, 0, 10, 10), - Rect::MakeLTRB(0, 0, 10, 10), - }); - contents->SetTransforms({ - Matrix::MakeTranslation(Vector2(0, 0)), - Matrix::MakeTranslation(Vector2(100, 100)), - Matrix::MakeTranslation(Vector2(200, 200)), - }); - - // Since all colors are different, there are three entires. - auto subatlas = contents->GenerateSubAtlas(); - ASSERT_EQ(subatlas->sub_texture_coords.size(), 3u); - - // The translations are kept but the sample rects point into - // different parts of the sub atlas. - ASSERT_EQ(subatlas->result_texture_coords[0], Rect::MakeXYWH(0, 0, 10, 10)); - ASSERT_EQ(subatlas->result_texture_coords[1], - Rect::MakeXYWH(11, 0, 10, 10)); - ASSERT_EQ(subatlas->result_texture_coords[2], - Rect::MakeXYWH(22, 0, 10, 10)); - } -} - static Vector3 RGBToYUV(Vector3 rgb, YUVColorSpace yuv_color_space) { Vector3 yuv; switch (yuv_color_space) {