Repository navigation
Handle linear and radial gradients in UberSDF #190874
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
Changes from all commits
0238b98
704e398
fec9027
c4f1565
1096e81
8bb2c2a
69cda7b
5b5fcdc
ab93ec4
cef7428
2770ec3
228eebd
236cbf0
7f4eae8
e877b1b
15877ff
a0363dc
643f07d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,4 +149,36 @@ vec3 IPComputeFixedGradientValues(float t, float colors_length) { | |
| return vec3(lower_index, upper_index, scale); | ||
| } | ||
|
|
||
| /// Samples a linear gradient from a 1D gradient ramp texture. | ||
| vec4 IPSampleLinearGradient(sampler2D tex, | ||
| vec2 start_point, | ||
| vec2 end_point, | ||
| vec2 pos, | ||
| vec2 half_texel, | ||
| float tile_mode, | ||
| vec4 decal_border_color) { | ||
| vec2 start_to_end = end_point - start_point; | ||
| vec2 start_to_position = pos - start_point; | ||
| float start_to_end_squared = dot(start_to_end, start_to_end); | ||
|
|
||
| float t = start_to_end_squared == 0.0 | ||
| ? 0.0 | ||
| : dot(start_to_position, start_to_end) / start_to_end_squared; | ||
| return IPSampleLinearWithTileMode(tex, vec2(t, 0.5), half_texel, tile_mode, | ||
| decal_border_color); | ||
| } | ||
|
|
||
| /// Samples a radial gradient from a 1D gradient ramp texture. | ||
| vec4 IPSampleRadialGradient(sampler2D tex, | ||
| vec2 center, | ||
| float radius, | ||
| vec2 pos, | ||
| vec2 half_texel, | ||
| float tile_mode, | ||
| vec4 decal_border_color) { | ||
| float t = radius == 0.0 ? 0.0 : length(pos - center) / radius; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return IPSampleLinearWithTileMode(tex, vec2(t, 0.5), half_texel, tile_mode, | ||
| decal_border_color); | ||
| } | ||
|
b-luk marked this conversation as resolved.
|
||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||
|
|
||||
| #include "impeller/entity/contents/uber_sdf_contents.h" | ||||
|
|
||||
| #include "fml/logging.h" | ||||
| #include "impeller/entity/contents/color_source_contents.h" | ||||
| #include "impeller/entity/contents/content_context.h" | ||||
| #include "impeller/entity/contents/pipelines.h" | ||||
|
|
@@ -46,6 +47,47 @@ Scalar ToShaderStrokeJoin(Join join) { | |||
| } | ||||
| } | ||||
|
|
||||
| Scalar ToShaderColorSourceType(const UberSDFParameters& params) { | ||||
| if (!params.gradient.has_value()) { | ||||
| return 0.0f; | ||||
| } | ||||
| switch (params.gradient->type) { | ||||
| case UberSDFParameters::GradientParameters::Type::kLinear: | ||||
| return 1.0f; | ||||
| case UberSDFParameters::GradientParameters::Type::kRadial: | ||||
| return 2.0f; | ||||
| } | ||||
|
b-luk marked this conversation as resolved.
|
||||
| } | ||||
|
b-luk marked this conversation as resolved.
|
||||
|
|
||||
| struct SamplerBinding { | ||||
| std::shared_ptr<Texture> texture; | ||||
| raw_ptr<const Sampler> sampler; | ||||
| }; | ||||
|
|
||||
| /// @brief Populates the gradient uniform fields in `frag_info` and returns | ||||
| /// the texture and sampler for the gradient. | ||||
| SamplerBinding SetupGradientParameters( | ||||
| const UberSDFParameters::GradientParameters& gradient, | ||||
| const ContentContext& renderer, | ||||
| FS::FragInfo& frag_info) { | ||||
| FML_DCHECK(gradient.texture); | ||||
| frag_info.gradient_start = gradient.start; | ||||
| frag_info.gradient_end = gradient.end; | ||||
| frag_info.tile_mode = static_cast<Scalar>(gradient.tile_mode); | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have a function for this conversion too?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As stated in the other comment, the enum value is expected to always exactly match the shader float value, and this is made explicit in https://github.com/flutter/flutter/blob/e6aa89eea34850cb1fd25d9f4d0b2fad379b00bf/engine/src/flutter/impeller/compiler/shader_lib/impeller/tile_mode.glsl. So I don't think an explicit conversion function here is necessary. This matches how it's used in our existing shaders, like
|
||||
| auto texture_size = gradient.texture->GetSize(); | ||||
| FML_DCHECK(!texture_size.IsEmpty()); | ||||
| frag_info.half_texel = | ||||
| Point(0.5f, 0.5f) / Point(texture_size.width, texture_size.height); | ||||
|
|
||||
| SamplerDescriptor sampler_desc; | ||||
| sampler_desc.min_filter = MinMagFilter::kLinear; | ||||
| sampler_desc.mag_filter = MinMagFilter::kLinear; | ||||
| raw_ptr<const Sampler> sampler = | ||||
| renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); | ||||
|
|
||||
| return {gradient.texture, sampler}; | ||||
| } | ||||
|
|
||||
| } // namespace | ||||
|
|
||||
| std::unique_ptr<UberSDFContents> UberSDFContents::Make( | ||||
|
|
@@ -69,6 +111,7 @@ bool UberSDFContents::Render(const ContentContext& renderer, | |||
| VS::FrameInfo frame_info; | ||||
| FS::FragInfo frag_info; | ||||
| frag_info.type = ToShaderType(params_.type); | ||||
| frag_info.color_source_type = ToShaderColorSourceType(params_); | ||||
| frag_info.color = | ||||
| params_.color.WithAlpha(params_.color.alpha * GetOpacityFactor()); | ||||
| frag_info.center = params_.center; | ||||
|
|
@@ -84,6 +127,16 @@ bool UberSDFContents::Render(const ContentContext& renderer, | |||
| frag_info.circle_center_right = params_.circle_center_right; | ||||
| frag_info.radii = params_.radii; | ||||
|
|
||||
| SamplerBinding sampler_binding; | ||||
| if (params_.gradient) { | ||||
| sampler_binding = | ||||
| SetupGradientParameters(params_.gradient.value(), renderer, frag_info); | ||||
| } else { | ||||
| sampler_binding.texture = renderer.GetEmptyTexture(); | ||||
| sampler_binding.sampler = | ||||
| renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); | ||||
| } | ||||
|
|
||||
| auto geometry_result = | ||||
| GetGeometry()->GetPositionBuffer(renderer, entity, pass); | ||||
|
|
||||
|
|
@@ -96,7 +149,10 @@ bool UberSDFContents::Render(const ContentContext& renderer, | |||
| this, GetGeometry(), renderer, entity, pass, pipeline_callback, | ||||
| frame_info, | ||||
| /*bind_fragment_callback=*/ | ||||
| [&frag_info, &data_host_buffer](RenderPass& pass) { | ||||
| [&frag_info, &data_host_buffer, | ||||
| sampler_binding = std::move(sampler_binding)](RenderPass& pass) { | ||||
| FS::BindColorSourceSampler(pass, sampler_binding.texture, | ||||
| sampler_binding.sampler); | ||||
| FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info)); | ||||
| pass.SetCommandLabel("UberSDF"); | ||||
| return true; | ||||
|
|
@@ -123,14 +179,18 @@ Color UberSDFContents::GetColor() const { | |||
|
|
||||
| bool UberSDFContents::ApplyColorFilter( | ||||
| const ColorFilterProc& color_filter_proc) { | ||||
| if (params_.gradient.has_value()) { | ||||
| return false; | ||||
| } | ||||
| params_.color = color_filter_proc(params_.color); | ||||
| return true; | ||||
| } | ||||
|
|
||||
| std::optional<Color> UberSDFContents::AsBackgroundColor( | ||||
| const Entity& entity, | ||||
| ISize target_size) const { | ||||
| if (params_.type != UberSDFParameters::Type::kRect) { | ||||
| if (params_.type != UberSDFParameters::Type::kRect || | ||||
| params_.gradient.has_value()) { | ||||
| return std::nullopt; | ||||
| } | ||||
| const Geometry* geometry = GetGeometry(); | ||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To prevent potential division-by-zero or overflow issues on some GPUs when the start and end points of a linear gradient are extremely close (but not exactly identical), consider using a small epsilon check (e.g.,
1e-6) instead of comparingstart_to_end_squareddirectly to0.0.