[Impeller] porter duff workarounds for Adreno GPU. (#161273)

Part of https://github.com/flutter/flutter/issues/161209

Many Adreno 6XX are having trouble compiling the PorterDuff and
ConicalGradient Pipeline. This rewrites the former to use specialization
constants to reduce runtime branches. From testing on an S9+, this is
sufficient to get it to compile correctly.

As a bonus, this should be faster... though it adds more shaders.
This commit is contained in:
Jonah Williams 2025-01-07 21:50:21 -08:00 committed by GitHub
parent 5f2bf18183
commit b5df29072d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 215 additions and 53 deletions

View File

@ -97,8 +97,10 @@ bool AtlasContents::Render(const ContentContext& renderer,
pass.SetCommandLabel("DrawAtlas Blend");
#endif // IMPELLER_DEBUG
pass.SetVertexBuffer(geometry_->CreateBlendVertexBuffer(host_buffer));
pass.SetPipeline(
renderer.GetPorterDuffBlendPipeline(OptionsFromPass(pass)));
auto inverted_blend_mode =
InvertPorterDuffBlend(blend_mode).value_or(BlendMode::kSource);
pass.SetPipeline(renderer.GetPorterDuffPipeline(inverted_blend_mode,
OptionsFromPass(pass)));
FS::FragInfo frag_info;
VS::FrameInfo frame_info;
@ -110,15 +112,6 @@ bool AtlasContents::Render(const ContentContext& renderer,
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];
// These values are ignored on platforms that natively support decal.
frag_info.tmx = static_cast<int>(Entity::TileMode::kDecal);
frag_info.tmy = static_cast<int>(Entity::TileMode::kDecal);

View File

@ -220,6 +220,28 @@ void ContentContextOptions::ApplyToPipelineDescriptor(
desc.SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill);
}
std::array<std::vector<Scalar>, 15> GetPorterDuffSpecConstants(
bool supports_decal) {
Scalar x = supports_decal ? 1 : 0;
return {{
{x, 0, 0, 0, 0, 0}, // Clear
{x, 1, 0, 0, 0, 0}, // Source
{x, 0, 0, 1, 0, 0}, // Destination
{x, 1, 0, 1, -1, 0}, // SourceOver
{x, 1, -1, 1, 0, 0}, // DestinationOver
{x, 0, 1, 0, 0, 0}, // SourceIn
{x, 0, 0, 0, 1, 0}, // DestinationIn
{x, 1, -1, 0, 0, 0}, // SourceOut
{x, 0, 0, 1, -1, 0}, // DestinationOut
{x, 0, 1, 1, -1, 0}, // SourceATop
{x, 1, -1, 0, 1, 0}, // DestinationATop
{x, 1, -1, 1, -1, 0}, // Xor
{x, 1, 0, 1, 0, 0}, // Plus
{x, 0, 0, 0, 0, 1}, // Modulate
{x, 0, 0, 1, 0, -1}, // Screen
}};
}
template <typename PipelineT>
static std::unique_ptr<PipelineT> CreateDefaultPipeline(
const Context& context) {
@ -352,9 +374,40 @@ ContentContext::ContentContext(
border_mask_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
color_matrix_color_filter_pipelines_.CreateDefault(*context_,
options_trianglestrip);
porter_duff_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
{supports_decal});
vertices_uber_shader_.CreateDefault(*context_, options, {supports_decal});
const std::array<std::vector<Scalar>, 15> porter_duff_constants =
GetPorterDuffSpecConstants(supports_decal);
clear_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[0]);
source_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[1]);
destination_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[2]);
source_over_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[3]);
destination_over_blend_pipelines_.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[4]);
source_in_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[5]);
destination_in_blend_pipelines_.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[6]);
source_out_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[7]);
destination_out_blend_pipelines_.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[8]);
source_a_top_blend_pipelines_.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[9]);
destination_a_top_blend_pipelines_.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[10]);
xor_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[11]);
plus_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[12]);
modulate_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[13]);
screen_blend_pipelines_.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[14]);
}
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {

View File

@ -15,6 +15,7 @@
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/geometry/color.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline.h"
@ -522,8 +523,121 @@ class ContentContext {
return GetPipeline(yuv_to_rgb_filter_pipelines_, opts);
}
PipelineRef GetPorterDuffBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(porter_duff_blend_pipelines_, opts);
// Porter-Duff combined blends.
PipelineRef GetPorterDuffPipeline(BlendMode mode,
ContentContextOptions opts) const {
switch (mode) {
case BlendMode::kClear:
return GetClearBlendPipeline(opts);
case BlendMode::kSource:
return GetSourceBlendPipeline(opts);
case BlendMode::kDestination:
return GetDestinationBlendPipeline(opts);
case BlendMode::kSourceOver:
return GetSourceOverBlendPipeline(opts);
case BlendMode::kDestinationOver:
return GetDestinationOverBlendPipeline(opts);
case BlendMode::kSourceIn:
return GetSourceInBlendPipeline(opts);
case BlendMode::kDestinationIn:
return GetDestinationInBlendPipeline(opts);
case BlendMode::kSourceOut:
return GetSourceOutBlendPipeline(opts);
case BlendMode::kDestinationOut:
return GetDestinationOutBlendPipeline(opts);
case BlendMode::kSourceATop:
return GetSourceATopBlendPipeline(opts);
case BlendMode::kDestinationATop:
return GetDestinationATopBlendPipeline(opts);
case BlendMode::kXor:
return GetXorBlendPipeline(opts);
case BlendMode::kPlus:
return GetPlusBlendPipeline(opts);
case BlendMode::kModulate:
return GetModulateBlendPipeline(opts);
case BlendMode::kScreen:
return GetScreenBlendPipeline(opts);
case BlendMode::kOverlay:
case BlendMode::kDarken:
case BlendMode::kLighten:
case BlendMode::kColorDodge:
case BlendMode::kColorBurn:
case BlendMode::kHardLight:
case BlendMode::kSoftLight:
case BlendMode::kDifference:
case BlendMode::kExclusion:
case BlendMode::kMultiply:
case BlendMode::kHue:
case BlendMode::kSaturation:
case BlendMode::kColor:
case BlendMode::kLuminosity:
VALIDATION_LOG << "Invalid porter duff blend mode "
<< BlendModeToString(mode);
return GetClearBlendPipeline(opts);
break;
}
}
PipelineRef GetClearBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(clear_blend_pipelines_, opts);
}
PipelineRef GetSourceBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(source_blend_pipelines_, opts);
}
PipelineRef GetDestinationBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(destination_blend_pipelines_, opts);
}
PipelineRef GetSourceOverBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(source_over_blend_pipelines_, opts);
}
PipelineRef GetDestinationOverBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(destination_over_blend_pipelines_, opts);
}
PipelineRef GetSourceInBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(source_in_blend_pipelines_, opts);
}
PipelineRef GetDestinationInBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(destination_in_blend_pipelines_, opts);
}
PipelineRef GetSourceOutBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(source_out_blend_pipelines_, opts);
}
PipelineRef GetDestinationOutBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(destination_out_blend_pipelines_, opts);
}
PipelineRef GetSourceATopBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(source_a_top_blend_pipelines_, opts);
}
PipelineRef GetDestinationATopBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(destination_a_top_blend_pipelines_, opts);
}
PipelineRef GetXorBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(xor_blend_pipelines_, opts);
}
PipelineRef GetPlusBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(plus_blend_pipelines_, opts);
}
PipelineRef GetModulateBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(modulate_blend_pipelines_, opts);
}
PipelineRef GetScreenBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(screen_blend_pipelines_, opts);
}
// Advanced blends.
@ -826,7 +940,7 @@ class ContentContext {
void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::initializer_list<Scalar>& constants = {}) {
const std::vector<Scalar>& constants = {}) {
auto desc = PipelineHandleT::Builder::MakeDefaultPipelineDescriptor(
context, constants);
if (!desc.has_value()) {
@ -916,7 +1030,24 @@ class ContentContext {
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
mutable Variants<YUVToRGBFilterPipeline> yuv_to_rgb_filter_pipelines_;
mutable Variants<PorterDuffBlendPipeline> porter_duff_blend_pipelines_;
// Porter Duff Blends.
mutable Variants<PorterDuffBlendPipeline> clear_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_over_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_over_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_in_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_in_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_out_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_out_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_a_top_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_a_top_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> xor_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> plus_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> modulate_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> screen_blend_pipelines_;
// Advanced blends.
mutable Variants<BlendColorPipeline> blend_color_pipelines_;
mutable Variants<BlendColorBurnPipeline> blend_colorburn_pipelines_;

View File

@ -470,7 +470,7 @@ std::optional<Entity> BlendFilterContents::CreateForegroundPorterDuffBlend(
pass.SetVertexBuffer(std::move(vtx_buffer));
auto options = OptionsFromPassAndEntity(pass, entity);
options.primitive_type = PrimitiveType::kTriangleStrip;
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
pass.SetPipeline(renderer.GetPorterDuffPipeline(blend_mode, options));
FS::FragInfo frag_info;
VS::FrameInfo frame_info;
@ -497,14 +497,6 @@ std::optional<Entity> BlendFilterContents::CreateForegroundPorterDuffBlend(
: 1.0;
frag_info.output_alpha = 1.0;
auto blend_coefficients =
kPorterDuffCoefficients[static_cast<int>(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];
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));

View File

@ -151,7 +151,10 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
auto options = OptionsFromPassAndEntity(pass, entity);
options.primitive_type = geometry_result.type;
pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
auto inverted_blend_mode =
InvertPorterDuffBlend(blend_mode).value_or(BlendMode::kSource);
pass.SetPipeline(
renderer.GetPorterDuffPipeline(inverted_blend_mode, options));
FS::BindTextureSamplerDst(pass, texture, dst_sampler);
@ -164,16 +167,6 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer,
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];
// These values are ignored if the platform supports native decal mode.
frag_info.tmx = static_cast<int>(tile_mode_x_);
frag_info.tmy = static_cast<int>(tile_mode_y_);

View File

@ -9,16 +9,17 @@ precision mediump float;
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
// see GetPorterDuffSpecConstants in content_context.cc for actual constants
layout(constant_id = 0) const float supports_decal = 1.0;
layout(constant_id = 1) const float src_coeff = 1.0;
layout(constant_id = 2) const float src_coeff_dst_alpha = 1.0;
layout(constant_id = 3) const float dst_coeff = 1.0;
layout(constant_id = 4) const float dst_coeff_src_alpha = 1.0;
layout(constant_id = 5) const float dst_coeff_src_color = 1.0;
uniform f16sampler2D texture_sampler_dst;
uniform FragInfo {
float16_t src_coeff;
float16_t src_coeff_dst_alpha;
float16_t dst_coeff;
float16_t dst_coeff_src_alpha;
float16_t dst_coeff_src_color;
float16_t input_alpha;
float16_t output_alpha;
float tmx;
@ -29,7 +30,7 @@ frag_info;
in vec2 v_texture_coords;
in f16vec4 v_color;
out f16vec4 frag_color;
out vec4 frag_color;
f16vec4 Sample(f16sampler2D texture_sampler,
vec2 texture_coords,
@ -46,9 +47,8 @@ void main() {
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) +
dst * (frag_info.dst_coeff + src.a * frag_info.dst_coeff_src_alpha +
src * frag_info.dst_coeff_src_color);
frag_color = f16vec4(src * (src_coeff + dst.a * src_coeff_dst_alpha) +
dst * (dst_coeff + src.a * dst_coeff_src_alpha +
src * dst_coeff_src_color));
frag_color *= frag_info.output_alpha;
}

View File

@ -3812,8 +3812,8 @@
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 8,
"work_registers_used": 19
"uniform_registers_used": 4,
"work_registers_used": 20
}
}
},
@ -3830,7 +3830,7 @@
"arithmetic"
],
"longest_path_cycles": [
1.649999976158142,
1.3200000524520874,
1.0,
1.0
],
@ -3843,7 +3843,7 @@
"arithmetic"
],
"shortest_path_cycles": [
1.649999976158142,
1.3200000524520874,
1.0,
1.0
],
@ -3851,7 +3851,7 @@
"arithmetic"
],
"total_cycles": [
2.0,
1.6666666269302368,
1.0,
1.0
]
@ -7251,7 +7251,7 @@
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 14,
"uniform_registers_used": 6,
"work_registers_used": 11
}
}