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