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: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -40377,6 +40377,8 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/clip.frag + ../../../flutter/LICENSE
Expand Down Expand Up @@ -43257,6 +43259,8 @@ FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag
FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert
FILE: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.frag
FILE: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.vert
FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag
FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert
FILE: ../../../flutter/impeller/entity/shaders/clip.frag
Expand Down
32 changes: 32 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2773,6 +2773,38 @@ TEST_P(AiksTest, VerticesGeometryColorUVPositionData) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, VerticesGeometryColorUVPositionDataAdvancedBlend) {
Canvas canvas;
Paint paint;
auto texture = CreateTextureForFixture("table_mountain_nx.png");

paint.color_source =
ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
Entity::TileMode::kClamp, {}, Matrix());

auto vertices = {
Point(0, 0),
Point(texture->GetSize().width, 0),
Point(0, texture->GetSize().height),
Point(texture->GetSize().width, 0),
Point(0, 0),
Point(texture->GetSize().width, texture->GetSize().height),
};
std::vector<uint16_t> indices = {};
std::vector<Point> texture_coordinates = {};
std::vector<Color> vertex_colors = {
Color::Red().WithAlpha(0.5), Color::Blue().WithAlpha(0.5),
Color::Green().WithAlpha(0.5), Color::Red().WithAlpha(0.5),
Color::Blue().WithAlpha(0.5), Color::Green().WithAlpha(0.5),
};
auto geometry = std::make_shared<VerticesGeometry>(
vertices, indices, texture_coordinates, vertex_colors,
Rect::MakeLTRB(0, 0, 1, 1), VerticesGeometry::VertexMode::kTriangles);

canvas.DrawVertices(geometry, BlendMode::kColorBurn, paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, MatrixImageFilterMagnify) {
Canvas canvas;
canvas.Scale(GetContentScale());
Expand Down
32 changes: 15 additions & 17 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -938,23 +938,21 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,

// If there is are per-vertex colors, an image, and the blend mode
// is simple we can draw without a sub-renderpass.
if (blend_mode <= BlendMode::kModulate && vertices->HasVertexColors()) {
if (std::optional<ImageData> maybe_image_data =
GetImageColorSourceData(paint.color_source)) {
const ImageData& image_data = maybe_image_data.value();
auto contents = std::make_shared<VerticesSimpleBlendContents>();
contents->SetBlendMode(blend_mode);
contents->SetAlpha(paint.color.alpha);
contents->SetGeometry(vertices);

contents->SetEffectTransform(image_data.effect_transform);
contents->SetTexture(image_data.texture);
contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);

entity.SetContents(paint.WithFilters(std::move(contents)));
AddRenderEntityToCurrentPass(std::move(entity));
return;
}
if (std::optional<ImageData> maybe_image_data =
GetImageColorSourceData(paint.color_source)) {
const ImageData& image_data = maybe_image_data.value();
auto contents = std::make_shared<VerticesSimpleBlendContents>();
contents->SetBlendMode(blend_mode);
contents->SetAlpha(paint.color.alpha);
contents->SetGeometry(vertices);

contents->SetEffectTransform(image_data.effect_transform);
contents->SetTexture(image_data.texture);
contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);

entity.SetContents(paint.WithFilters(std::move(contents)));
AddRenderEntityToCurrentPass(std::move(entity));
return;
}

auto src_paint = paint;
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ impeller_shaders("entity_shaders") {
"shaders/filters/linear_to_srgb_filter.frag",
"shaders/filters/morphology_filter.frag",
"shaders/filters/morphology_filter.vert",
"shaders/blending/vertices_uber.frag",
"shaders/blending/vertices_uber.vert",
]

if (impeller_debug) {
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ ContentContext::ContentContext(
yuv_to_rgb_filter_pipelines_.CreateDefault(*context_, options_trianglestrip);
porter_duff_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
{supports_decal});
vertices_uber_shader_.CreateDefault(*context_, options);
// GLES only shader that is unsupported on macOS.
#if defined(IMPELLER_ENABLE_OPENGLES) && !defined(FML_OS_MACOSX)
if (GetContext()->GetBackendType() == Context::BackendType::kOpenGLES) {
Expand Down
13 changes: 13 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
#include "impeller/entity/framebuffer_blend.frag.h"
#include "impeller/entity/framebuffer_blend.vert.h"

#include "impeller/entity/vertices_uber.frag.h"
#include "impeller/entity/vertices_uber.vert.h"

#ifdef IMPELLER_ENABLE_OPENGLES
#include "impeller/entity/tiled_texture_fill_external.frag.h"
#endif // IMPELLER_ENABLE_OPENGLES
Expand Down Expand Up @@ -251,6 +254,10 @@ using FramebufferBlendSoftLightPipeline =
RenderPipelineHandle<FramebufferBlendVertexShader,
FramebufferBlendFragmentShader>;

/// Draw Vertices/Atlas Uber Shader
using VerticesUberShader =
RenderPipelineHandle<VerticesUberVertexShader, VerticesUberFragmentShader>;

/// Geometry Pipelines
using PointsComputeShaderPipeline = ComputePipelineBuilder<PointsComputeShader>;
using UvComputeShaderPipeline = ComputePipelineBuilder<UvComputeShader>;
Expand Down Expand Up @@ -721,6 +728,11 @@ class ContentContext {
return GetPipeline(framebuffer_blend_softlight_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetDrawVerticesUberShader(
ContentContextOptions opts) const {
return GetPipeline(vertices_uber_shader_, opts);
}

std::shared_ptr<Pipeline<ComputePipelineDescriptor>> GetPointComputePipeline()
const {
FML_DCHECK(GetDeviceCapabilities().SupportsCompute());
Expand Down Expand Up @@ -995,6 +1007,7 @@ class ContentContext {
framebuffer_blend_screen_pipelines_;
mutable Variants<FramebufferBlendSoftLightPipeline>
framebuffer_blend_softlight_pipelines_;
mutable Variants<VerticesUberShader> vertices_uber_shader_;
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>
point_field_compute_pipelines_;
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>
Expand Down
111 changes: 72 additions & 39 deletions impeller/entity/contents/vertices_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ void VerticesSimpleBlendContents::SetAlpha(Scalar alpha) {
}

void VerticesSimpleBlendContents::SetBlendMode(BlendMode blend_mode) {
FML_DCHECK(blend_mode <= BlendMode::kModulate);
blend_mode_ = blend_mode;
}

Expand Down Expand Up @@ -275,11 +274,22 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
FML_DCHECK(texture_);
FML_DCHECK(geometry_->HasVertexColors());
BlendMode blend_mode = blend_mode_;
if (!geometry_->HasVertexColors()) {
blend_mode = BlendMode::kSource;
}

auto dst_sampler_descriptor = descriptor_;
dst_sampler_descriptor.width_address_mode =
TileModeToAddressMode(tile_mode_x_, renderer.GetDeviceCapabilities())
.value_or(SamplerAddressMode::kClampToEdge);
dst_sampler_descriptor.height_address_mode =
TileModeToAddressMode(tile_mode_y_, renderer.GetDeviceCapabilities())
.value_or(SamplerAddressMode::kClampToEdge);

// Simple Porter-Duff blends can be accomplished without a sub renderpass.
using VS = PorterDuffBlendPipeline::VertexShader;
using FS = PorterDuffBlendPipeline::FragmentShader;
const std::unique_ptr<const Sampler>& dst_sampler =
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
dst_sampler_descriptor);

GeometryResult geometry_result = geometry_->GetPositionUVColorBuffer(
Rect::MakeSize(texture_->GetSize()), inverse_matrix_, renderer, entity,
Expand All @@ -289,53 +299,76 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
}
FML_DCHECK(geometry_result.mode == GeometryResult::Mode::kNormal);

if (blend_mode <= Entity::kLastPipelineBlendMode) {
using VS = PorterDuffBlendPipeline::VertexShader;
using FS = PorterDuffBlendPipeline::FragmentShader;

#ifdef IMPELLER_DEBUG
pass.SetCommandLabel(SPrintF("DrawVertices Porterduff Blend (%s)",
BlendModeToString(blend_mode)));
#endif // IMPELLER_DEBUG
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));

auto options = OptionsFromPassAndEntity(pass, entity);
options.primitive_type = geometry_result.type;
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));

FS::BindTextureSamplerDst(pass, texture_, dst_sampler);

VS::FrameInfo frame_info;
FS::FragInfo frag_info;

frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
frame_info.mvp = geometry_result.transform;

frag_info.output_alpha = alpha_;
frag_info.input_alpha = 1.0;

auto inverted_blend_mode =
InvertPorterDuffBlend(blend_mode).value_or(BlendMode::kSource);
auto blend_coefficients =
kPorterDuffCoefficients[static_cast<int>(inverted_blend_mode)];
frag_info.src_coeff = blend_coefficients[0];
frag_info.src_coeff_dst_alpha = blend_coefficients[1];
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];
// Only used on devices that do not natively support advanced blends.
frag_info.tmx = static_cast<int>(tile_mode_x_);
frag_info.tmy = static_cast<int>(tile_mode_y_);

auto& host_buffer = renderer.GetTransientsBuffer();
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));

return pass.Draw().ok();
}

using VS = VerticesUberShader::VertexShader;
using FS = VerticesUberShader::FragmentShader;

#ifdef IMPELLER_DEBUG
pass.SetCommandLabel(SPrintF("DrawVertices Porterduff Blend (%s)",
BlendModeToString(blend_mode_)));
pass.SetCommandLabel(SPrintF("DrawVertices Advanced Blend (%s)",
BlendModeToString(blend_mode)));
#endif // IMPELLER_DEBUG
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));

auto options = OptionsFromPassAndEntity(pass, entity);
options.primitive_type = geometry_result.type;
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));

auto dst_sampler_descriptor = descriptor_;
dst_sampler_descriptor.width_address_mode =
TileModeToAddressMode(tile_mode_x_, renderer.GetDeviceCapabilities())
.value_or(SamplerAddressMode::kClampToEdge);
dst_sampler_descriptor.height_address_mode =
TileModeToAddressMode(tile_mode_y_, renderer.GetDeviceCapabilities())
.value_or(SamplerAddressMode::kClampToEdge);
pass.SetPipeline(renderer.GetDrawVerticesUberShader(options));
FS::BindTextureSampler(pass, texture_, dst_sampler);

const std::unique_ptr<const Sampler>& dst_sampler =
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
dst_sampler_descriptor);
FS::BindTextureSamplerDst(pass, texture_, dst_sampler);

FS::FragInfo frag_info;
VS::FrameInfo frame_info;
FS::FragInfo frag_info;

frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
frag_info.output_alpha = alpha_;
frag_info.input_alpha = 1.0;

auto inverted_blend_mode =
InvertPorterDuffBlend(blend_mode_).value_or(BlendMode::kSource);
auto blend_coefficients =
kPorterDuffCoefficients[static_cast<int>(inverted_blend_mode)];
frag_info.src_coeff = blend_coefficients[0];
frag_info.src_coeff_dst_alpha = blend_coefficients[1];
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];
frame_info.mvp = geometry_result.transform;
frag_info.alpha = alpha_;
frag_info.blend_mode = static_cast<int>(blend_mode);

auto& host_buffer = renderer.GetTransientsBuffer();
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));

frame_info.mvp = geometry_result.transform;

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(pass, uniform_view);
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));

return pass.Draw().ok();
}
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/vertices_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ class VerticesUVContents final : public Contents {
VerticesUVContents& operator=(const VerticesUVContents&) = delete;
};

/// A vertices contents for per-color vertices + texture and porter duff
/// blended.
/// A vertices contents for (optional) per-color vertices + texture and any
/// blend mode.
class VerticesSimpleBlendContents final : public Contents {
public:
VerticesSimpleBlendContents();
Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/geometry/vertices_geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ GeometryResult VerticesGeometry::GetPositionUVColorBuffer(
auto uv_transform =
texture_coverage.GetNormalizingTransform() * effect_transform;
auto has_texture_coordinates = HasTextureCoordinates();
auto has_colors = HasVertexColors();

size_t total_vtx_bytes = vertices_.size() * sizeof(VS::PerVertexData);
auto vertex_buffer = renderer.GetTransientsBuffer().Emplace(
Expand All @@ -274,7 +275,7 @@ GeometryResult VerticesGeometry::GetPositionUVColorBuffer(
.texture_coords =
Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
.color = colors_[i],
.color = has_colors ? colors_[i] : Color::BlackTransparent(),
};
std::memcpy(vtx_contents++, &vertex_data, sizeof(VS::PerVertexData));
}
Expand Down
14 changes: 10 additions & 4 deletions impeller/entity/shaders/blending/porter_duff_blend.frag
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ uniform FragInfo {
float16_t dst_coeff_src_color;
float16_t input_alpha;
float16_t output_alpha;
float tmx;
float tmy;
}
frag_info;

Expand All @@ -29,16 +31,20 @@ in f16vec4 v_color;

out f16vec4 frag_color;

f16vec4 Sample(f16sampler2D texture_sampler, vec2 texture_coords) {
f16vec4 Sample(f16sampler2D texture_sampler,
vec2 texture_coords,
float tmx,
float tmy) {
if (supports_decal > 0.0) {
return texture(texture_sampler, texture_coords);
}
return IPHalfSampleDecal(texture_sampler, texture_coords);
return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tmx, tmy);
}

void main() {
f16vec4 dst =
texture(texture_sampler_dst, v_texture_coords) * frag_info.input_alpha;
f16vec4 dst = Sample(texture_sampler_dst, v_texture_coords, frag_info.tmx,
frag_info.tmy) *
frag_info.input_alpha;
f16vec4 src = v_color;
frag_color =
src * (frag_info.src_coeff + dst.a * frag_info.src_coeff_dst_alpha) +
Expand Down
33 changes: 33 additions & 0 deletions impeller/entity/shaders/blending/vertices_uber.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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/blending.glsl>
#include <impeller/types.glsl>
#include "blend_select.glsl"

uniform FragInfo {
float16_t alpha;
float16_t blend_mode;
}
frag_info;

uniform f16sampler2D texture_sampler;

in highp vec2 v_texture_coords;
in mediump f16vec4 v_color;

out f16vec4 frag_color;

// A shader that implements the required src/dst blending for drawVertices and
// drawAtlas advanced blends without requiring an offscreen render pass. This is
// done in a single shader to reduce the permutations of PSO needed at runtime
// for rarely used features.
void main() {
f16vec4 dst = IPHalfUnpremultiply(v_color);
f16vec4 src = IPHalfUnpremultiply(texture(texture_sampler, v_texture_coords));
f16vec3 blend_result =
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this is fast enough maybe we'll just do all the advanced blends this way 😏

Copy link
Member

Choose a reason for hiding this comment

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

This causes stack spills (yay malioc!) on OpenGL ES on the Mali T880 (the ancient one). Notably, I don't see the spills on the Vulkan version. Given we are focusing on Vulkan, I'm definitely not opposed to landing this. But maybe have a comment in there about the spill with an issue filed so we have that observation on record for OpenGL ES.

The bound pipeline is the arith where the spill happens which tracks I suppose. Personally, I'd say the bar for shaders being "fast enough" would be to not cause these spills on the T880.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I don't see the T880 in the Vulkan malioc results. Perhaps that is too old for Vulkan? Maybe we should find an older baseline than the Mali-G78.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We shrunk down the malioc to two models, a pixel and I think the moto g4 gpu

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, if memory serves, the reasoning was that one would capture the high end on Vulkan and the other the low one with GLES. But that was when we were still focusing on GLES. Should we have two for Vulkan (and decide what the low one should be)?

In any case, don't want to distract you. This is good. There are no spills on our current Vulkan baseline.

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's a good idea , we should revisit the gpu list

AdvancedBlend(dst.rgb, src.rgb, int(frag_info.blend_mode - 14.0));
frag_color = IPApplyBlendedColor(dst, src, blend_result);
frag_color *= frag_info.alpha;
}
Loading