Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1313,8 +1313,6 @@ ORIGIN: ../../../flutter/impeller/entity/geometry.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/geometry.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/inline_pass_context.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/inline_pass_context.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/atlas_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/atlas_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.glsl + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_color.frag + ../../../flutter/LICENSE
Expand Down Expand Up @@ -3791,8 +3789,6 @@ FILE: ../../../flutter/impeller/entity/geometry.cc
FILE: ../../../flutter/impeller/entity/geometry.h
FILE: ../../../flutter/impeller/entity/inline_pass_context.cc
FILE: ../../../flutter/impeller/entity/inline_pass_context.h
FILE: ../../../flutter/impeller/entity/shaders/atlas_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/atlas_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.glsl
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.vert
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_color.frag
Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ void Canvas::DrawTextFrame(const TextFrame& text_frame,

void Canvas::DrawVertices(std::unique_ptr<VerticesGeometry> vertices,
BlendMode blend_mode,
Paint paint) {
const Paint& paint) {
Entity entity;
entity.SetTransformation(GetCurrentTransformation());
entity.SetStencilDepth(GetStencilDepth());
Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Canvas {

void DrawVertices(std::unique_ptr<VerticesGeometry> vertices,
BlendMode blend_mode,
Paint paint);
const Paint& paint);

void DrawAtlas(const std::shared_ptr<Image>& atlas,
std::vector<Matrix> transforms,
Expand Down
2 changes: 0 additions & 2 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ impeller_shaders("entity_shaders") {
name = "entity"

shaders = [
"shaders/atlas_fill.frag",
"shaders/atlas_fill.vert",
"shaders/blending/advanced_blend.vert",
"shaders/blending/advanced_blend_color.frag",
"shaders/blending/advanced_blend_colorburn.frag",
Expand Down
204 changes: 174 additions & 30 deletions impeller/entity/contents/atlas_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
#include <optional>
#include <utility>

#include "impeller/renderer/formats.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"

#include "impeller/entity/atlas_fill.frag.h"
#include "impeller/entity/atlas_fill.vert.h"
#include "impeller/entity/contents/atlas_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/entity.h"
#include "impeller/entity/geometry.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/renderer/formats.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"

namespace impeller {

Expand Down Expand Up @@ -47,7 +50,6 @@ void AtlasContents::SetAlpha(Scalar alpha) {
}

void AtlasContents::SetBlendMode(BlendMode blend_mode) {
// TODO(jonahwilliams): blending of colors with texture.
blend_mode_ = blend_mode;
}

Expand All @@ -59,15 +61,18 @@ std::optional<Rect> AtlasContents::GetCoverage(const Entity& entity) const {
if (cull_rect_.has_value()) {
return cull_rect_.value().TransformBounds(entity.GetTransformation());
}
return ComputeBoundingBox().TransformBounds(entity.GetTransformation());
}

Rect AtlasContents::ComputeBoundingBox() const {
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.size).TransformBounds(matrix);
bounding_box = bounds.Union(bounding_box);
}
return bounding_box.TransformBounds(entity.GetTransformation());
return bounding_box;
}

void AtlasContents::SetSamplerDescriptor(SamplerDescriptor desc) {
Expand All @@ -78,30 +83,98 @@ const SamplerDescriptor& AtlasContents::GetSamplerDescriptor() const {
return sampler_descriptor_;
}

const std::vector<Matrix>& AtlasContents::GetTransforms() const {
return transforms_;
}

const std::vector<Rect>& AtlasContents::GetTextureCoordinates() const {
return texture_coords_;
}

const std::vector<Color>& AtlasContents::GetColors() const {
return colors_;
}

bool AtlasContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (texture_ == nullptr) {
if (texture_ == nullptr || blend_mode_ == BlendMode::kClear ||
alpha_ <= 0.0) {
return true;
}

using VS = AtlasFillVertexShader;
using FS = AtlasFillFragmentShader;
// Ensure that we use the actual computed bounds and not a cull-rect
// approximation of them.
auto coverage = ComputeBoundingBox();

const auto texture_size = texture_->GetSize();
if (texture_size.IsEmpty()) {
return true;
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);
}

auto src_contents = std::make_shared<AtlasTextureContents>(*this);
src_contents->SetCoverage(coverage);

auto dst_contents = std::make_shared<AtlasColorContents>(*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)});
contents->SetAlpha(alpha_);
return contents->Render(renderer, entity, pass);
}

// AtlasTextureContents
// ---------------------------------------------------------

AtlasTextureContents::AtlasTextureContents(const AtlasContents& parent)
: parent_(parent) {}

AtlasTextureContents::~AtlasTextureContents() {}

std::optional<Rect> AtlasTextureContents::GetCoverage(
const Entity& entity) const {
return coverage_.TransformBounds(entity.GetTransformation());
}

void AtlasTextureContents::SetAlpha(Scalar alpha) {
alpha_ = alpha;
}

void AtlasTextureContents::SetCoverage(Rect coverage) {
coverage_ = coverage;
}

bool AtlasTextureContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = TextureFillVertexShader;
using FS = TextureFillFragmentShader;

auto texture = parent_.GetTexture();
auto texture_coords = parent_.GetTextureCoordinates();
auto transforms = parent_.GetTransforms();

const auto texture_size = texture->GetSize();
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
vertex_builder.Reserve(texture_coords_.size() * 6);
vertex_builder.Reserve(texture_coords.size() * 6);
constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3};
constexpr Scalar width[6] = {0, 1, 0, 1, 0, 1};
constexpr Scalar height[6] = {0, 0, 1, 0, 1, 1};
for (size_t i = 0; i < texture_coords_.size(); i++) {
auto sample_rect = texture_coords_[i];
auto matrix = transforms_[i];
auto color = colors_.size() > 0 ? colors_[i] : Color::Black();
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.size).GetTransformedPoints(matrix);

Expand All @@ -112,7 +185,6 @@ bool AtlasContents::Render(const ContentContext& renderer,
(sample_rect.origin + Point(sample_rect.size.width * width[j],
sample_rect.size.height * height[j])) /
texture_size;
data.color = color.Premultiply();
vertex_builder.AppendVertex(data);
}
}
Expand All @@ -121,31 +193,103 @@ bool AtlasContents::Render(const ContentContext& renderer,
return true;
}

Command cmd;
cmd.label = "AtlasTexture";

auto& host_buffer = pass.GetTransientsBuffer();

VS::VertInfo vert_info;
vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();

FS::FragInfo frag_info;
frag_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
frag_info.has_vertex_color = colors_.size() > 0 ? 1.0 : 0.0;
frag_info.texture_sampler_y_coord_scale = texture->GetYCoordScale();
frag_info.alpha = alpha_;

Command cmd;
cmd.label = "DrawAtlas";
cmd.pipeline =
renderer.GetAtlasPipeline(OptionsFromPassAndEntity(pass, entity));
auto options = OptionsFromPassAndEntity(pass, entity);
cmd.pipeline = renderer.GetTexturePipeline(options);
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info));
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
FS::BindTextureSampler(cmd, texture_,
FS::BindTextureSampler(cmd, texture,
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
sampler_descriptor_));
pass.AddCommand(std::move(cmd));
parent_.GetSamplerDescriptor()));
return pass.AddCommand(std::move(cmd));
}

// AtlasColorContents
// ---------------------------------------------------------

AtlasColorContents::AtlasColorContents(const AtlasContents& parent)
: parent_(parent) {}

return true;
AtlasColorContents::~AtlasColorContents() {}

std::optional<Rect> AtlasColorContents::GetCoverage(
const Entity& entity) const {
return coverage_.TransformBounds(entity.GetTransformation());
}

void AtlasColorContents::SetAlpha(Scalar alpha) {
alpha_ = alpha;
}

void AtlasColorContents::SetCoverage(Rect coverage) {
coverage_ = coverage;
}

bool AtlasColorContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = GeometryColorPipeline::VertexShader;
using FS = GeometryColorPipeline::FragmentShader;

auto texture_coords = parent_.GetTextureCoordinates();
auto transforms = parent_.GetTransforms();
auto colors = parent_.GetColors();

VertexBufferBuilder<VS::PerVertexData> 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.size).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;
}

Command cmd;
cmd.label = "AtlasColors";

auto& host_buffer = pass.GetTransientsBuffer();

VS::VertInfo vert_info;
vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();

FS::FragInfo frag_info;
frag_info.alpha = alpha_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so looking over this, I think the destination color is getting double premultiplied. First it's getting multiplied here with the GeometryColorPipeline , and then the same value is getting multiplied into the destination via the new alpha in the blend filter.

I think the better place to keep the SetAlpha business is here in this contents, and the new SetAlpha stuff can be removed from the blend filter.

If it still doesn't look like Skia after fixing the double premul, then I'd wonder if this alpha is supposed to be deferred to the final blend as opposed to impacting the destination color of the vertex color blend (I suspect you may have worked this out already, though).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is what I thought, but I don't set the alpha here at all if I'm blending - its only used for the src or dst case. Double checking this


auto opts = OptionsFromPassAndEntity(pass, entity);
opts.blend_mode = BlendMode::kSourceOver;
cmd.pipeline = renderer.GetGeometryColorPipeline(opts);
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info));
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
return pass.AddCommand(std::move(cmd));
}

} // namespace impeller
Loading