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