Flutter Impeller
blend_filter_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 
7 #include <array>
8 #include <memory>
9 #include <optional>
10 
11 #include "flutter/fml/logging.h"
12 #include "impeller/base/strings.h"
13 #include "impeller/core/formats.h"
23 #include "impeller/entity/entity.h"
25 #include "impeller/entity/texture_fill.frag.h"
26 #include "impeller/entity/texture_fill.vert.h"
30 
31 namespace impeller {
32 
33 std::optional<BlendMode> InvertPorterDuffBlend(BlendMode blend_mode) {
34  switch (blend_mode) {
35  case BlendMode::kClear:
36  return BlendMode::kClear;
37  case BlendMode::kSource:
40  return BlendMode::kSource;
48  return BlendMode::kSourceIn;
52  return BlendMode::kSourceOut;
57  case BlendMode::kXor:
58  return BlendMode::kXor;
59  case BlendMode::kPlus:
60  return BlendMode::kPlus;
62  return BlendMode::kModulate;
63  default:
64  return std::nullopt;
65  }
66 }
67 
70 }
71 
73 
74 using PipelineProc = std::shared_ptr<Pipeline<PipelineDescriptor>> (
76 
77 template <typename TPipeline>
78 static std::optional<Entity> AdvancedBlend(
79  const FilterInput::Vector& inputs,
80  const ContentContext& renderer,
81  const Entity& entity,
82  const Rect& coverage,
83  BlendMode blend_mode,
84  std::optional<Color> foreground_color,
86  PipelineProc pipeline_proc,
87  std::optional<Scalar> alpha) {
88  using VS = typename TPipeline::VertexShader;
89  using FS = typename TPipeline::FragmentShader;
90 
91  //----------------------------------------------------------------------------
92  /// Handle inputs.
93  ///
94 
95  const size_t total_inputs =
96  inputs.size() + (foreground_color.has_value() ? 1 : 0);
97  if (total_inputs < 2) {
98  return std::nullopt;
99  }
100 
101  auto dst_snapshot =
102  inputs[0]->GetSnapshot("AdvancedBlend(Dst)", renderer, entity);
103  if (!dst_snapshot.has_value()) {
104  return std::nullopt;
105  }
106  auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
107  if (!maybe_dst_uvs.has_value()) {
108  return std::nullopt;
109  }
110  auto dst_uvs = maybe_dst_uvs.value();
111 
112  std::optional<Snapshot> src_snapshot;
113  std::array<Point, 4> src_uvs;
114  if (!foreground_color.has_value()) {
115  src_snapshot =
116  inputs[1]->GetSnapshot("AdvancedBlend(Src)", renderer, entity);
117  if (!src_snapshot.has_value()) {
118  if (!dst_snapshot.has_value()) {
119  return std::nullopt;
120  }
121  return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode());
122  }
123  auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
124  if (!maybe_src_uvs.has_value()) {
125  if (!dst_snapshot.has_value()) {
126  return std::nullopt;
127  }
128  return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode());
129  }
130  src_uvs = maybe_src_uvs.value();
131  }
132 
133  Rect subpass_coverage = coverage;
134  if (entity.GetContents()) {
135  auto coverage_hint = entity.GetContents()->GetCoverageHint();
136 
137  if (coverage_hint.has_value()) {
138  auto maybe_subpass_coverage =
139  subpass_coverage.Intersection(*coverage_hint);
140  if (!maybe_subpass_coverage.has_value()) {
141  return std::nullopt; // Nothing to render.
142  }
143 
144  subpass_coverage = *maybe_subpass_coverage;
145  }
146  }
147 
148  //----------------------------------------------------------------------------
149  /// Render to texture.
150  ///
151 
152  ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
153  RenderPass& pass) {
154  auto& host_buffer = renderer.GetTransientsBuffer();
155 
156  auto size = pass.GetRenderTargetSize();
157 
158  std::array<typename VS::PerVertexData, 4> vertices = {
159  typename VS::PerVertexData{Point(0, 0), dst_uvs[0], src_uvs[0]},
160  typename VS::PerVertexData{Point(size.width, 0), dst_uvs[1],
161  src_uvs[1]},
162  typename VS::PerVertexData{Point(0, size.height), dst_uvs[2],
163  src_uvs[2]},
164  typename VS::PerVertexData{Point(size.width, size.height), dst_uvs[3],
165  src_uvs[3]},
166  };
167  auto vtx_buffer =
168  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer());
169 
170  auto options = OptionsFromPass(pass);
171  options.primitive_type = PrimitiveType::kTriangleStrip;
172  options.blend_mode = BlendMode::kSource;
173  std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline =
174  std::invoke(pipeline_proc, renderer, options);
175 
176 #ifdef IMPELLER_DEBUG
177  pass.SetCommandLabel(
178  SPrintF("Advanced Blend Filter (%s)", BlendModeToString(blend_mode)));
179 #endif // IMPELLER_DEBUG
180  pass.SetVertexBuffer(std::move(vtx_buffer));
181  pass.SetPipeline(pipeline);
182 
183  typename FS::BlendInfo blend_info;
184  typename VS::FrameInfo frame_info;
185 
186  auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
188  dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
189  dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
190  }
191  const std::unique_ptr<const Sampler>& dst_sampler =
192  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
193  dst_sampler_descriptor);
194  FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
195  frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
196  blend_info.dst_input_alpha =
198  ? dst_snapshot->opacity
199  : 1.0;
200 
201  if (foreground_color.has_value()) {
202  blend_info.color_factor = 1;
203  blend_info.color = foreground_color.value();
204  // This texture will not be sampled from due to the color factor. But
205  // this is present so that validation doesn't trip on a missing
206  // binding.
207  FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
208  } else {
209  auto src_sampler_descriptor = src_snapshot->sampler_descriptor;
211  src_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
212  src_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
213  }
214  const std::unique_ptr<const Sampler>& src_sampler =
215  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
216  src_sampler_descriptor);
217  blend_info.color_factor = 0;
218  blend_info.src_input_alpha = src_snapshot->opacity;
219  FS::BindTextureSamplerSrc(pass, src_snapshot->texture, src_sampler);
220  frame_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale();
221  }
222  auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
223  FS::BindBlendInfo(pass, blend_uniform);
224 
225  frame_info.mvp = pass.GetOrthographicTransform() *
227  subpass_coverage.GetOrigin());
228 
229  auto uniform_view = host_buffer.EmplaceUniform(frame_info);
230  VS::BindFrameInfo(pass, uniform_view);
231 
232  return pass.Draw().ok();
233  };
234 
235  std::shared_ptr<CommandBuffer> command_buffer =
236  renderer.GetContext()->CreateCommandBuffer();
237  if (!command_buffer) {
238  return std::nullopt;
239  }
240  fml::StatusOr<RenderTarget> render_target = renderer.MakeSubpass(
241  "Advanced Blend Filter", ISize(subpass_coverage.GetSize()),
242  command_buffer, callback);
243  if (!render_target.ok()) {
244  return std::nullopt;
245  }
246  if (!renderer.GetContext()
247  ->GetCommandQueue()
248  ->Submit(/*buffers=*/{std::move(command_buffer)})
249  .ok()) {
250  return std::nullopt;
251  }
252 
253  return Entity::FromSnapshot(
254  Snapshot{
255  .texture = render_target.value().GetRenderTargetTexture(),
256  .transform = Matrix::MakeTranslation(subpass_coverage.GetOrigin()),
257  // Since we absorbed the transform of the inputs and used the
258  // respective snapshot sampling modes when blending, pass on
259  // the default NN clamp sampler.
260  .sampler_descriptor = {},
261  .opacity = (absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
262  ? 1.0f
263  : dst_snapshot->opacity) *
264  alpha.value_or(1.0)},
265  entity.GetBlendMode());
266 }
267 
268 std::optional<Entity> BlendFilterContents::CreateForegroundAdvancedBlend(
269  const std::shared_ptr<FilterInput>& input,
270  const ContentContext& renderer,
271  const Entity& entity,
272  const Rect& coverage,
273  Color foreground_color,
274  BlendMode blend_mode,
275  std::optional<Scalar> alpha,
276  ColorFilterContents::AbsorbOpacity absorb_opacity) const {
277  auto dst_snapshot =
278  input->GetSnapshot("ForegroundAdvancedBlend", renderer, entity);
279  if (!dst_snapshot.has_value()) {
280  return std::nullopt;
281  }
282 
283  RenderProc render_proc = [foreground_color, dst_snapshot, blend_mode, alpha,
284  absorb_opacity](const ContentContext& renderer,
285  const Entity& entity,
286  RenderPass& pass) -> bool {
289 
290  auto& host_buffer = renderer.GetTransientsBuffer();
291  auto size = dst_snapshot->texture->GetSize();
292 
293  std::array<VS::PerVertexData, 4> vertices = {
294  VS::PerVertexData{{0, 0}, {0, 0}, {0, 0}},
295  VS::PerVertexData{Point(size.width, 0), {1, 0}, {1, 0}},
296  VS::PerVertexData{Point(0, size.height), {0, 1}, {0, 1}},
297  VS::PerVertexData{Point(size.width, size.height), {1, 1}, {1, 1}},
298  };
299  auto vtx_buffer =
300  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer());
301 
302 #ifdef IMPELLER_DEBUG
303  pass.SetCommandLabel(SPrintF("Foreground Advanced Blend Filter (%s)",
304  BlendModeToString(blend_mode)));
305 #endif // IMPELLER_DEBUG
306  pass.SetVertexBuffer(std::move(vtx_buffer));
307  auto options = OptionsFromPassAndEntity(pass, entity);
308  options.primitive_type = PrimitiveType::kTriangleStrip;
309 
310  switch (blend_mode) {
311  case BlendMode::kScreen:
312  pass.SetPipeline(renderer.GetBlendScreenPipeline(options));
313  break;
314  case BlendMode::kOverlay:
315  pass.SetPipeline(renderer.GetBlendOverlayPipeline(options));
316  break;
317  case BlendMode::kDarken:
318  pass.SetPipeline(renderer.GetBlendDarkenPipeline(options));
319  break;
320  case BlendMode::kLighten:
321  pass.SetPipeline(renderer.GetBlendLightenPipeline(options));
322  break;
324  pass.SetPipeline(renderer.GetBlendColorDodgePipeline(options));
325  break;
327  pass.SetPipeline(renderer.GetBlendColorBurnPipeline(options));
328  break;
330  pass.SetPipeline(renderer.GetBlendHardLightPipeline(options));
331  break;
333  pass.SetPipeline(renderer.GetBlendSoftLightPipeline(options));
334  break;
336  pass.SetPipeline(renderer.GetBlendDifferencePipeline(options));
337  break;
339  pass.SetPipeline(renderer.GetBlendExclusionPipeline(options));
340  break;
342  pass.SetPipeline(renderer.GetBlendMultiplyPipeline(options));
343  break;
344  case BlendMode::kHue:
345  pass.SetPipeline(renderer.GetBlendHuePipeline(options));
346  break;
348  pass.SetPipeline(renderer.GetBlendSaturationPipeline(options));
349  break;
350  case BlendMode::kColor:
351  pass.SetPipeline(renderer.GetBlendColorPipeline(options));
352  break;
354  pass.SetPipeline(renderer.GetBlendLuminosityPipeline(options));
355  break;
356  default:
357  return false;
358  }
359 
360  FS::BlendInfo blend_info;
361  VS::FrameInfo frame_info;
362 
363  auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
364  if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
365  dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
366  dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
367  }
368  const std::unique_ptr<const Sampler>& dst_sampler =
369  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
370  dst_sampler_descriptor);
371  FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
372  frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
373 
374  frame_info.mvp = Entity::GetShaderTransform(
375  entity.GetShaderClipDepth(), pass,
376  entity.GetTransform() * dst_snapshot->transform);
377 
378  blend_info.dst_input_alpha =
380  ? dst_snapshot->opacity * alpha.value_or(1.0)
381  : 1.0;
382 
383  blend_info.color_factor = 1;
384  blend_info.color = foreground_color;
385  // This texture will not be sampled from due to the color factor. But
386  // this is present so that validation doesn't trip on a missing
387  // binding.
388  FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
389 
390  auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
391  FS::BindBlendInfo(pass, blend_uniform);
392 
393  auto uniform_view = host_buffer.EmplaceUniform(frame_info);
394  VS::BindFrameInfo(pass, uniform_view);
395 
396  return pass.Draw().ok();
397  };
398  CoverageProc coverage_proc =
399  [coverage](const Entity& entity) -> std::optional<Rect> {
400  return coverage.TransformBounds(entity.GetTransform());
401  };
402 
403  auto contents = AnonymousContents::Make(render_proc, coverage_proc);
404 
405  Entity sub_entity;
406  sub_entity.SetContents(std::move(contents));
407  sub_entity.SetBlendMode(entity.GetBlendMode());
408 
409  return sub_entity;
410 }
411 
412 std::optional<Entity> BlendFilterContents::CreateForegroundPorterDuffBlend(
413  const std::shared_ptr<FilterInput>& input,
414  const ContentContext& renderer,
415  const Entity& entity,
416  const Rect& coverage,
417  Color foreground_color,
418  BlendMode blend_mode,
419  std::optional<Scalar> alpha,
420  ColorFilterContents::AbsorbOpacity absorb_opacity) const {
421  if (blend_mode == BlendMode::kClear) {
422  return std::nullopt;
423  }
424 
425  auto dst_snapshot =
426  input->GetSnapshot("ForegroundPorterDuffBlend", renderer, entity);
427  if (!dst_snapshot.has_value()) {
428  return std::nullopt;
429  }
430 
431  if (blend_mode == BlendMode::kDestination) {
432  return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode());
433  }
434 
435  RenderProc render_proc = [foreground_color, dst_snapshot, blend_mode,
436  absorb_opacity, alpha](
437  const ContentContext& renderer,
438  const Entity& entity, RenderPass& pass) -> bool {
441 
442  auto& host_buffer = renderer.GetTransientsBuffer();
443  auto size = dst_snapshot->texture->GetSize();
444  auto color = foreground_color.Premultiply();
445 
446  std::array<VS::PerVertexData, 4> vertices = {
447  VS::PerVertexData{{0, 0}, {0, 0}, color},
448  VS::PerVertexData{Point(size.width, 0), {1, 0}, color},
449  VS::PerVertexData{Point(0, size.height), {0, 1}, color},
450  VS::PerVertexData{Point(size.width, size.height), {1, 1}, color},
451  };
452  auto vtx_buffer =
453  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer());
454 
455 #ifdef IMPELLER_DEBUG
456  pass.SetCommandLabel(SPrintF("Foreground PorterDuff Blend Filter (%s)",
457  BlendModeToString(blend_mode)));
458 #endif // IMPELLER_DEBUG
459  pass.SetVertexBuffer(std::move(vtx_buffer));
460  auto options = OptionsFromPassAndEntity(pass, entity);
461  options.primitive_type = PrimitiveType::kTriangleStrip;
462  pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
463 
464  FS::FragInfo frag_info;
465  VS::FrameInfo frame_info;
466 
467  frame_info.mvp = Entity::GetShaderTransform(
468  entity.GetShaderClipDepth(), pass,
469  entity.GetTransform() * dst_snapshot->transform);
470 
471  auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
472  if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
473  dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
474  dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
475  }
476  const std::unique_ptr<const Sampler>& dst_sampler =
477  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
478  dst_sampler_descriptor);
479  FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
480  frame_info.texture_sampler_y_coord_scale =
481  dst_snapshot->texture->GetYCoordScale();
482 
483  frag_info.input_alpha =
485  ? dst_snapshot->opacity * alpha.value_or(1.0)
486  : 1.0;
487  frag_info.output_alpha = 1.0;
488 
489  auto blend_coefficients =
490  kPorterDuffCoefficients[static_cast<int>(blend_mode)];
491  frag_info.src_coeff = blend_coefficients[0];
492  frag_info.src_coeff_dst_alpha = blend_coefficients[1];
493  frag_info.dst_coeff = blend_coefficients[2];
494  frag_info.dst_coeff_src_alpha = blend_coefficients[3];
495  frag_info.dst_coeff_src_color = blend_coefficients[4];
496 
497  FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
498  VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
499 
500  return pass.Draw().ok();
501  };
502 
503  CoverageProc coverage_proc =
504  [coverage](const Entity& entity) -> std::optional<Rect> {
505  return coverage.TransformBounds(entity.GetTransform());
506  };
507 
508  auto contents = AnonymousContents::Make(render_proc, coverage_proc);
509 
510  Entity sub_entity;
511  sub_entity.SetContents(std::move(contents));
512  sub_entity.SetBlendMode(entity.GetBlendMode());
513 
514  return sub_entity;
515 }
516 
517 static std::optional<Entity> PipelineBlend(
518  const FilterInput::Vector& inputs,
519  const ContentContext& renderer,
520  const Entity& entity,
521  const Rect& coverage,
522  BlendMode blend_mode,
523  std::optional<Color> foreground_color,
524  ColorFilterContents::AbsorbOpacity absorb_opacity,
525  std::optional<Scalar> alpha) {
528 
529  auto dst_snapshot =
530  inputs[0]->GetSnapshot("PipelineBlend(Dst)", renderer, entity);
531  if (!dst_snapshot.has_value()) {
532  return std::nullopt; // Nothing to render.
533  }
534 
535  Rect subpass_coverage = coverage;
536  if (entity.GetContents()) {
537  auto coverage_hint = entity.GetContents()->GetCoverageHint();
538 
539  if (coverage_hint.has_value()) {
540  auto maybe_subpass_coverage =
541  subpass_coverage.Intersection(*coverage_hint);
542  if (!maybe_subpass_coverage.has_value()) {
543  return std::nullopt; // Nothing to render.
544  }
545 
546  subpass_coverage = *maybe_subpass_coverage;
547  }
548  }
549 
550  ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
551  RenderPass& pass) {
552  auto& host_buffer = renderer.GetTransientsBuffer();
553 
554 #ifdef IMPELLER_DEBUG
555  pass.SetCommandLabel(
556  SPrintF("Pipeline Blend Filter (%s)", BlendModeToString(blend_mode)));
557 #endif // IMPELLER_DEBUG
558  auto options = OptionsFromPass(pass);
559  options.primitive_type = PrimitiveType::kTriangleStrip;
560 
561  auto add_blend_command = [&](std::optional<Snapshot> input) {
562  if (!input.has_value()) {
563  return false;
564  }
565  auto input_coverage = input->GetCoverage();
566  if (!input_coverage.has_value()) {
567  return false;
568  }
569 
570  const std::unique_ptr<const Sampler>& sampler =
571  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
572  input->sampler_descriptor);
573  FS::BindTextureSampler(pass, input->texture, sampler);
574 
575  auto size = input->texture->GetSize();
576  std::array<VS::PerVertexData, 4> vertices = {
577  VS::PerVertexData{Point(0, 0), Point(0, 0)},
578  VS::PerVertexData{Point(size.width, 0), Point(1, 0)},
579  VS::PerVertexData{Point(0, size.height), Point(0, 1)},
580  VS::PerVertexData{Point(size.width, size.height), Point(1, 1)},
581  };
582  pass.SetVertexBuffer(
583  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer()));
584 
585  VS::FrameInfo frame_info;
586  frame_info.mvp = pass.GetOrthographicTransform() *
587  Matrix::MakeTranslation(-subpass_coverage.GetOrigin()) *
588  input->transform;
589  frame_info.texture_sampler_y_coord_scale =
590  input->texture->GetYCoordScale();
591 
592  FS::FragInfo frag_info;
593  frag_info.alpha =
595  ? input->opacity
596  : 1.0;
597  FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
598  VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
599 
600  return pass.Draw().ok();
601  };
602 
603  // Draw the first texture using kSource.
604  options.blend_mode = BlendMode::kSource;
605  pass.SetPipeline(renderer.GetTexturePipeline(options));
606  if (!add_blend_command(dst_snapshot)) {
607  return true;
608  }
609 
610  // Write subsequent textures using the selected blend mode.
611 
612  if (inputs.size() >= 2) {
613  options.blend_mode = blend_mode;
614  pass.SetPipeline(renderer.GetTexturePipeline(options));
615 
616  for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
617  texture_i++) {
618  auto src_input = texture_i->get()->GetSnapshot("PipelineBlend(Src)",
619  renderer, entity);
620  if (!add_blend_command(src_input)) {
621  return true;
622  }
623  }
624  }
625 
626  // If a foreground color is set, blend it in.
627 
628  if (foreground_color.has_value()) {
629  auto contents = std::make_shared<SolidColorContents>();
630  RectGeometry geom(Rect::MakeSize(pass.GetRenderTargetSize()));
631  contents->SetGeometry(&geom);
632  contents->SetColor(foreground_color.value());
633 
634  Entity foreground_entity;
635  foreground_entity.SetBlendMode(blend_mode);
636  foreground_entity.SetContents(contents);
637  if (!foreground_entity.Render(renderer, pass)) {
638  return false;
639  }
640  }
641 
642  return true;
643  };
644 
645  std::shared_ptr<CommandBuffer> command_buffer =
646  renderer.GetContext()->CreateCommandBuffer();
647  if (!command_buffer) {
648  return std::nullopt;
649  }
650 
651  fml::StatusOr<RenderTarget> render_target = renderer.MakeSubpass(
652  "Pipeline Blend Filter", ISize(subpass_coverage.GetSize()),
653  command_buffer, callback);
654 
655  if (!render_target.ok()) {
656  return std::nullopt;
657  }
658 
659  if (!renderer.GetContext()
660  ->GetCommandQueue()
661  ->Submit(/*buffers=*/{std::move(command_buffer)})
662  .ok()) {
663  return std::nullopt;
664  }
665 
666  return Entity::FromSnapshot(
667  Snapshot{
668  .texture = render_target.value().GetRenderTargetTexture(),
669  .transform = Matrix::MakeTranslation(subpass_coverage.GetOrigin()),
670  // Since we absorbed the transform of the inputs and used the
671  // respective snapshot sampling modes when blending, pass on
672  // the default NN clamp sampler.
673  .sampler_descriptor = {},
674  .opacity = (absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
675  ? 1.0f
676  : dst_snapshot->opacity) *
677  alpha.value_or(1.0)},
678  entity.GetBlendMode());
679 }
680 
681 std::optional<Entity> BlendFilterContents::CreateFramebufferAdvancedBlend(
682  const FilterInput::Vector& inputs,
683  const ContentContext& renderer,
684  const Entity& entity,
685  const Rect& coverage,
686  std::optional<Color> foreground_color,
687  BlendMode blend_mode,
688  std::optional<Scalar> alpha,
689  ColorFilterContents::AbsorbOpacity absorb_opacity) const {
690  // This works with either 2 contents or 1 contents and a foreground color.
691  FML_DCHECK(inputs.size() == 2u ||
692  (inputs.size() == 1u && foreground_color.has_value()));
693 
694  auto dst_snapshot =
695  inputs[0]->GetSnapshot("ForegroundAdvancedBlend", renderer, entity);
696  if (!dst_snapshot.has_value()) {
697  return std::nullopt;
698  }
699 
700  std::shared_ptr<Texture> foreground_texture;
701 
702  ContentContext::SubpassCallback subpass_callback = [&](const ContentContext&
703  renderer,
704  RenderPass& pass) {
705  // First, we create a new render pass and populate it with the contents
706  // of the first (dst) input.
707  HostBuffer& host_buffer = renderer.GetTransientsBuffer();
708 
709  {
710  using FS = TextureFillFragmentShader;
711  using VS = TextureFillVertexShader;
712 
713  pass.SetCommandLabel("Framebuffer Advanced Blend");
714  auto pipeline_options = OptionsFromPass(pass);
715  pipeline_options.primitive_type = PrimitiveType::kTriangleStrip;
716  pass.SetPipeline(renderer.GetTexturePipeline(pipeline_options));
717 
718  VS::FrameInfo frame_info;
719  frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
720  frame_info.texture_sampler_y_coord_scale = 1.0;
721 
722  FS::FragInfo frag_info;
723  frag_info.alpha = 1.0;
724 
725  std::array<VS::PerVertexData, 4> vertices = {
726  VS::PerVertexData{{0, 0}, {0, 0}},
727  VS::PerVertexData{Point(1, 0), {1, 0}},
728  VS::PerVertexData{Point(0, 1), {0, 1}},
729  VS::PerVertexData{Point(1, 1), {1, 1}},
730  };
731  pass.SetVertexBuffer(
732  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer()));
733 
734  VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
735  FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
736  FS::BindTextureSampler(
737  pass, dst_snapshot->texture,
738  renderer.GetContext()->GetSamplerLibrary()->GetSampler({}));
739 
740  if (!pass.Draw().ok()) {
741  return false;
742  }
743  }
744 
745  {
748 
749  // Next, we render the second contents to a snapshot, or create a 1x1
750  // texture for the foreground color.
751  std::shared_ptr<Texture> src_texture;
752  if (foreground_color.has_value()) {
753  src_texture = foreground_texture;
754  } else {
755  auto src_snapshot =
756  inputs[0]->GetSnapshot("ForegroundAdvancedBlend", renderer, entity);
757  if (!src_snapshot.has_value()) {
758  return false;
759  }
760  // This doesn't really handle the case where the transforms are wildly
761  // different, but we only need to support blending two contents together
762  // in limited circumstances (mask blur).
763  src_texture = src_snapshot->texture;
764  }
765 
766  std::array<VS::PerVertexData, 4> vertices = {
767  VS::PerVertexData{Point(0, 0), Point(0, 0)},
768  VS::PerVertexData{Point(1, 0), Point(1, 0)},
769  VS::PerVertexData{Point(0, 1), Point(0, 1)},
770  VS::PerVertexData{Point(1, 1), Point(1, 1)},
771  };
772 
773  auto options = OptionsFromPass(pass);
774  options.blend_mode = BlendMode::kSource;
775  options.primitive_type = PrimitiveType::kTriangleStrip;
776 
777  pass.SetCommandLabel("Framebuffer Advanced Blend Filter");
778  pass.SetVertexBuffer(
779  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer()));
780 
781  switch (blend_mode) {
782  case BlendMode::kScreen:
783  pass.SetPipeline(renderer.GetFramebufferBlendScreenPipeline(options));
784  break;
785  case BlendMode::kOverlay:
786  pass.SetPipeline(
787  renderer.GetFramebufferBlendOverlayPipeline(options));
788  break;
789  case BlendMode::kDarken:
790  pass.SetPipeline(renderer.GetFramebufferBlendDarkenPipeline(options));
791  break;
792  case BlendMode::kLighten:
793  pass.SetPipeline(
794  renderer.GetFramebufferBlendLightenPipeline(options));
795  break;
797  pass.SetPipeline(
798  renderer.GetFramebufferBlendColorDodgePipeline(options));
799  break;
801  pass.SetPipeline(
802  renderer.GetFramebufferBlendColorBurnPipeline(options));
803  break;
805  pass.SetPipeline(
806  renderer.GetFramebufferBlendHardLightPipeline(options));
807  break;
809  pass.SetPipeline(
810  renderer.GetFramebufferBlendSoftLightPipeline(options));
811  break;
813  pass.SetPipeline(
814  renderer.GetFramebufferBlendDifferencePipeline(options));
815  break;
817  pass.SetPipeline(
818  renderer.GetFramebufferBlendExclusionPipeline(options));
819  break;
821  pass.SetPipeline(
822  renderer.GetFramebufferBlendMultiplyPipeline(options));
823  break;
824  case BlendMode::kHue:
825  pass.SetPipeline(renderer.GetFramebufferBlendHuePipeline(options));
826  break;
828  pass.SetPipeline(
829  renderer.GetFramebufferBlendSaturationPipeline(options));
830  break;
831  case BlendMode::kColor:
832  pass.SetPipeline(renderer.GetFramebufferBlendColorPipeline(options));
833  break;
835  pass.SetPipeline(
836  renderer.GetFramebufferBlendLuminosityPipeline(options));
837  break;
838  default:
839  return false;
840  }
841 
842  VS::FrameInfo frame_info;
843  FS::FragInfo frag_info;
844 
845  auto src_sampler_descriptor = SamplerDescriptor{};
846  if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
847  src_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
848  src_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
849  }
850  const std::unique_ptr<const Sampler>& src_sampler =
851  renderer.GetContext()->GetSamplerLibrary()->GetSampler(
852  src_sampler_descriptor);
853  FS::BindTextureSamplerSrc(pass, src_texture, src_sampler);
854 
855  frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
856  frame_info.src_y_coord_scale = src_texture->GetYCoordScale();
857  VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
858 
859  frag_info.src_input_alpha = 1.0;
860  FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
861 
862  return pass.Draw().ok();
863  }
864  };
865 
866  std::shared_ptr<CommandBuffer> cmd_buffer =
867  renderer.GetContext()->CreateCommandBuffer();
868 
869  // Generate a 1x1 texture to implement foreground color blending.
870  if (foreground_color.has_value()) {
871  TextureDescriptor desc;
872  desc.size = {1, 1};
873  desc.format = PixelFormat::kR8G8B8A8UNormInt;
874  desc.storage_mode = StorageMode::kDevicePrivate;
875  foreground_texture =
876  renderer.GetContext()->GetResourceAllocator()->CreateTexture(desc);
877  if (!foreground_texture) {
878  return std::nullopt;
879  }
880  auto blit_pass = cmd_buffer->CreateBlitPass();
881  auto buffer_view = renderer.GetTransientsBuffer().Emplace(
882  foreground_color->Premultiply().ToR8G8B8A8(), /*alignment=*/4);
883 
884  blit_pass->AddCopy(std::move(buffer_view), foreground_texture);
885  if (!blit_pass->EncodeCommands(
886  renderer.GetContext()->GetResourceAllocator())) {
887  return std::nullopt;
888  }
889  }
890 
891  auto render_target =
892  renderer.MakeSubpass("FramebufferBlend", dst_snapshot->texture->GetSize(),
893  cmd_buffer, subpass_callback);
894 
895  if (!render_target.ok()) {
896  return std::nullopt;
897  }
898 
899  if (!renderer.GetContext()
900  ->GetCommandQueue()
901  ->Submit(/*buffers=*/{std::move(cmd_buffer)})
902  .ok()) {
903  return std::nullopt;
904  }
905 
906  return Entity::FromSnapshot(
907  Snapshot{
908  .texture = render_target.value().GetRenderTargetTexture(),
909  .transform = dst_snapshot->transform,
910  // Since we absorbed the transform of the inputs and used the
911  // respective snapshot sampling modes when blending, pass on
912  // the default NN clamp sampler.
913  .sampler_descriptor = {},
914  .opacity = (absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
915  ? 1.0f
916  : dst_snapshot->opacity) *
917  alpha.value_or(1.0)},
918  entity.GetBlendMode());
919 }
920 
921 #define BLEND_CASE(mode) \
922  case BlendMode::k##mode: \
923  advanced_blend_proc_ = \
924  [](const FilterInput::Vector& inputs, const ContentContext& renderer, \
925  const Entity& entity, const Rect& coverage, BlendMode blend_mode, \
926  std::optional<Color> fg_color, \
927  ColorFilterContents::AbsorbOpacity absorb_opacity, \
928  std::optional<Scalar> alpha) { \
929  PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \
930  return AdvancedBlend<Blend##mode##Pipeline>( \
931  inputs, renderer, entity, coverage, blend_mode, fg_color, \
932  absorb_opacity, p, alpha); \
933  }; \
934  break;
935 
937  if (blend_mode > Entity::kLastAdvancedBlendMode) {
938  VALIDATION_LOG << "Invalid blend mode " << static_cast<int>(blend_mode)
939  << " assigned to BlendFilterContents.";
940  }
941 
942  blend_mode_ = blend_mode;
943 
944  if (blend_mode > Entity::kLastPipelineBlendMode) {
945  switch (blend_mode) {
946  BLEND_CASE(Screen)
947  BLEND_CASE(Overlay)
948  BLEND_CASE(Darken)
949  BLEND_CASE(Lighten)
950  BLEND_CASE(ColorDodge)
951  BLEND_CASE(ColorBurn)
952  BLEND_CASE(HardLight)
953  BLEND_CASE(SoftLight)
954  BLEND_CASE(Difference)
955  BLEND_CASE(Exclusion)
956  BLEND_CASE(Multiply)
957  BLEND_CASE(Hue)
961  default:
962  FML_UNREACHABLE();
963  }
964  }
965 }
966 
967 void BlendFilterContents::SetForegroundColor(std::optional<Color> color) {
968  foreground_color_ = color;
969 }
970 
971 std::optional<Entity> BlendFilterContents::RenderFilter(
972  const FilterInput::Vector& inputs,
973  const ContentContext& renderer,
974  const Entity& entity,
975  const Matrix& effect_transform,
976  const Rect& coverage,
977  const std::optional<Rect>& coverage_hint) const {
978  if (inputs.empty()) {
979  return std::nullopt;
980  }
981 
982  if (inputs.size() == 1 && !foreground_color_.has_value()) {
983  // Nothing to blend.
984  return PipelineBlend(inputs, renderer, entity, coverage, BlendMode::kSource,
985  std::nullopt, GetAbsorbOpacity(), GetAlpha());
986  }
987 
988  if (blend_mode_ <= Entity::kLastPipelineBlendMode) {
989  if (inputs.size() == 1 && foreground_color_.has_value() &&
991  return CreateForegroundPorterDuffBlend(
992  inputs[0], renderer, entity, coverage, foreground_color_.value(),
993  blend_mode_, GetAlpha(), GetAbsorbOpacity());
994  }
995  return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_,
996  foreground_color_, GetAbsorbOpacity(), GetAlpha());
997  }
998 
999  if (blend_mode_ <= Entity::kLastAdvancedBlendMode) {
1001  return CreateFramebufferAdvancedBlend(inputs, renderer, entity, coverage,
1002  foreground_color_, blend_mode_,
1003  GetAlpha(), GetAbsorbOpacity());
1004  }
1005  if (inputs.size() == 1 && foreground_color_.has_value() &&
1007  return CreateForegroundAdvancedBlend(
1008  inputs[0], renderer, entity, coverage, foreground_color_.value(),
1009  blend_mode_, GetAlpha(), GetAbsorbOpacity());
1010  }
1011  return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode_,
1012  foreground_color_, GetAbsorbOpacity(),
1013  GetAlpha());
1014  }
1015 
1016  FML_UNREACHABLE();
1017 }
1018 
1019 } // namespace impeller
impeller::ContentContext::GetTexturePipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetTexturePipeline(ContentContextOptions opts) const
Definition: content_context.h:438
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::RenderPipelineHandle::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:107
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:51
impeller::OptionsFromPass
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:19
BLEND_CASE
#define BLEND_CASE(mode)
Definition: blend_filter_contents.cc:921
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
impeller::BlendModeToString
const char * BlendModeToString(BlendMode blend_mode)
Definition: color.cc:47
impeller::BlendMode::kDestinationATop
@ kDestinationATop
contents.h
impeller::BlendFilterContents::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: blend_filter_contents.cc:936
impeller::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:108
impeller::BlendFilterContents::SetForegroundColor
void SetForegroundColor(std::optional< Color > color)
Sets a source color which is blended after all of the inputs have been blended.
Definition: blend_filter_contents.cc:967
vertex_buffer.h
entity.h
impeller::BlendMode
BlendMode
Definition: color.h:58
solid_color_contents.h
impeller::Color
Definition: color.h:123
impeller::BlendMode::kLuminosity
@ kLuminosity
impeller::BlendMode::kSource
@ kSource
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::BlendMode::kColorDodge
@ kColorDodge
impeller::BlendMode::kDestination
@ kDestination
texture_descriptor.h
impeller::BlendMode::kDarken
@ kDarken
impeller::TRect::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:522
impeller::InvertPorterDuffBlend
std::optional< BlendMode > InvertPorterDuffBlend(BlendMode blend_mode)
Definition: blend_filter_contents.cc:33
impeller::BlendMode::kColor
@ kColor
formats.h
impeller::BlendMode::kDestinationOver
@ kDestinationOver
impeller::BlendMode::kPlus
@ kPlus
impeller::BlendMode::kOverlay
@ kOverlay
rect_geometry.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:128
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:314
impeller::BlendMode::kModulate
@ kModulate
impeller::AdvancedBlend
static std::optional< Entity > AdvancedBlend(const FilterInput::Vector &inputs, const ContentContext &renderer, const Entity &entity, const Rect &coverage, BlendMode blend_mode, std::optional< Color > foreground_color, ColorFilterContents::AbsorbOpacity absorb_opacity, PipelineProc pipeline_proc, std::optional< Scalar > alpha)
Definition: blend_filter_contents.cc:78
impeller::BlendMode::kSourceOut
@ kSourceOut
impeller::BlendMode::kSaturation
@ kSaturation
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:83
impeller::BlendMode::kDifference
@ kDifference
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:16
impeller::Entity
Definition: entity.h:20
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
impeller::BlendMode::kLighten
@ kLighten
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::BlendMode::kSoftLight
@ kSoftLight
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
render_pass.h
impeller::BlendMode::kColorBurn
@ kColorBurn
impeller::Entity::Render
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
Definition: entity.cc:156
impeller::BlendMode::kHardLight
@ kHardLight
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:213
impeller::Entity::FromSnapshot
static Entity FromSnapshot(const Snapshot &snapshot, BlendMode blend_mode=BlendMode::kSourceOver)
Create an entity that can be used to render a given snapshot.
Definition: entity.cc:21
impeller::BlendMode::kClear
@ kClear
impeller::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &host_buffer)
Create an index-less vertex buffer from a fixed size array.
Definition: vertex_buffer_builder.h:24
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:550
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::Entity::kLastAdvancedBlendMode
static constexpr BlendMode kLastAdvancedBlendMode
Definition: entity.h:23
impeller::ColorFilterContents::GetAbsorbOpacity
AbsorbOpacity GetAbsorbOpacity() const
Definition: color_filter_contents.cc:89
impeller::ContentContext::MakeSubpass
fml::StatusOr< RenderTarget > MakeSubpass(std::string_view label, ISize texture_size, const std::shared_ptr< CommandBuffer > &command_buffer, const SubpassCallback &subpass_callback, bool msaa_enabled=true, bool depth_stencil_enabled=false, int32_t mip_count=1) const
Creates a new texture of size texture_size and calls subpass_callback with a RenderPass for drawing t...
Definition: content_context.cc:478
impeller::Snapshot
Represents a texture and its intended draw transform/sampler configuration.
Definition: snapshot.h:24
impeller::RenderPipelineHandle::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:106
impeller::RectGeometry
Definition: rect_geometry.h:12
impeller::kPorterDuffCoefficients
constexpr std::array< std::array< Scalar, 5 >, 15 > kPorterDuffCoefficients
Definition: blend_filter_contents.h:15
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:87
impeller::PipelineProc
std::shared_ptr< Pipeline< PipelineDescriptor > >(ContentContext::*)(ContentContextOptions) const PipelineProc
Definition: blend_filter_contents.cc:75
filter_input.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:776
impeller::Luminosity
static constexpr Scalar Luminosity(Vector3 color)
Definition: color.cc:63
strings.h
color_filter_contents.h
impeller::BlendFilterContents::~BlendFilterContents
~BlendFilterContents() override
anonymous_contents.h
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:112
impeller::ContentContext::SubpassCallback
std::function< bool(const ContentContext &, RenderPass &)> SubpassCallback
Definition: content_context.h:701
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
sampler_descriptor.h
impeller::BlendMode::kDestinationIn
@ kDestinationIn
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::BlendMode::kExclusion
@ kExclusion
content_context.h
impeller::BlendMode::kDestinationOut
@ kDestinationOut
impeller::Contents::RenderProc
std::function< bool(const ContentContext &renderer, const Entity &entity, RenderPass &pass)> RenderProc
Definition: contents.h:57
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:321
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:554
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
snapshot.h
impeller::PipelineBlend
static std::optional< Entity > PipelineBlend(const FilterInput::Vector &inputs, const ContentContext &renderer, const Entity &entity, const Rect &coverage, BlendMode blend_mode, std::optional< Color > foreground_color, ColorFilterContents::AbsorbOpacity absorb_opacity, std::optional< Scalar > alpha)
Definition: blend_filter_contents.cc:517
impeller::BlendMode::kSourceIn
@ kSourceIn
impeller::BlendMode::kScreen
@ kScreen
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:523
color.h
color
DlColor color
Definition: dl_golden_blur_unittests.cc:24
impeller::BlendMode::kHue
@ kHue
blend_filter_contents.h
impeller::Contents::CoverageProc
std::function< std::optional< Rect >(const Entity &entity)> CoverageProc
Definition: contents.h:58
impeller::Snapshot::texture
std::shared_ptr< Texture > texture
Definition: snapshot.h:25
impeller::ColorFilterContents::AbsorbOpacity::kYes
@ kYes
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::BlendMode::kXor
@ kXor
impeller::ColorFilterContents::GetAlpha
std::optional< Scalar > GetAlpha() const
Definition: color_filter_contents.cc:98
impeller::Capabilities::SupportsDecalSamplerAddressMode
virtual bool SupportsDecalSamplerAddressMode() const =0
Whether the context backend supports SamplerAddressMode::Decal.
impeller::ContentContextOptions
Definition: content_context.h:254
impeller::Capabilities::SupportsFramebufferFetch
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
impeller::ColorFilterContents::AbsorbOpacity
AbsorbOpacity
Definition: color_filter_contents.h:14
impeller
Definition: allocation.cc:12
impeller::BlendMode::kSourceATop
@ kSourceATop
impeller::BlendMode::kMultiply
@ kMultiply
impeller::ContentContext
Definition: content_context.h:366
impeller::BlendFilterContents::BlendFilterContents
BlendFilterContents()
Definition: blend_filter_contents.cc:68
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::AnonymousContents::Make
static std::shared_ptr< Contents > Make(RenderProc render_proc, CoverageProc coverage_proc)
Definition: anonymous_contents.cc:11
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:753
impeller::Saturation
static constexpr Scalar Saturation(Vector3 color)
Definition: color.cc:89
impeller::SamplerAddressMode::kDecal
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...