Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] drawAtlas blend mode. #38335

Merged
merged 31 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ff6f4de
fill out drawAtlas
jonahwilliams Dec 15, 2022
b2cc708
Merge branch 'master' of github.com:flutter/engine into drawAtlas
jonahwilliams Jan 11, 2023
56bf47d
++
jonahwilliams Jan 11, 2023
683e306
add drawVertices uage
jonahwilliams Jan 11, 2023
8a1caa1
++
jonahwilliams Jan 11, 2023
1a00d10
test fixes
jonahwilliams Jan 11, 2023
0c23ff4
dont double divide
jonahwilliams Jan 12, 2023
2a27640
CI cleanups
jonahwilliams Jan 12, 2023
79c13e5
some texture coordinates work
jonahwilliams Jan 12, 2023
785e18b
++
jonahwilliams Jan 12, 2023
a3a9476
basic texture coordiantes work
jonahwilliams Jan 13, 2023
ca273f4
++
jonahwilliams Jan 13, 2023
3905cb1
++
jonahwilliams Jan 13, 2023
426d6a1
++
jonahwilliams Jan 13, 2023
94e6c24
Delete color blending
jonahwilliams Jan 13, 2023
9dbe177
Merge branch 'master' of github.com:flutter/engine into drawAtlas
jonahwilliams Jan 17, 2023
997bb3f
back out vertices change
jonahwilliams Jan 18, 2023
d8b3023
++
jonahwilliams Jan 18, 2023
a4f25cd
++
jonahwilliams Jan 18, 2023
7d9e751
++
jonahwilliams Jan 18, 2023
040a83f
remove atlas_fill from licenses
jonahwilliams Jan 18, 2023
e83fb61
blending cleanup
jonahwilliams Jan 18, 2023
53a2189
Use sub-contents
jonahwilliams Jan 18, 2023
fd230d2
fix opacity for pipeline blends
jonahwilliams Jan 19, 2023
b3b51b2
use alpha in snapshot to avoid extra pass
jonahwilliams Jan 20, 2023
b422933
++
jonahwilliams Jan 20, 2023
c3aa8ce
++
jonahwilliams Jan 20, 2023
979d1ef
Merge branch 'master' of github.com:flutter/engine into drawAtlas
jonahwilliams Jan 20, 2023
417ee4f
Merge branch 'master' of github.com:flutter/engine into drawAtlas
jonahwilliams Jan 20, 2023
4837acc
fix order
jonahwilliams Jan 20, 2023
53e9c23
Merge branch 'master' of github.com:flutter/engine into drawAtlas
jonahwilliams Jan 24, 2023
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
Member 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