| 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
5 #include "impeller/entity/contents/filters/blend_filter_contents.h"
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"
14 #include "impeller/core/sampler_descriptor.h"
15 #include "impeller/core/texture_descriptor.h"
16 #include "impeller/core/vertex_buffer.h"
17 #include "impeller/entity/contents/anonymous_contents.h"
18 #include "impeller/entity/contents/content_context.h"
19 #include "impeller/entity/contents/contents.h"
20 #include "impeller/entity/contents/filters/color_filter_contents.h"
21 #include "impeller/entity/contents/filters/inputs/filter_input.h"
22 #include "impeller/entity/contents/solid_color_contents.h"
23 #include "impeller/entity/entity.h"
24 #include "impeller/entity/geometry/rect_geometry.h"
25 #include "impeller/entity/texture_fill.frag.h"
26 #include "impeller/entity/texture_fill.vert.h"
27 #include "impeller/geometry/color.h"
28 #include "impeller/renderer/render_pass.h"
29 #include "impeller/renderer/snapshot.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:
38 return BlendMode::kDestination;
39 case BlendMode::kDestination:
40 return BlendMode::kSource;
41 case BlendMode::kSourceOver:
42 return BlendMode::kDestinationOver;
43 case BlendMode::kDestinationOver:
44 return BlendMode::kSourceOver;
45 case BlendMode::kSourceIn:
46 return BlendMode::kDestinationIn;
47 case BlendMode::kDestinationIn:
48 return BlendMode::kSourceIn;
49 case BlendMode::kSourceOut:
50 return BlendMode::kDestinationOut;
51 case BlendMode::kDestinationOut:
52 return BlendMode::kSourceOut;
53 case BlendMode::kSourceATop:
54 return BlendMode::kDestinationATop;
55 case BlendMode::kDestinationATop:
56 return BlendMode::kSourceATop;
57 case BlendMode::kXor:
58 return BlendMode::kXor;
59 case BlendMode::kPlus:
60 return BlendMode::kPlus;
61 case BlendMode::kModulate:
62 return BlendMode::kModulate;
63 default:
64 return std::nullopt;
65 }
66 }
67
68 BlendFilterContents::BlendFilterContents() {
69 SetBlendMode(BlendMode::kSourceOver);
70 }
71
72 BlendFilterContents::~BlendFilterContents() = default;
73
74 using PipelineProc = std::shared_ptr<Pipeline<PipelineDescriptor>> (
75 ContentContext::*)(ContentContextOptions) const;
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,
85 ColorFilterContents::AbsorbOpacity absorb_opacity,
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;
187 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
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 =
197 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
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;
210 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
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() *
226 Matrix::MakeTranslation(coverage.GetOrigin() -
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 {
287 using VS = BlendScreenPipeline::VertexShader;
288 using FS = BlendScreenPipeline::FragmentShader;
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;
323 case BlendMode::kColorDodge:
324 pass.SetPipeline(renderer.GetBlendColorDodgePipeline(options));
325 break;
326 case BlendMode::kColorBurn:
327 pass.SetPipeline(renderer.GetBlendColorBurnPipeline(options));
328 break;
329 case BlendMode::kHardLight:
330 pass.SetPipeline(renderer.GetBlendHardLightPipeline(options));
331 break;
332 case BlendMode::kSoftLight:
333 pass.SetPipeline(renderer.GetBlendSoftLightPipeline(options));
334 break;
335 case BlendMode::kDifference:
336 pass.SetPipeline(renderer.GetBlendDifferencePipeline(options));
337 break;
338 case BlendMode::kExclusion:
339 pass.SetPipeline(renderer.GetBlendExclusionPipeline(options));
340 break;
341 case BlendMode::kMultiply:
342 pass.SetPipeline(renderer.GetBlendMultiplyPipeline(options));
343 break;
344 case BlendMode::kHue:
345 pass.SetPipeline(renderer.GetBlendHuePipeline(options));
346 break;
347 case BlendMode::kSaturation:
348 pass.SetPipeline(renderer.GetBlendSaturationPipeline(options));
349 break;
350 case BlendMode::kColor:
351 pass.SetPipeline(renderer.GetBlendColorPipeline(options));
352 break;
353 case BlendMode::kLuminosity:
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 =
379 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
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 {
439 using VS = PorterDuffBlendPipeline::VertexShader;
440 using FS = PorterDuffBlendPipeline::FragmentShader;
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 =
484 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
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) {
526 using VS = TexturePipeline::VertexShader;
527 using FS = TexturePipeline::FragmentShader;
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 =
594 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
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 {
746 using VS = FramebufferBlendScreenPipeline::VertexShader;
747 using FS = FramebufferBlendScreenPipeline::FragmentShader;
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;
796 case BlendMode::kColorDodge:
797 pass.SetPipeline(
798 renderer.GetFramebufferBlendColorDodgePipeline(options));
799 break;
800 case BlendMode::kColorBurn:
801 pass.SetPipeline(
802 renderer.GetFramebufferBlendColorBurnPipeline(options));
803 break;
804 case BlendMode::kHardLight:
805 pass.SetPipeline(
806 renderer.GetFramebufferBlendHardLightPipeline(options));
807 break;
808 case BlendMode::kSoftLight:
809 pass.SetPipeline(
810 renderer.GetFramebufferBlendSoftLightPipeline(options));
811 break;
812 case BlendMode::kDifference:
813 pass.SetPipeline(
814 renderer.GetFramebufferBlendDifferencePipeline(options));
815 break;
816 case BlendMode::kExclusion:
817 pass.SetPipeline(
818 renderer.GetFramebufferBlendExclusionPipeline(options));
819 break;
820 case BlendMode::kMultiply:
821 pass.SetPipeline(
822 renderer.GetFramebufferBlendMultiplyPipeline(options));
823 break;
824 case BlendMode::kHue:
825 pass.SetPipeline(renderer.GetFramebufferBlendHuePipeline(options));
826 break;
827 case BlendMode::kSaturation:
828 pass.SetPipeline(
829 renderer.GetFramebufferBlendSaturationPipeline(options));
830 break;
831 case BlendMode::kColor:
832 pass.SetPipeline(renderer.GetFramebufferBlendColorPipeline(options));
833 break;
834 case BlendMode::kLuminosity:
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
936 void BlendFilterContents::SetBlendMode(BlendMode blend_mode) {
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)
958 BLEND_CASE(Saturation)
959 BLEND_CASE(Color)
960 BLEND_CASE(Luminosity)
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() &&
990 GetAbsorbOpacity() == ColorFilterContents::AbsorbOpacity::kYes) {
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) {
1000 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
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() &&
1006 GetAbsorbOpacity() == ColorFilterContents::AbsorbOpacity::kYes) {
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...