[Impeller] Switch to uniform arrays for gradient data on non-SSBO hardware (flutter/engine#56441)

Currently the most generalized form of the Impeller gradient shaders uses an SSBO to store the gradient information, but SSBO data is not supported on older platforms. To make the capability more general we introduce variants of the gradient shaders that uses uniform arrays which are more widely supported.
This commit is contained in:
Jim Graham 2024-11-08 10:18:05 -08:00 committed by GitHub
parent ac0b5ca828
commit 2fb2e3e70a
21 changed files with 1469 additions and 2 deletions

View File

@ -43078,15 +43078,19 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flu
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/gradient_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE
@ -45940,15 +45944,19 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert
FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_ssbo_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.vert
FILE: ../../../flutter/impeller/entity/shaders/gradients/gradient_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_ssbo_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag
FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert
FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert

View File

@ -216,6 +216,123 @@ TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) {
CanRenderLinearGradientWithOverlappingStops(this, DlTileMode::kClamp);
}
namespace {
void CanRenderGradientWithIncompleteStops(AiksTest* aiks_test,
DlColorSourceType type) {
const DlTileMode tile_modes[4] = {
DlTileMode::kClamp,
DlTileMode::kRepeat,
DlTileMode::kMirror,
DlTileMode::kDecal,
};
const DlScalar test_size = 250;
const DlScalar test_border = 25;
const DlScalar gradient_size = 50;
const DlScalar quadrant_size = test_size + test_border * 2;
DisplayListBuilder builder;
builder.DrawRect(DlRect::MakeWH(quadrant_size * 2, quadrant_size * 2),
DlPaint().setColor(DlColor::kDarkGrey()));
for (int quadrant = 0; quadrant < 4; quadrant++) {
builder.Save();
builder.Translate((quadrant & 1) * quadrant_size + test_border,
(quadrant >> 1) * quadrant_size + test_border);
if (type == DlColorSourceType::kLinearGradient) {
// Alignment lines for the gradient edges/repeats/mirrors/etc.
// (rendered under the gradient so as not to obscure it)
DlPoint center = DlPoint(test_size, test_size) * 0.5;
DlScalar ten_percent = gradient_size * 0.1;
for (int i = gradient_size / 2; i <= test_size / 2; i += gradient_size) {
auto draw_at = [=](DlCanvas& canvas, DlScalar offset, DlColor color) {
DlPaint line_paint;
line_paint.setColor(color);
// strokewidth of 2 straddles the dividing line
line_paint.setStrokeWidth(2.0f);
line_paint.setDrawStyle(DlDrawStyle::kStroke);
DlPoint along(offset, offset);
DlScalar across_distance = test_size / 2 + 10 - offset;
DlPoint across(across_distance, -across_distance);
canvas.DrawLine(center - along - across, //
center - along + across, //
line_paint);
canvas.DrawLine(center + along - across, //
center + along + across, //
line_paint);
};
// White line is at the edge of the gradient
// Grey lines are where the 0.1 and 0.9 color stops land
draw_at(builder, i - ten_percent, DlColor::kMidGrey());
draw_at(builder, i, DlColor::kWhite());
draw_at(builder, i + ten_percent, DlColor::kMidGrey());
}
}
std::vector<DlColor> colors = {
DlColor::kGreen(),
DlColor::kPurple(),
DlColor::kOrange(),
DlColor::kBlue(),
};
std::vector<Scalar> stops = {0.1, 0.3, 0.7, 0.9};
DlPaint paint;
switch (type) {
case DlColorSourceType::kLinearGradient:
paint.setColorSource(DlColorSource::MakeLinear(
{test_size / 2 - gradient_size / 2,
test_size / 2 - gradient_size / 2},
{test_size / 2 + gradient_size / 2,
test_size / 2 + gradient_size / 2},
stops.size(), colors.data(), stops.data(), tile_modes[quadrant]));
break;
case DlColorSourceType::kRadialGradient:
paint.setColorSource(DlColorSource::MakeRadial(
{test_size / 2, test_size / 2}, gradient_size, //
stops.size(), colors.data(), stops.data(), tile_modes[quadrant]));
break;
case DlColorSourceType::kConicalGradient:
paint.setColorSource(DlColorSource::MakeConical(
{test_size / 2, test_size / 2}, 0,
{test_size / 2 + 20, test_size / 2 - 10}, gradient_size,
stops.size(), colors.data(), stops.data(), tile_modes[quadrant]));
break;
case DlColorSourceType::kSweepGradient:
paint.setColorSource(DlColorSource::MakeSweep(
{test_size / 2, test_size / 2}, 0, 45, //
stops.size(), colors.data(), stops.data(), tile_modes[quadrant]));
break;
default:
FML_UNREACHABLE();
}
builder.DrawRect(SkRect::MakeXYWH(0, 0, test_size, test_size), paint);
builder.Restore();
}
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
TEST_P(AiksTest, CanRenderLinearGradientWithIncompleteStops) {
CanRenderGradientWithIncompleteStops(this,
DlColorSourceType::kLinearGradient);
}
TEST_P(AiksTest, CanRenderRadialGradientWithIncompleteStops) {
CanRenderGradientWithIncompleteStops(this,
DlColorSourceType::kRadialGradient);
}
TEST_P(AiksTest, CanRenderConicalGradientWithIncompleteStops) {
CanRenderGradientWithIncompleteStops(this,
DlColorSourceType::kConicalGradient);
}
TEST_P(AiksTest, CanRenderSweepGradientWithIncompleteStops) {
CanRenderGradientWithIncompleteStops(this, DlColorSourceType::kSweepGradient);
}
namespace {
void CanRenderLinearGradientManyColors(AiksTest* aiks_test,
DlTileMode tile_mode) {

View File

@ -18,18 +18,22 @@ impeller_shaders("entity_shaders") {
"shaders/blending/advanced_blend.frag",
"shaders/clip.frag",
"shaders/clip.vert",
"shaders/gradients/conical_gradient_fill.frag",
"shaders/glyph_atlas.frag",
"shaders/glyph_atlas.vert",
"shaders/gradients/gradient_fill.vert",
"shaders/gradients/conical_gradient_fill.frag",
"shaders/gradients/conical_gradient_uniform_fill.frag",
"shaders/gradients/linear_gradient_fill.frag",
"shaders/gradients/linear_gradient_uniform_fill.frag",
"shaders/gradients/radial_gradient_fill.frag",
"shaders/gradients/radial_gradient_uniform_fill.frag",
"shaders/gradients/sweep_gradient_fill.frag",
"shaders/gradients/sweep_gradient_uniform_fill.frag",
"shaders/rrect_blur.vert",
"shaders/rrect_blur.frag",
"shaders/runtime_effect.vert",
"shaders/solid_fill.frag",
"shaders/solid_fill.vert",
"shaders/gradients/sweep_gradient_fill.frag",
"shaders/texture_fill.frag",
"shaders/texture_fill.vert",
"shaders/texture_uv_fill.vert",

View File

@ -49,12 +49,24 @@ void ConicalGradientContents::SetFocus(std::optional<Point> focus,
focus_radius_ = radius;
}
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define UNIFORM_FRAG_INFO(t) \
t##GradientUniformFillPipeline::FragmentShader::FragInfo
#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Conical)::colors)
#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Conical)::stop_pairs)
static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops);
static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2);
bool ConicalGradientContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
return RenderSSBO(renderer, entity, pass);
}
if (colors_.size() <= kMaxUniformGradientStops &&
stops_.size() <= kMaxUniformGradientStops) {
return RenderUniform(renderer, entity, pass);
}
return RenderTexture(renderer, entity, pass);
}
@ -107,6 +119,49 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
});
}
bool ConicalGradientContents::RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = ConicalGradientUniformFillPipeline::VertexShader;
using FS = ConicalGradientUniformFillPipeline::FragmentShader;
VS::FrameInfo frame_info;
frame_info.matrix = GetInverseEffectTransform();
PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {
return renderer.GetConicalGradientUniformFillPipeline(options);
};
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &entity](RenderPass& pass) {
FS::FragInfo frag_info;
frag_info.center = center_;
if (focus_) {
frag_info.focus = focus_.value();
frag_info.focus_radius = focus_radius_;
} else {
frag_info.focus = center_;
frag_info.focus_radius = 0.0;
}
frag_info.radius = radius_;
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.alpha =
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.colors_length = PopulateUniformGradientColors(
colors_, stops_, frag_info.colors, frag_info.stop_pairs);
frag_info.decal_border_color = decal_border_color_;
pass.SetCommandLabel("ConicalGradientUniformFill");
FS::BindFragInfo(
pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
return true;
});
}
bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {

View File

@ -51,6 +51,11 @@ class ConicalGradientContents final : public ColorSourceContents {
bool RenderSSBO(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
Point center_;
Scalar radius_ = 0.0f;
std::vector<Color> colors_;

View File

@ -308,6 +308,12 @@ ContentContext::ContentContext(
conical_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options);
sweep_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options);
} else {
linear_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options);
radial_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options);
conical_gradient_uniform_fill_pipelines_.CreateDefault(*context_,
options);
sweep_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options);
linear_gradient_fill_pipelines_.CreateDefault(*context_, options);
radial_gradient_fill_pipelines_.CreateDefault(*context_, options);
conical_gradient_fill_pipelines_.CreateDefault(*context_, options);

View File

@ -56,6 +56,11 @@
#include "impeller/entity/tiled_texture_fill.frag.h"
#include "impeller/entity/yuv_to_rgb_filter.frag.h"
#include "impeller/entity/conical_gradient_uniform_fill.frag.h"
#include "impeller/entity/linear_gradient_uniform_fill.frag.h"
#include "impeller/entity/radial_gradient_uniform_fill.frag.h"
#include "impeller/entity/sweep_gradient_uniform_fill.frag.h"
#include "impeller/entity/conical_gradient_ssbo_fill.frag.h"
#include "impeller/entity/linear_gradient_ssbo_fill.frag.h"
#include "impeller/entity/radial_gradient_ssbo_fill.frag.h"
@ -92,6 +97,18 @@ using ConicalGradientFillPipeline =
using SweepGradientFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
SweepGradientFillFragmentShader>;
using LinearGradientUniformFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
LinearGradientUniformFillFragmentShader>;
using ConicalGradientUniformFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
ConicalGradientUniformFillFragmentShader>;
using RadialGradientUniformFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
RadialGradientUniformFillFragmentShader>;
using SweepGradientUniformFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
SweepGradientUniformFillFragmentShader>;
using LinearGradientSSBOFillPipeline =
RenderPipelineHandle<GradientFillVertexShader,
LinearGradientSsboFillFragmentShader>;
@ -370,6 +387,26 @@ class ContentContext {
return GetPipeline(linear_gradient_fill_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetLinearGradientUniformFillPipeline(ContentContextOptions opts) const {
return GetPipeline(linear_gradient_uniform_fill_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetRadialGradientUniformFillPipeline(ContentContextOptions opts) const {
return GetPipeline(radial_gradient_uniform_fill_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetConicalGradientUniformFillPipeline(ContentContextOptions opts) const {
return GetPipeline(conical_gradient_uniform_fill_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetSweepGradientUniformFillPipeline(ContentContextOptions opts) const {
return GetPipeline(sweep_gradient_uniform_fill_pipelines_, opts);
}
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsSSBO());
@ -867,6 +904,14 @@ class ContentContext {
mutable Variants<ConicalGradientFillPipeline>
conical_gradient_fill_pipelines_;
mutable Variants<SweepGradientFillPipeline> sweep_gradient_fill_pipelines_;
mutable Variants<LinearGradientUniformFillPipeline>
linear_gradient_uniform_fill_pipelines_;
mutable Variants<RadialGradientUniformFillPipeline>
radial_gradient_uniform_fill_pipelines_;
mutable Variants<ConicalGradientUniformFillPipeline>
conical_gradient_uniform_fill_pipelines_;
mutable Variants<SweepGradientUniformFillPipeline>
sweep_gradient_uniform_fill_pipelines_;
mutable Variants<LinearGradientSSBOFillPipeline>
linear_gradient_ssbo_fill_pipelines_;
mutable Variants<RadialGradientSSBOFillPipeline>

View File

@ -67,4 +67,31 @@ std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
return result;
}
int PopulateUniformGradientColors(
const std::vector<Color>& colors,
const std::vector<Scalar>& stops,
Vector4 frag_info_colors[kMaxUniformGradientStops],
Vector4 frag_info_stop_pairs[kMaxUniformGradientStops / 2]) {
FML_DCHECK(stops.size() == colors.size());
Scalar last_stop = 0;
int index = 0;
for (auto i = 0u; i < stops.size() && i < kMaxUniformGradientStops; i++) {
Scalar cur_stop = stops[i];
Scalar delta = cur_stop - last_stop;
Scalar inverse_delta = delta == 0.0f ? 0.0 : 1.0 / delta;
frag_info_colors[index] = colors[i];
if ((i & 1) == 0) {
frag_info_stop_pairs[index / 2].x = cur_stop;
frag_info_stop_pairs[index / 2].y = inverse_delta;
} else {
frag_info_stop_pairs[index / 2].z = cur_stop;
frag_info_stop_pairs[index / 2].w = inverse_delta;
}
last_stop = cur_stop;
index++;
}
return index;
}
} // namespace impeller

View File

@ -44,6 +44,28 @@ static_assert(sizeof(StopData) == 32);
std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
const std::vector<Scalar>& stops);
static constexpr uint32_t kMaxUniformGradientStops = 256u;
/**
* @brief Populate 2 arrays with the colors and stop data for a gradient
*
* The color data is simply converted to a vec4 format, but the stop data
* is both turned into pairs of {t, inverse_delta} information and also
* stops are themselves paired up into a vec4 format for efficient packing
* in the uniform data.
*
* @param colors colors from gradient
* @param stops stops from gradient
* @param frag_info_colors colors for fragment shader in vec4 format
* @param frag_info_stop_pairs pairs of stop data for shader in vec4 format
* @return count of colors stored
*/
int PopulateUniformGradientColors(
const std::vector<Color>& colors,
const std::vector<Scalar>& stops,
Vector4 frag_info_colors[kMaxUniformGradientStops],
Vector4 frag_info_stop_pairs[kMaxUniformGradientStops / 2]);
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_GRADIENT_GENERATOR_H_

View File

@ -186,6 +186,14 @@ bool LinearGradientContents::FastLinearGradient(const ContentContext& renderer,
/*force_stencil=*/force_stencil, geom_callback);
}
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define UNIFORM_FRAG_INFO(t) \
t##GradientUniformFillPipeline::FragmentShader::FragInfo
#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::colors)
#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::stop_pairs)
static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops);
static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2);
bool LinearGradientContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
@ -198,6 +206,10 @@ bool LinearGradientContents::Render(const ContentContext& renderer,
if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
return RenderSSBO(renderer, entity, pass);
}
if (colors_.size() <= kMaxUniformGradientStops &&
stops_.size() <= kMaxUniformGradientStops) {
return RenderUniform(renderer, entity, pass);
}
return RenderTexture(renderer, entity, pass);
}
@ -310,6 +322,44 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
});
}
bool LinearGradientContents::RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = LinearGradientUniformFillPipeline::VertexShader;
using FS = LinearGradientUniformFillPipeline::FragmentShader;
VS::FrameInfo frame_info;
frame_info.matrix = GetInverseEffectTransform();
PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {
return renderer.GetLinearGradientUniformFillPipeline(options);
};
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &entity](RenderPass& pass) {
FS::FragInfo frag_info;
frag_info.start_point = start_point_;
frag_info.start_to_end = end_point_ - start_point_;
frag_info.alpha =
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.colors_length = PopulateUniformGradientColors(
colors_, stops_, frag_info.colors, frag_info.stop_pairs);
frag_info.inverse_dot_start_to_end =
CalculateInverseDotStartToEnd(start_point_, end_point_);
frag_info.decal_border_color = decal_border_color_;
pass.SetCommandLabel("LinearGradientUniformFill");
FS::BindFragInfo(
pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
return true;
});
}
bool LinearGradientContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
for (Color& color : colors_) {

View File

@ -53,6 +53,10 @@ class LinearGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool FastLinearGradient(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;

View File

@ -55,12 +55,24 @@ bool RadialGradientContents::IsOpaque(const Matrix& transform) const {
return !AppliesAlphaForStrokeCoverage(transform);
}
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define UNIFORM_FRAG_INFO(t) \
t##GradientUniformFillPipeline::FragmentShader::FragInfo
#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Radial)::colors)
#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Radial)::stop_pairs)
static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops);
static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2);
bool RadialGradientContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
return RenderSSBO(renderer, entity, pass);
}
if (colors_.size() <= kMaxUniformGradientStops &&
stops_.size() <= kMaxUniformGradientStops) {
return RenderUniform(renderer, entity, pass);
}
return RenderTexture(renderer, entity, pass);
}
@ -106,6 +118,42 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer,
});
}
bool RadialGradientContents::RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = RadialGradientUniformFillPipeline::VertexShader;
using FS = RadialGradientUniformFillPipeline::FragmentShader;
VS::FrameInfo frame_info;
frame_info.matrix = GetInverseEffectTransform();
PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {
return renderer.GetRadialGradientUniformFillPipeline(options);
};
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &entity](RenderPass& pass) {
FS::FragInfo frag_info;
frag_info.center = center_;
frag_info.radius = radius_;
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.alpha =
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.colors_length = PopulateUniformGradientColors(
colors_, stops_, frag_info.colors, frag_info.stop_pairs);
frag_info.decal_border_color = decal_border_color_;
pass.SetCommandLabel("RadialGradientUniformFill");
FS::BindFragInfo(
pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
return true;
});
}
bool RadialGradientContents::RenderTexture(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {

View File

@ -52,6 +52,11 @@ class RadialGradientContents final : public ColorSourceContents {
bool RenderSSBO(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
Point center_;
Scalar radius_;
std::vector<Color> colors_;

View File

@ -61,12 +61,24 @@ bool SweepGradientContents::IsOpaque(const Matrix& transform) const {
return !AppliesAlphaForStrokeCoverage(transform);
}
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define UNIFORM_FRAG_INFO(t) \
t##GradientUniformFillPipeline::FragmentShader::FragInfo
#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Sweep)::colors)
#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Sweep)::stop_pairs)
static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops);
static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2);
bool SweepGradientContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
return RenderSSBO(renderer, entity, pass);
}
if (colors_.size() <= kMaxUniformGradientStops &&
stops_.size() <= kMaxUniformGradientStops) {
return RenderUniform(renderer, entity, pass);
}
return RenderTexture(renderer, entity, pass);
}
@ -116,6 +128,46 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer,
});
}
bool SweepGradientContents::RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = SweepGradientUniformFillPipeline::VertexShader;
using FS = SweepGradientUniformFillPipeline::FragmentShader;
VS::FrameInfo frame_info;
frame_info.matrix = GetInverseEffectTransform();
VS::BindFrameInfo(pass,
renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {
return renderer.GetSweepGradientUniformFillPipeline(options);
};
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &entity](RenderPass& pass) {
FS::FragInfo frag_info;
frag_info.center = center_;
frag_info.bias = bias_;
frag_info.scale = scale_;
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.alpha =
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.colors_length = PopulateUniformGradientColors(
colors_, stops_, frag_info.colors, frag_info.stop_pairs);
frag_info.decal_border_color = decal_border_color_;
pass.SetCommandLabel("SweepGradientUniformFill");
FS::BindFragInfo(
pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
return true;
});
}
bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {

View File

@ -54,6 +54,10 @@ class SweepGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
Point center_;
Scalar bias_;
Scalar scale_;

View File

@ -0,0 +1,68 @@
// 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.
precision mediump float;
#include <impeller/color.glsl>
#include <impeller/dithering.glsl>
#include <impeller/gradient.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
uniform FragInfo {
highp vec2 center;
vec2 focus;
float focus_radius;
float radius;
float tile_mode;
float alpha;
float colors_length;
vec4 decal_border_color;
vec4 colors[256];
vec4 stop_pairs[128];
}
frag_info;
highp in vec2 v_position;
out vec4 frag_color;
void main() {
vec2 res = IPComputeConicalT(frag_info.focus, frag_info.focus_radius,
frag_info.center, frag_info.radius, v_position);
float t = res.x;
vec4 result_color = vec4(0);
if (res.y < 0.0 ||
((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal)) {
result_color = frag_info.decal_border_color;
} else {
t = IPFloatTile(t, frag_info.tile_mode);
vec2 prev_stop = frag_info.stop_pairs[0].xy;
bool even = false;
for (int i = 1; i < frag_info.colors_length; i++) {
// stop_pairs[i/2].xy = values for stop i
// stop_pairs[i/2].zw = values for stop i+1
vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy
: frag_info.stop_pairs[i / 2].zw;
even = !even;
// stop.x == t value
// stop.y == inverse_delta to next stop
if (t >= prev_stop.x && t <= cur_stop.x) {
if (cur_stop.y > 1000.0) {
result_color = frag_info.colors[i];
} else {
float ratio = (t - prev_stop.x) * cur_stop.y;
result_color =
mix(frag_info.colors[i - 1], frag_info.colors[i], ratio);
}
break;
}
prev_stop = cur_stop;
}
}
frag_color = IPPremultiply(result_color) * frag_info.alpha;
}

View File

@ -0,0 +1,64 @@
// 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.
precision mediump float;
#include <impeller/color.glsl>
#include <impeller/dithering.glsl>
#include <impeller/gradient.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
uniform FragInfo {
highp vec2 start_point;
highp vec2 start_to_end;
float alpha;
float tile_mode;
float colors_length;
float inverse_dot_start_to_end;
vec4 decal_border_color;
vec4 colors[256];
vec4 stop_pairs[128];
}
frag_info;
highp in vec2 v_position;
out vec4 frag_color;
void main() {
highp vec2 start_to_position = v_position - frag_info.start_point;
highp float t = dot(start_to_position, frag_info.start_to_end) *
frag_info.inverse_dot_start_to_end;
if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) {
frag_color = frag_info.decal_border_color;
} else {
t = IPFloatTile(t, frag_info.tile_mode);
vec2 prev_stop = frag_info.stop_pairs[0].xy;
bool even = false;
for (int i = 1; i < frag_info.colors_length; i++) {
// stop_pairs[i/2].xy = values for stop i
// stop_pairs[i/2].zw = values for stop i+1
vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy
: frag_info.stop_pairs[i / 2].zw;
even = !even;
// stop.x == t value
// stop.y == inverse_delta to next stop
if (t >= prev_stop.x && t <= cur_stop.x) {
if (cur_stop.y > 1000.0) {
frag_color = frag_info.colors[i];
} else {
float ratio = (t - prev_stop.x) * cur_stop.y;
frag_color = mix(frag_info.colors[i - 1], frag_info.colors[i], ratio);
}
break;
}
prev_stop = cur_stop;
}
}
frag_color = IPPremultiply(frag_color) * frag_info.alpha;
}

View File

@ -0,0 +1,64 @@
// 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.
precision mediump float;
#include <impeller/color.glsl>
#include <impeller/dithering.glsl>
#include <impeller/gradient.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
uniform FragInfo {
highp vec2 center;
float radius;
float tile_mode;
float alpha;
float colors_length;
vec4 decal_border_color;
vec4 colors[256];
vec4 stop_pairs[128];
}
frag_info;
highp in vec2 v_position;
out vec4 frag_color;
void main() {
float len = length(v_position - frag_info.center);
float t = len / frag_info.radius;
vec4 result_color = vec4(0);
if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) {
result_color = frag_info.decal_border_color;
} else {
t = IPFloatTile(t, frag_info.tile_mode);
vec2 prev_stop = frag_info.stop_pairs[0].xy;
bool even = false;
for (int i = 1; i < frag_info.colors_length; i++) {
// stop_pairs[i/2].xy = values for stop i
// stop_pairs[i/2].zw = values for stop i+1
vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy
: frag_info.stop_pairs[i / 2].zw;
even = !even;
// stop.x == t value
// stop.y == inverse_delta to next stop
if (t >= prev_stop.x && t <= cur_stop.x) {
if (cur_stop.y > 1000.0) {
result_color = frag_info.colors[i];
} else {
float ratio = (t - prev_stop.x) * cur_stop.y;
result_color =
mix(frag_info.colors[i - 1], frag_info.colors[i], ratio);
}
break;
}
prev_stop = cur_stop;
}
}
frag_color = IPPremultiply(result_color) * frag_info.alpha;
}

View File

@ -0,0 +1,65 @@
// 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/color.glsl>
#include <impeller/constants.glsl>
#include <impeller/dithering.glsl>
#include <impeller/gradient.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>
uniform FragInfo {
highp vec2 center;
float bias;
float scale;
float tile_mode;
float alpha;
float colors_length;
vec4 decal_border_color;
vec4 colors[256];
vec4 stop_pairs[128];
}
frag_info;
highp in vec2 v_position;
out vec4 frag_color;
void main() {
vec2 coord = v_position - frag_info.center;
float angle = atan(-coord.y, -coord.x);
float t = (angle * k1Over2Pi + 0.5 + frag_info.bias) * frag_info.scale;
vec4 result_color = vec4(0);
if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) {
result_color = frag_info.decal_border_color;
} else {
t = IPFloatTile(t, frag_info.tile_mode);
vec2 prev_stop = frag_info.stop_pairs[0].xy;
bool even = false;
for (int i = 1; i < frag_info.colors_length; i++) {
// stop_pairs[i/2].xy = values for stop i
// stop_pairs[i/2].zw = values for stop i+1
vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy
: frag_info.stop_pairs[i / 2].zw;
even = !even;
// stop.x == t value
// stop.y == inverse_delta to next stop
if (t >= prev_stop.x && t <= cur_stop.x) {
if (cur_stop.y > 1000.0) {
result_color = frag_info.colors[i];
} else {
float ratio = (t - prev_stop.x) * cur_stop.y;
result_color =
mix(frag_info.colors[i - 1], frag_info.colors[i], ratio);
}
break;
}
prev_stop = cur_stop;
}
}
frag_color = IPPremultiply(result_color) * frag_info.alpha;
}

View File

@ -613,6 +613,76 @@
}
}
},
"flutter/impeller/entity/conical_gradient_uniform_fill.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/conical_gradient_uniform_fill.frag.vkspv",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 70,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.1875,
0.0625,
0.1875,
0.0,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
1.5499999523162842,
0.800000011920929,
1.5499999523162842,
0.5,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 36,
"work_registers_used": 18
}
}
}
},
"flutter/impeller/entity/fast_gradient.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
@ -1951,6 +2021,121 @@
}
}
},
"flutter/impeller/entity/gles/conical_gradient_uniform_fill.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/conical_gradient_uniform_fill.frag.gles",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 62,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.1875,
0.0625,
0.1875,
0.0,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
1.40625,
0.84375,
1.40625,
0.4375,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 38,
"work_registers_used": 21
}
}
},
"Mali-T880": {
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/conical_gradient_uniform_fill.frag.gles",
"has_uniform_computation": true,
"type": "Fragment",
"variants": {
"Main": {
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null
],
"pipelines": [
"arithmetic",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"arithmetic"
],
"shortest_path_cycles": [
1.649999976158142,
1.0,
0.0
],
"total_bound_pipelines": [
"arithmetic"
],
"total_cycles": [
20.66666603088379,
4.0,
0.0
]
},
"thread_occupancy": 100,
"uniform_registers_used": 6,
"work_registers_used": 3
}
}
}
},
"flutter/impeller/entity/gles/fast_gradient.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
@ -3210,6 +3395,121 @@
}
}
},
"flutter/impeller/entity/gles/linear_gradient_uniform_fill.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/linear_gradient_uniform_fill.frag.gles",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 13,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.203125,
0.203125,
0.171875,
0.0625,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.8125,
0.46875,
0.8125,
0.1875,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 12,
"work_registers_used": 21
}
}
},
"Mali-T880": {
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/linear_gradient_uniform_fill.frag.gles",
"has_uniform_computation": false,
"type": "Fragment",
"variants": {
"Main": {
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null
],
"pipelines": [
"arithmetic",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"arithmetic"
],
"shortest_path_cycles": [
2.640000104904175,
1.0,
0.0
],
"total_bound_pipelines": [
"arithmetic"
],
"total_cycles": [
10.0,
4.0,
0.0
]
},
"thread_occupancy": 100,
"uniform_registers_used": 3,
"work_registers_used": 3
}
}
}
},
"flutter/impeller/entity/gles/linear_to_srgb_filter.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
@ -3837,6 +4137,121 @@
}
}
},
"flutter/impeller/entity/gles/radial_gradient_uniform_fill.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/radial_gradient_uniform_fill.frag.gles",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 67,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.1875,
0.171875,
0.1875,
0.0625,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.762499988079071,
0.359375,
0.762499988079071,
0.1875,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 10,
"work_registers_used": 21
}
}
},
"Mali-T880": {
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/radial_gradient_uniform_fill.frag.gles",
"has_uniform_computation": false,
"type": "Fragment",
"variants": {
"Main": {
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null
],
"pipelines": [
"arithmetic",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"arithmetic"
],
"shortest_path_cycles": [
2.640000104904175,
1.0,
0.0
],
"total_bound_pipelines": [
"arithmetic"
],
"total_cycles": [
9.666666984558105,
4.0,
0.0
]
},
"thread_occupancy": 100,
"uniform_registers_used": 2,
"work_registers_used": 3
}
}
}
},
"flutter/impeller/entity/gles/rrect_blur.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
@ -4730,6 +5145,122 @@
}
}
},
"flutter/impeller/entity/gles/sweep_gradient_uniform_fill.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/gles/sweep_gradient_uniform_fill.frag.gles",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"arith_total",
"arith_fma"
],
"shortest_path_cycles": [
0.375,
0.375,
0.25,
0.3125,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.925000011920929,
0.625,
0.925000011920929,
0.4375,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 20,
"work_registers_used": 25
}
}
},
"Mali-T880": {
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/sweep_gradient_uniform_fill.frag.gles",
"has_uniform_computation": false,
"type": "Fragment",
"variants": {
"Main": {
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null
],
"pipelines": [
"arithmetic",
"load_store",
"texture"
],
"shortest_path_bound_pipelines": [
"arithmetic"
],
"shortest_path_cycles": [
2.9700000286102295,
1.0,
0.0
],
"total_bound_pipelines": [
"arithmetic"
],
"total_cycles": [
10.333333015441895,
5.0,
0.0
]
},
"thread_occupancy": 100,
"uniform_registers_used": 3,
"work_registers_used": 3
}
}
}
},
"flutter/impeller/entity/gles/texture_downsample.frag.gles": {
"Mali-G78": {
"core": "Mali-G78",
@ -6443,6 +6974,76 @@
}
}
},
"flutter/impeller/entity/linear_gradient_uniform_fill.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/linear_gradient_uniform_fill.frag.vkspv",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 35,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.15625,
0.15625,
0.15625,
0.0625,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.84375,
0.359375,
0.84375,
0.25,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 14,
"work_registers_used": 18
}
}
}
},
"flutter/impeller/entity/linear_to_srgb_filter.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
@ -6913,6 +7514,76 @@
}
}
},
"flutter/impeller/entity/radial_gradient_uniform_fill.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/radial_gradient_uniform_fill.frag.vkspv",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 58,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"varying"
],
"shortest_path_cycles": [
0.171875,
0.171875,
0.171875,
0.0625,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.84375,
0.359375,
0.84375,
0.25,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 12,
"work_registers_used": 18
}
}
}
},
"flutter/impeller/entity/rrect_blur.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
@ -7561,6 +8232,77 @@
}
}
},
"flutter/impeller/entity/sweep_gradient_uniform_fill.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",
"filename": "flutter/impeller/entity/sweep_gradient_uniform_fill.frag.vkspv",
"has_side_effects": false,
"has_uniform_computation": true,
"modifies_coverage": false,
"reads_color_buffer": false,
"type": "Fragment",
"uses_late_zs_test": false,
"uses_late_zs_update": false,
"variants": {
"Main": {
"fp16_arithmetic": 0,
"has_stack_spilling": false,
"performance": {
"longest_path_bound_pipelines": [
null
],
"longest_path_cycles": [
null,
null,
null,
null,
null,
null,
null
],
"pipelines": [
"arith_total",
"arith_fma",
"arith_cvt",
"arith_sfu",
"load_store",
"varying",
"texture"
],
"shortest_path_bound_pipelines": [
"arith_total",
"arith_fma"
],
"shortest_path_cycles": [
0.390625,
0.390625,
0.25,
0.3125,
0.0,
0.25,
0.0
],
"total_bound_pipelines": [
"load_store"
],
"total_cycles": [
0.875,
0.637499988079071,
0.875,
0.5,
4.0,
0.25,
0.0
]
},
"stack_spill_bytes": 0,
"thread_occupancy": 100,
"uniform_registers_used": 20,
"work_registers_used": 23
}
}
}
},
"flutter/impeller/entity/texture_downsample.frag.vkspv": {
"Mali-G78": {
"core": "Mali-G78",

View File

@ -289,6 +289,9 @@ impeller_Play_AiksTest_CanRenderColoredRect_Vulkan.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Vulkan.png
impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_Metal.png
impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_OpenGLES.png
impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_Vulkan.png
impeller_Play_AiksTest_CanRenderConicalGradient_Metal.png
impeller_Play_AiksTest_CanRenderConicalGradient_OpenGLES.png
impeller_Play_AiksTest_CanRenderConicalGradient_Vulkan.png
@ -382,6 +385,9 @@ impeller_Play_AiksTest_CanRenderLinearGradientWayManyColorsClamp_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_Vulkan.png
@ -412,6 +418,9 @@ impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradient_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradient_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradient_Vulkan.png
@ -463,6 +472,9 @@ impeller_Play_AiksTest_CanRenderSweepGradientRepeat_Vulkan.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Vulkan.png
impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_Metal.png
impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_OpenGLES.png
impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_Vulkan.png
impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_Metal.png
impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_OpenGLES.png
impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_Vulkan.png