Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Switch to uniform arrays for gradient data on non-SSBO hardware #56294

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -45938,15 +45942,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
Expand Down
8 changes: 6 additions & 2 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
55 changes: 55 additions & 0 deletions impeller/entity/contents/conical_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions impeller/entity/contents/conical_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
45 changes: 45 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -91,6 +96,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>;
Expand Down Expand Up @@ -366,6 +383,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());
Expand Down Expand Up @@ -858,6 +895,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>
Expand Down
27 changes: 27 additions & 0 deletions impeller/entity/contents/gradient_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
22 changes: 22 additions & 0 deletions impeller/entity/contents/gradient_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
50 changes: 50 additions & 0 deletions impeller/entity/contents/linear_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
}

Expand Down Expand Up @@ -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_) {
Expand Down
4 changes: 4 additions & 0 deletions impeller/entity/contents/linear_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class LinearGradientContents final : public ColorSourceContents {
const Entity& entity,
Copy link
Member

Choose a reason for hiding this comment

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

Can we also remove RenderTexture in this patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eventually, I want to leave the old stuff around while I get the new stuff working and then I can run comparisons for testing/benchmarking.

Copy link
Member

Choose a reason for hiding this comment

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

SGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Per other discussions I think we decided it would stay in case we get more than 256 colors. Eventually we hope to have a vertex tiling solution that works efficiently on all platforms, but until then we'll still have the issue with zero-length stops on older platforms, but only if there are more than 256 stops total...

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;
Expand Down
Loading