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

Commit b698b75

Browse files
[Impeller] drawVertices uber shader. (#52315)
In order to land #52303 , we need to finally fix the advanced blend draw vertices combo. Right now a ColorFilter is used for advanced blends which doesn't work if there are overlapping vertices. See also: flutter/flutter#145707 The issue was fixed for drawVertices/drawAtlas pipeline blends using the porterduff shader. This extends this to advanced blends, but since drawVertices/atlas with an advanced blend is uncommon and because we don't 15 new shader variants, just add one special uber shader. Part of flutter/flutter#131345
1 parent 26befb4 commit b698b75

14 files changed

+674
-63
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40377,6 +40377,8 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag
4037740377
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert + ../../../flutter/LICENSE
4037840378
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag + ../../../flutter/LICENSE
4037940379
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert + ../../../flutter/LICENSE
40380+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.frag + ../../../flutter/LICENSE
40381+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.vert + ../../../flutter/LICENSE
4038040382
ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag + ../../../flutter/LICENSE
4038140383
ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert + ../../../flutter/LICENSE
4038240384
ORIGIN: ../../../flutter/impeller/entity/shaders/clip.frag + ../../../flutter/LICENSE
@@ -43257,6 +43259,8 @@ FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag
4325743259
FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert
4325843260
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag
4325943261
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert
43262+
FILE: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.frag
43263+
FILE: ../../../flutter/impeller/entity/shaders/blending/vertices_uber.vert
4326043264
FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag
4326143265
FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert
4326243266
FILE: ../../../flutter/impeller/entity/shaders/clip.frag

impeller/aiks/aiks_unittests.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2773,6 +2773,38 @@ TEST_P(AiksTest, VerticesGeometryColorUVPositionData) {
27732773
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
27742774
}
27752775

2776+
TEST_P(AiksTest, VerticesGeometryColorUVPositionDataAdvancedBlend) {
2777+
Canvas canvas;
2778+
Paint paint;
2779+
auto texture = CreateTextureForFixture("table_mountain_nx.png");
2780+
2781+
paint.color_source =
2782+
ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
2783+
Entity::TileMode::kClamp, {}, Matrix());
2784+
2785+
auto vertices = {
2786+
Point(0, 0),
2787+
Point(texture->GetSize().width, 0),
2788+
Point(0, texture->GetSize().height),
2789+
Point(texture->GetSize().width, 0),
2790+
Point(0, 0),
2791+
Point(texture->GetSize().width, texture->GetSize().height),
2792+
};
2793+
std::vector<uint16_t> indices = {};
2794+
std::vector<Point> texture_coordinates = {};
2795+
std::vector<Color> vertex_colors = {
2796+
Color::Red().WithAlpha(0.5), Color::Blue().WithAlpha(0.5),
2797+
Color::Green().WithAlpha(0.5), Color::Red().WithAlpha(0.5),
2798+
Color::Blue().WithAlpha(0.5), Color::Green().WithAlpha(0.5),
2799+
};
2800+
auto geometry = std::make_shared<VerticesGeometry>(
2801+
vertices, indices, texture_coordinates, vertex_colors,
2802+
Rect::MakeLTRB(0, 0, 1, 1), VerticesGeometry::VertexMode::kTriangles);
2803+
2804+
canvas.DrawVertices(geometry, BlendMode::kColorBurn, paint);
2805+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2806+
}
2807+
27762808
TEST_P(AiksTest, MatrixImageFilterMagnify) {
27772809
Canvas canvas;
27782810
canvas.Scale(GetContentScale());

impeller/aiks/canvas.cc

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -938,23 +938,21 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
938938

939939
// If there is are per-vertex colors, an image, and the blend mode
940940
// is simple we can draw without a sub-renderpass.
941-
if (blend_mode <= BlendMode::kModulate && vertices->HasVertexColors()) {
942-
if (std::optional<ImageData> maybe_image_data =
943-
GetImageColorSourceData(paint.color_source)) {
944-
const ImageData& image_data = maybe_image_data.value();
945-
auto contents = std::make_shared<VerticesSimpleBlendContents>();
946-
contents->SetBlendMode(blend_mode);
947-
contents->SetAlpha(paint.color.alpha);
948-
contents->SetGeometry(vertices);
949-
950-
contents->SetEffectTransform(image_data.effect_transform);
951-
contents->SetTexture(image_data.texture);
952-
contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);
953-
954-
entity.SetContents(paint.WithFilters(std::move(contents)));
955-
AddRenderEntityToCurrentPass(std::move(entity));
956-
return;
957-
}
941+
if (std::optional<ImageData> maybe_image_data =
942+
GetImageColorSourceData(paint.color_source)) {
943+
const ImageData& image_data = maybe_image_data.value();
944+
auto contents = std::make_shared<VerticesSimpleBlendContents>();
945+
contents->SetBlendMode(blend_mode);
946+
contents->SetAlpha(paint.color.alpha);
947+
contents->SetGeometry(vertices);
948+
949+
contents->SetEffectTransform(image_data.effect_transform);
950+
contents->SetTexture(image_data.texture);
951+
contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);
952+
953+
entity.SetContents(paint.WithFilters(std::move(contents)));
954+
AddRenderEntityToCurrentPass(std::move(entity));
955+
return;
958956
}
959957

960958
auto src_paint = paint;

impeller/entity/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ impeller_shaders("entity_shaders") {
5252
"shaders/filters/linear_to_srgb_filter.frag",
5353
"shaders/filters/morphology_filter.frag",
5454
"shaders/filters/morphology_filter.vert",
55+
"shaders/blending/vertices_uber.frag",
56+
"shaders/blending/vertices_uber.vert",
5557
]
5658

5759
if (impeller_debug) {

impeller/entity/contents/content_context.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ ContentContext::ContentContext(
445445
yuv_to_rgb_filter_pipelines_.CreateDefault(*context_, options_trianglestrip);
446446
porter_duff_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
447447
{supports_decal});
448+
vertices_uber_shader_.CreateDefault(*context_, options);
448449
// GLES only shader that is unsupported on macOS.
449450
#if defined(IMPELLER_ENABLE_OPENGLES) && !defined(FML_OS_MACOSX)
450451
if (GetContext()->GetBackendType() == Context::BackendType::kOpenGLES) {

impeller/entity/contents/content_context.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@
8181
#include "impeller/entity/framebuffer_blend.frag.h"
8282
#include "impeller/entity/framebuffer_blend.vert.h"
8383

84+
#include "impeller/entity/vertices_uber.frag.h"
85+
#include "impeller/entity/vertices_uber.vert.h"
86+
8487
#ifdef IMPELLER_ENABLE_OPENGLES
8588
#include "impeller/entity/tiled_texture_fill_external.frag.h"
8689
#endif // IMPELLER_ENABLE_OPENGLES
@@ -251,6 +254,10 @@ using FramebufferBlendSoftLightPipeline =
251254
RenderPipelineHandle<FramebufferBlendVertexShader,
252255
FramebufferBlendFragmentShader>;
253256

257+
/// Draw Vertices/Atlas Uber Shader
258+
using VerticesUberShader =
259+
RenderPipelineHandle<VerticesUberVertexShader, VerticesUberFragmentShader>;
260+
254261
/// Geometry Pipelines
255262
using PointsComputeShaderPipeline = ComputePipelineBuilder<PointsComputeShader>;
256263
using UvComputeShaderPipeline = ComputePipelineBuilder<UvComputeShader>;
@@ -721,6 +728,11 @@ class ContentContext {
721728
return GetPipeline(framebuffer_blend_softlight_pipelines_, opts);
722729
}
723730

731+
std::shared_ptr<Pipeline<PipelineDescriptor>> GetDrawVerticesUberShader(
732+
ContentContextOptions opts) const {
733+
return GetPipeline(vertices_uber_shader_, opts);
734+
}
735+
724736
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> GetPointComputePipeline()
725737
const {
726738
FML_DCHECK(GetDeviceCapabilities().SupportsCompute());
@@ -995,6 +1007,7 @@ class ContentContext {
9951007
framebuffer_blend_screen_pipelines_;
9961008
mutable Variants<FramebufferBlendSoftLightPipeline>
9971009
framebuffer_blend_softlight_pipelines_;
1010+
mutable Variants<VerticesUberShader> vertices_uber_shader_;
9981011
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>
9991012
point_field_compute_pipelines_;
10001013
mutable std::shared_ptr<Pipeline<ComputePipelineDescriptor>>

impeller/entity/contents/vertices_contents.cc

Lines changed: 72 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ void VerticesSimpleBlendContents::SetAlpha(Scalar alpha) {
243243
}
244244

245245
void VerticesSimpleBlendContents::SetBlendMode(BlendMode blend_mode) {
246-
FML_DCHECK(blend_mode <= BlendMode::kModulate);
247246
blend_mode_ = blend_mode;
248247
}
249248

@@ -275,11 +274,22 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
275274
const Entity& entity,
276275
RenderPass& pass) const {
277276
FML_DCHECK(texture_);
278-
FML_DCHECK(geometry_->HasVertexColors());
277+
BlendMode blend_mode = blend_mode_;
278+
if (!geometry_->HasVertexColors()) {
279+
blend_mode = BlendMode::kSource;
280+
}
281+
282+
auto dst_sampler_descriptor = descriptor_;
283+
dst_sampler_descriptor.width_address_mode =
284+
TileModeToAddressMode(tile_mode_x_, renderer.GetDeviceCapabilities())
285+
.value_or(SamplerAddressMode::kClampToEdge);
286+
dst_sampler_descriptor.height_address_mode =
287+
TileModeToAddressMode(tile_mode_y_, renderer.GetDeviceCapabilities())
288+
.value_or(SamplerAddressMode::kClampToEdge);
279289

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

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

302+
if (blend_mode <= Entity::kLastPipelineBlendMode) {
303+
using VS = PorterDuffBlendPipeline::VertexShader;
304+
using FS = PorterDuffBlendPipeline::FragmentShader;
305+
306+
#ifdef IMPELLER_DEBUG
307+
pass.SetCommandLabel(SPrintF("DrawVertices Porterduff Blend (%s)",
308+
BlendModeToString(blend_mode)));
309+
#endif // IMPELLER_DEBUG
310+
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
311+
312+
auto options = OptionsFromPassAndEntity(pass, entity);
313+
options.primitive_type = geometry_result.type;
314+
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
315+
316+
FS::BindTextureSamplerDst(pass, texture_, dst_sampler);
317+
318+
VS::FrameInfo frame_info;
319+
FS::FragInfo frag_info;
320+
321+
frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
322+
frame_info.mvp = geometry_result.transform;
323+
324+
frag_info.output_alpha = alpha_;
325+
frag_info.input_alpha = 1.0;
326+
327+
auto inverted_blend_mode =
328+
InvertPorterDuffBlend(blend_mode).value_or(BlendMode::kSource);
329+
auto blend_coefficients =
330+
kPorterDuffCoefficients[static_cast<int>(inverted_blend_mode)];
331+
frag_info.src_coeff = blend_coefficients[0];
332+
frag_info.src_coeff_dst_alpha = blend_coefficients[1];
333+
frag_info.dst_coeff = blend_coefficients[2];
334+
frag_info.dst_coeff_src_alpha = blend_coefficients[3];
335+
frag_info.dst_coeff_src_color = blend_coefficients[4];
336+
// Only used on devices that do not natively support advanced blends.
337+
frag_info.tmx = static_cast<int>(tile_mode_x_);
338+
frag_info.tmy = static_cast<int>(tile_mode_y_);
339+
340+
auto& host_buffer = renderer.GetTransientsBuffer();
341+
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
342+
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
343+
344+
return pass.Draw().ok();
345+
}
346+
347+
using VS = VerticesUberShader::VertexShader;
348+
using FS = VerticesUberShader::FragmentShader;
349+
292350
#ifdef IMPELLER_DEBUG
293-
pass.SetCommandLabel(SPrintF("DrawVertices Porterduff Blend (%s)",
294-
BlendModeToString(blend_mode_)));
351+
pass.SetCommandLabel(SPrintF("DrawVertices Advanced Blend (%s)",
352+
BlendModeToString(blend_mode)));
295353
#endif // IMPELLER_DEBUG
296354
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
297355

298356
auto options = OptionsFromPassAndEntity(pass, entity);
299357
options.primitive_type = geometry_result.type;
300-
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
301-
302-
auto dst_sampler_descriptor = descriptor_;
303-
dst_sampler_descriptor.width_address_mode =
304-
TileModeToAddressMode(tile_mode_x_, renderer.GetDeviceCapabilities())
305-
.value_or(SamplerAddressMode::kClampToEdge);
306-
dst_sampler_descriptor.height_address_mode =
307-
TileModeToAddressMode(tile_mode_y_, renderer.GetDeviceCapabilities())
308-
.value_or(SamplerAddressMode::kClampToEdge);
358+
pass.SetPipeline(renderer.GetDrawVerticesUberShader(options));
359+
FS::BindTextureSampler(pass, texture_, dst_sampler);
309360

310-
const std::unique_ptr<const Sampler>& dst_sampler =
311-
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
312-
dst_sampler_descriptor);
313-
FS::BindTextureSamplerDst(pass, texture_, dst_sampler);
314-
315-
FS::FragInfo frag_info;
316361
VS::FrameInfo frame_info;
362+
FS::FragInfo frag_info;
317363

318364
frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale();
319-
frag_info.output_alpha = alpha_;
320-
frag_info.input_alpha = 1.0;
321-
322-
auto inverted_blend_mode =
323-
InvertPorterDuffBlend(blend_mode_).value_or(BlendMode::kSource);
324-
auto blend_coefficients =
325-
kPorterDuffCoefficients[static_cast<int>(inverted_blend_mode)];
326-
frag_info.src_coeff = blend_coefficients[0];
327-
frag_info.src_coeff_dst_alpha = blend_coefficients[1];
328-
frag_info.dst_coeff = blend_coefficients[2];
329-
frag_info.dst_coeff_src_alpha = blend_coefficients[3];
330-
frag_info.dst_coeff_src_color = blend_coefficients[4];
365+
frame_info.mvp = geometry_result.transform;
366+
frag_info.alpha = alpha_;
367+
frag_info.blend_mode = static_cast<int>(blend_mode);
331368

332369
auto& host_buffer = renderer.GetTransientsBuffer();
333370
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
334-
335-
frame_info.mvp = geometry_result.transform;
336-
337-
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
338-
VS::BindFrameInfo(pass, uniform_view);
371+
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
339372

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

impeller/entity/contents/vertices_contents.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ class VerticesUVContents final : public Contents {
108108
VerticesUVContents& operator=(const VerticesUVContents&) = delete;
109109
};
110110

111-
/// A vertices contents for per-color vertices + texture and porter duff
112-
/// blended.
111+
/// A vertices contents for (optional) per-color vertices + texture and any
112+
/// blend mode.
113113
class VerticesSimpleBlendContents final : public Contents {
114114
public:
115115
VerticesSimpleBlendContents();

impeller/entity/geometry/vertices_geometry.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ GeometryResult VerticesGeometry::GetPositionUVColorBuffer(
256256
auto uv_transform =
257257
texture_coverage.GetNormalizingTransform() * effect_transform;
258258
auto has_texture_coordinates = HasTextureCoordinates();
259+
auto has_colors = HasVertexColors();
259260

260261
size_t total_vtx_bytes = vertices_.size() * sizeof(VS::PerVertexData);
261262
auto vertex_buffer = renderer.GetTransientsBuffer().Emplace(
@@ -274,7 +275,7 @@ GeometryResult VerticesGeometry::GetPositionUVColorBuffer(
274275
.texture_coords =
275276
Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
276277
std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
277-
.color = colors_[i],
278+
.color = has_colors ? colors_[i] : Color::BlackTransparent(),
278279
};
279280
std::memcpy(vtx_contents++, &vertex_data, sizeof(VS::PerVertexData));
280281
}

impeller/entity/shaders/blending/porter_duff_blend.frag

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ uniform FragInfo {
2121
float16_t dst_coeff_src_color;
2222
float16_t input_alpha;
2323
float16_t output_alpha;
24+
float tmx;
25+
float tmy;
2426
}
2527
frag_info;
2628

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

3032
out f16vec4 frag_color;
3133

32-
f16vec4 Sample(f16sampler2D texture_sampler, vec2 texture_coords) {
34+
f16vec4 Sample(f16sampler2D texture_sampler,
35+
vec2 texture_coords,
36+
float tmx,
37+
float tmy) {
3338
if (supports_decal > 0.0) {
3439
return texture(texture_sampler, texture_coords);
3540
}
36-
return IPHalfSampleDecal(texture_sampler, texture_coords);
41+
return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tmx, tmy);
3742
}
3843

3944
void main() {
40-
f16vec4 dst =
41-
texture(texture_sampler_dst, v_texture_coords) * frag_info.input_alpha;
45+
f16vec4 dst = Sample(texture_sampler_dst, v_texture_coords, frag_info.tmx,
46+
frag_info.tmy) *
47+
frag_info.input_alpha;
4248
f16vec4 src = v_color;
4349
frag_color =
4450
src * (frag_info.src_coeff + dst.a * frag_info.src_coeff_dst_alpha) +
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <impeller/blending.glsl>
6+
#include <impeller/types.glsl>
7+
#include "blend_select.glsl"
8+
9+
uniform FragInfo {
10+
float16_t alpha;
11+
float16_t blend_mode;
12+
}
13+
frag_info;
14+
15+
uniform f16sampler2D texture_sampler;
16+
17+
in highp vec2 v_texture_coords;
18+
in mediump f16vec4 v_color;
19+
20+
out f16vec4 frag_color;
21+
22+
// A shader that implements the required src/dst blending for drawVertices and
23+
// drawAtlas advanced blends without requiring an offscreen render pass. This is
24+
// done in a single shader to reduce the permutations of PSO needed at runtime
25+
// for rarely used features.
26+
void main() {
27+
f16vec4 dst = IPHalfUnpremultiply(v_color);
28+
f16vec4 src = IPHalfUnpremultiply(texture(texture_sampler, v_texture_coords));
29+
f16vec3 blend_result =
30+
AdvancedBlend(dst.rgb, src.rgb, int(frag_info.blend_mode - 14.0));
31+
frag_color = IPApplyBlendedColor(dst, src, blend_result);
32+
frag_color *= frag_info.alpha;
33+
}

0 commit comments

Comments
 (0)