211 {
212
213
214
215 if (CanApplyFastGradient()) {
216 return FastLinearGradient(renderer, entity, pass);
217 }
218 if (renderer.GetDeviceCapabilities().SupportsSSBO()) {
219 return RenderSSBO(renderer, entity, pass);
220 }
221 if (colors_.size() <= kMaxUniformGradientStops &&
222 stops_.size() <= kMaxUniformGradientStops) {
223 return RenderUniform(renderer, entity, pass);
224 }
225 return RenderTexture(renderer, entity, pass);
226}
227
228bool LinearGradientContents::RenderTexture(const ContentContext& renderer,
229 const Entity& entity,
230 RenderPass& pass) const {
231 using VS = LinearGradientFillPipeline::VertexShader;
232 using FS = LinearGradientFillPipeline::FragmentShader;
233
234 VS::FrameInfo frame_info;
235 frame_info.matrix = GetInverseEffectTransform();
236
237 PipelineBuilderCallback pipeline_callback =
238 [&renderer](ContentContextOptions options) {
239 return renderer.GetLinearGradientFillPipeline(options);
240 };
241 return ColorSourceContents::DrawGeometry<VS>(
242 renderer, entity, pass, pipeline_callback, frame_info,
243 [this, &renderer, &entity](RenderPass& pass) {
245 auto gradient_texture =
247 if (gradient_texture == nullptr) {
248 return false;
249 }
250
251 FS::FragInfo frag_info;
252 frag_info.start_point = start_point_;
253 frag_info.end_point = end_point_;
254 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
255 frag_info.decal_border_color = decal_border_color_;
256 frag_info.alpha =
257 GetOpacityFactor() *
258 GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
259 ;
260 frag_info.half_texel =
261 Vector2(0.5 / gradient_texture->GetSize().width,
262 0.5 / gradient_texture->GetSize().height);
263
264 pass.SetCommandLabel("LinearGradientFill");
265
266 SamplerDescriptor sampler_desc;
267 sampler_desc.min_filter = MinMagFilter::kLinear;
268 sampler_desc.mag_filter = MinMagFilter::kLinear;
269
270 FS::BindTextureSampler(
271 pass, std::move(gradient_texture),
272 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
273 sampler_desc));
274 FS::BindFragInfo(
275 pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frag_info));
276 return true;
277 });
278}
279
280namespace {
281Scalar CalculateInverseDotStartToEnd(Point start_point, Point end_point) {
282 Point start_to_end = end_point - start_point;
284 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
285 return dot == 0.0f ? 0.0f : 1.0f / dot;
286}
287}
288
289bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
290 const Entity& entity,
291 RenderPass& pass) const {
292 using VS = LinearGradientSSBOFillPipeline::VertexShader;
293 using FS = LinearGradientSSBOFillPipeline::FragmentShader;
294
295 VS::FrameInfo frame_info;
296 frame_info.matrix = GetInverseEffectTransform();
297
298 PipelineBuilderCallback pipeline_callback =
299 [&renderer](ContentContextOptions options) {
300 return renderer.GetLinearGradientSSBOFillPipeline(options);
301 };
302 return ColorSourceContents::DrawGeometry<VS>(
303 renderer, entity, pass, pipeline_callback, frame_info,
304 [this, &renderer, &entity](RenderPass& pass) {
305 FS::FragInfo frag_info;
306 frag_info.start_point = start_point_;
307 frag_info.end_point = end_point_;
308 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
309 frag_info.decal_border_color = decal_border_color_;
310 frag_info.alpha =
311 GetOpacityFactor() *
312 GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
313 frag_info.start_to_end = end_point_ - start_point_;
314 frag_info.inverse_dot_start_to_end =
315 CalculateInverseDotStartToEnd(start_point_, end_point_);
316
317 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
319
320 frag_info.colors_length = colors.size();
321 auto color_buffer = data_host_buffer.Emplace(
322 colors.data(), colors.size() * sizeof(StopData),
323 renderer.GetDeviceCapabilities()
324 .GetMinimumStorageBufferAlignment());
325
326 pass.SetCommandLabel("LinearGradientSSBOFill");
327
328 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
329 FS::BindColorData(pass, color_buffer);
330
331 return true;
332 });
333}
334
335bool LinearGradientContents::RenderUniform(const ContentContext& renderer,
336 const Entity& entity,
337 RenderPass& pass) const {
338 using VS = LinearGradientUniformFillPipeline::VertexShader;
339 using FS = LinearGradientUniformFillPipeline::FragmentShader;
340
341 VS::FrameInfo frame_info;
342 frame_info.matrix = GetInverseEffectTransform();
343
344 PipelineBuilderCallback pipeline_callback =
345 [&renderer](ContentContextOptions options) {
346 return renderer.GetLinearGradientUniformFillPipeline(options);
347 };
348 return ColorSourceContents::DrawGeometry<VS>(
349 renderer, entity, pass, pipeline_callback, frame_info,
350 [this, &renderer, &entity](RenderPass& pass) {
351 FS::FragInfo frag_info;
352 FS::ColorsInfo colors_info;
353 FS::StopPairsInfo stop_pairs_info;
354
355 frag_info.start_point = start_point_;
356 frag_info.start_to_end = end_point_ - start_point_;
357 frag_info.alpha =
358 GetOpacityFactor() *
359 GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
360 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
362 colors_, stops_, colors_info.colors, stop_pairs_info.stop_pairs);
363 frag_info.inverse_dot_start_to_end =
364 CalculateInverseDotStartToEnd(start_point_, end_point_);
365 frag_info.decal_border_color = decal_border_color_;
366
367 pass.SetCommandLabel("LinearGradientUniformFill");
368
369 auto& transients_buffer = renderer.GetTransientsDataBuffer();
370 FS::BindFragInfo(pass, transients_buffer.EmplaceUniform(frag_info));
371 FS::BindColorsInfo(pass, transients_buffer.EmplaceUniform(colors_info));
372 FS::BindStopPairsInfo(
373 pass, transients_buffer.EmplaceUniform(stop_pairs_info));
374
375 return true;
376 });
377}
378
379bool LinearGradientContents::ApplyColorFilter(
380 const ColorFilterProc& color_filter_proc) {
381 for (Color& color : colors_) {
382 color = color_filter_proc(color);
383 }
384 decal_border_color_ = color_filter_proc(decal_border_color_);
385 return true;
386}
387
388}
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...