Flutter Impeller
conical_gradient_contents.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
10 #include "impeller/entity/entity.h"
14 
15 namespace impeller {
16 
17 namespace {
18 ConicalKind GetConicalKind(Point center,
19  Scalar radius,
20  std::optional<Point> focus,
21  Scalar focus_radius) {
23  if (!focus.has_value() ||
24  center.GetDistance(focus.value()) < kEhCloseEnough) {
25  kind = ConicalKind::kRadial;
26  }
27  if (focus.has_value() && std::fabsf(radius - focus_radius) < kEhCloseEnough) {
28  if (kind == ConicalKind::kRadial) {
30  } else {
31  kind = ConicalKind::kStrip;
32  }
33  }
34  return kind;
35 }
36 
37 } // namespace
38 
40  : geometry_(geometry) {}
41 
43 
45  return geometry_;
46 }
47 
49  center_ = center;
50  radius_ = radius;
51 }
52 
54  tile_mode_ = tile_mode;
55 }
56 
57 void ConicalGradientContents::SetColors(std::vector<Color> colors) {
58  colors_ = std::move(colors);
59 }
60 
61 void ConicalGradientContents::SetStops(std::vector<Scalar> stops) {
62  stops_ = std::move(stops);
63 }
64 
65 const std::vector<Color>& ConicalGradientContents::GetColors() const {
66  return colors_;
67 }
68 
69 const std::vector<Scalar>& ConicalGradientContents::GetStops() const {
70  return stops_;
71 }
72 
73 void ConicalGradientContents::SetFocus(std::optional<Point> focus,
74  Scalar radius) {
75  focus_ = focus;
76  focus_radius_ = radius;
77 }
78 
79 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
80 #define UNIFORM_COLORS_INFO(t) \
81  t##GradientUniformFillConicalPipeline::FragmentShader::ColorsInfo
82 #define UNIFORM_STOP_PAIRS_INFO(t) \
83  t##GradientUniformFillConicalPipeline::FragmentShader::StopPairsInfo
84 #define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_COLORS_INFO(Conical)::colors)
85 #define UNIFORM_STOP_SIZE \
86  ARRAY_LEN(UNIFORM_STOP_PAIRS_INFO(Conical)::stop_pairs)
88 static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2);
89 static_assert(sizeof(UNIFORM_COLORS_INFO(Conical)) ==
90  sizeof(UNIFORM_COLORS_INFO(Conical)::colors));
91 static_assert(sizeof(UNIFORM_STOP_PAIRS_INFO(Conical)) ==
92  sizeof(UNIFORM_STOP_PAIRS_INFO(Conical)::stop_pairs));
93 
95  const Entity& entity,
96  RenderPass& pass) const {
97  if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
98  return RenderSSBO(renderer, entity, pass);
99  }
100  if (colors_.size() <= kMaxUniformGradientStops &&
101  stops_.size() <= kMaxUniformGradientStops) {
102  return RenderUniform(renderer, entity, pass);
103  }
104  return RenderTexture(renderer, entity, pass);
105 }
106 
107 bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
108  const Entity& entity,
109  RenderPass& pass) const {
112 
113  VS::FrameInfo frame_info;
114  frame_info.matrix = GetInverseEffectTransform();
115 
116  ConicalKind kind = GetConicalKind(center_, radius_, focus_, focus_radius_);
117  PipelineBuilderCallback pipeline_callback =
118  [&renderer, kind](ContentContextOptions options) {
119  return renderer.GetConicalGradientSSBOFillPipeline(options, kind);
120  };
121  return ColorSourceContents::DrawGeometry<VS>(
122  renderer, entity, pass, pipeline_callback, frame_info,
123  [this, &renderer, &entity](RenderPass& pass) {
124  FS::FragInfo frag_info;
125  frag_info.center = center_;
126  frag_info.radius = radius_;
127  frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
128  frag_info.decal_border_color = decal_border_color_;
129  frag_info.alpha =
130  GetOpacityFactor() *
132  if (focus_) {
133  frag_info.focus = focus_.value();
134  frag_info.focus_radius = focus_radius_;
135  } else {
136  frag_info.focus = center_;
137  frag_info.focus_radius = 0.0;
138  }
139 
140  auto& data_host_buffer = renderer.GetTransientsDataBuffer();
141  auto colors = CreateGradientColors(colors_, stops_);
142 
143  frag_info.colors_length = colors.size();
144  auto color_buffer = data_host_buffer.Emplace(
145  colors.data(), colors.size() * sizeof(StopData),
146  renderer.GetDeviceCapabilities()
148 
149  FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
150  FS::BindColorData(pass, color_buffer);
151 
152  pass.SetCommandLabel("ConicalGradientSSBOFill");
153  return true;
154  });
155 }
156 
157 bool ConicalGradientContents::RenderUniform(const ContentContext& renderer,
158  const Entity& entity,
159  RenderPass& pass) const {
162 
163  VS::FrameInfo frame_info;
164  frame_info.matrix = GetInverseEffectTransform();
165 
166  ConicalKind kind = GetConicalKind(center_, radius_, focus_, focus_radius_);
167  PipelineBuilderCallback pipeline_callback =
168  [&renderer, kind](ContentContextOptions options) {
169  return renderer.GetConicalGradientUniformFillPipeline(options, kind);
170  };
171  return ColorSourceContents::DrawGeometry<VS>(
172  renderer, entity, pass, pipeline_callback, frame_info,
173  [this, &renderer, &entity](RenderPass& pass) {
174  FS::FragInfo frag_info;
175  FS::ColorsInfo colors_info;
176  FS::StopPairsInfo stop_pairs_info;
177 
178  frag_info.center = center_;
179  if (focus_) {
180  frag_info.focus = focus_.value();
181  frag_info.focus_radius = focus_radius_;
182  } else {
183  frag_info.focus = center_;
184  frag_info.focus_radius = 0.0;
185  }
186  frag_info.radius = radius_;
187  frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
188  frag_info.alpha =
189  GetOpacityFactor() *
190  GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
191  frag_info.colors_length = PopulateUniformGradientColors(
192  colors_, stops_, colors_info.colors, stop_pairs_info.stop_pairs);
193  frag_info.decal_border_color = decal_border_color_;
194 
195  pass.SetCommandLabel("ConicalGradientUniformFill");
196 
197  auto& transients_buffer = renderer.GetTransientsDataBuffer();
198  FS::BindFragInfo(pass, transients_buffer.EmplaceUniform(frag_info));
199  FS::BindColorsInfo(pass, transients_buffer.EmplaceUniform(colors_info));
200  FS::BindStopPairsInfo(
201  pass, transients_buffer.EmplaceUniform(stop_pairs_info));
202 
203  return true;
204  });
205 }
206 
207 bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
208  const Entity& entity,
209  RenderPass& pass) const {
212 
213  auto gradient_data = CreateGradientBuffer(colors_, stops_);
214  auto gradient_texture =
215  CreateGradientTexture(gradient_data, renderer.GetContext());
216  if (gradient_texture == nullptr) {
217  return false;
218  }
219 
220  VS::FrameInfo frame_info;
221  frame_info.matrix = GetInverseEffectTransform();
222 
223  ConicalKind kind = GetConicalKind(center_, radius_, focus_, focus_radius_);
224  PipelineBuilderCallback pipeline_callback =
225  [&renderer, kind](ContentContextOptions options) {
226  return renderer.GetConicalGradientFillPipeline(options, kind);
227  };
228  return ColorSourceContents::DrawGeometry<VS>(
229  renderer, entity, pass, pipeline_callback, frame_info,
230  [this, &renderer, &gradient_texture, &entity](RenderPass& pass) {
231  FS::FragInfo frag_info;
232  frag_info.center = center_;
233  frag_info.radius = radius_;
234  frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
235  frag_info.decal_border_color = decal_border_color_;
236  frag_info.alpha =
237  GetOpacityFactor() *
238  GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
239  frag_info.half_texel =
240  Vector2(0.5 / gradient_texture->GetSize().width,
241  0.5 / gradient_texture->GetSize().height);
242  if (focus_) {
243  frag_info.focus = focus_.value();
244  frag_info.focus_radius = focus_radius_;
245  } else {
246  frag_info.focus = center_;
247  frag_info.focus_radius = 0.0;
248  }
249 
250  pass.SetCommandLabel("ConicalGradientFill");
251 
252  FS::BindFragInfo(
253  pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frag_info));
254  SamplerDescriptor sampler_desc;
255  sampler_desc.min_filter = MinMagFilter::kLinear;
256  sampler_desc.mag_filter = MinMagFilter::kLinear;
257  FS::BindTextureSampler(
258  pass, gradient_texture,
259  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
260  sampler_desc));
261 
262  return true;
263  });
264 }
265 
267  const ColorFilterProc& color_filter_proc) {
268  for (Color& color : colors_) {
269  color = color_filter_proc(color);
270  }
271  decal_border_color_ = color_filter_proc(decal_border_color_);
272  return true;
273 }
274 
275 } // namespace impeller
virtual size_t GetMinimumStorageBufferAlignment() const
The minimum alignment of storage buffer value offsets in bytes.
Definition: capabilities.cc:14
virtual bool SupportsSSBO() const =0
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
Scalar GetOpacityFactor() const
Get the opacity factor for this color source.
const Matrix & GetInverseEffectTransform() const
Get the inverted effect transform for this color source.
std::function< PipelineRef(ContentContextOptions)> PipelineBuilderCallback
void SetFocus(std::optional< Point > focus, Scalar radius)
bool ApplyColorFilter(const ColorFilterProc &color_filter_proc) override
If possible, applies a color filter to this contents inputs on the CPU.
void SetStops(std::vector< Scalar > stops)
void SetCenterAndRadius(Point center, Scalar radius)
const Geometry * GetGeometry() const override
Get the geometry that this contents will use to render.
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
const std::vector< Scalar > & GetStops() const
void SetTileMode(Entity::TileMode tile_mode)
const std::vector< Color > & GetColors() const
ConicalGradientContents(const Geometry *geometry)
void SetColors(std::vector< Color > colors)
const Capabilities & GetDeviceCapabilities() const
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
PipelineRef GetConicalGradientSSBOFillPipeline(ContentContextOptions opts, ConicalKind kind) const
std::function< Color(Color)> ColorFilterProc
Definition: contents.h:35
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
virtual Scalar ComputeAlphaCoverage(const Matrix &transform) const
Definition: geometry.h:135
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
FragmentShader_ FragmentShader
Definition: pipeline.h:169
#define UNIFORM_STOP_PAIRS_INFO(t)
#define UNIFORM_STOP_SIZE
#define UNIFORM_COLORS_INFO(t)
#define UNIFORM_COLOR_SIZE
Point Vector2
Definition: point.h:430
float Scalar
Definition: scalar.h:19
constexpr float kEhCloseEnough
Definition: constants.h:57
TPoint< Scalar > Point
Definition: point.h:426
LinePipeline::FragmentShader FS
int PopulateUniformGradientColors(const std::vector< Color > &colors, const std::vector< Scalar > &stops, Vector4 frag_info_colors[kMaxUniformGradientStops], Vector4 frag_info_stop_pairs[kMaxUniformGradientStops/2])
Populate 2 arrays with the colors and stop data for a gradient.
std::vector< StopData > CreateGradientColors(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the color and stop data for a gradient.
LinePipeline::VertexShader VS
std::shared_ptr< Texture > CreateGradientTexture(const GradientData &gradient_data, const std::shared_ptr< impeller::Context > &context)
Create a host visible texture that contains the gradient defined by the provided gradient data.
GradientData CreateGradientBuffer(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the interpolated color bytes for the linear gradient described by colors and s...
Definition: gradient.cc:20
static constexpr uint32_t kMaxUniformGradientStops
Scalar alpha
Definition: color.h:143