| 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 "impeller/base/strings.h"
12 #include "impeller/core/formats.h"
13 #include "impeller/entity/contents/anonymous_contents.h"
14 #include "impeller/entity/contents/content_context.h"
15 #include "impeller/entity/contents/contents.h"
16 #include "impeller/entity/contents/filters/color_filter_contents.h"
17 #include "impeller/entity/contents/filters/inputs/filter_input.h"
18 #include "impeller/entity/contents/solid_color_contents.h"
19 #include "impeller/entity/entity.h"
20 #include "impeller/geometry/color.h"
21 #include "impeller/renderer/render_pass.h"
22 #include "impeller/renderer/snapshot.h"
23
24 namespace impeller {
25
26 std::optional<BlendMode> InvertPorterDuffBlend(BlendMode blend_mode) {
27 switch (blend_mode) {
28 case BlendMode::kClear:
29 return BlendMode::kClear;
30 case BlendMode::kSource:
31 return BlendMode::kDestination;
32 case BlendMode::kDestination:
33 return BlendMode::kSource;
34 case BlendMode::kSourceOver:
35 return BlendMode::kDestinationOver;
36 case BlendMode::kDestinationOver:
37 return BlendMode::kSourceOver;
38 case BlendMode::kSourceIn:
39 return BlendMode::kDestinationIn;
40 case BlendMode::kDestinationIn:
41 return BlendMode::kSourceIn;
42 case BlendMode::kSourceOut:
43 return BlendMode::kDestinationOut;
44 case BlendMode::kDestinationOut:
45 return BlendMode::kSourceOut;
46 case BlendMode::kSourceATop:
47 return BlendMode::kDestinationATop;
48 case BlendMode::kDestinationATop:
49 return BlendMode::kSourceATop;
50 case BlendMode::kXor:
51 return BlendMode::kXor;
52 case BlendMode::kPlus:
53 return BlendMode::kPlus;
54 case BlendMode::kModulate:
55 return BlendMode::kModulate;
56 default:
57 return std::nullopt;
58 }
59 }
60
61 BlendFilterContents::BlendFilterContents() {
62 SetBlendMode(BlendMode::kSourceOver);
63 }
64
65 BlendFilterContents::~BlendFilterContents() = default;
66
67 using PipelineProc = std::shared_ptr<Pipeline<PipelineDescriptor>> (
68 ContentContext::*)(ContentContextOptions) const;
69
70 template <typename TPipeline>
71 static std::optional<Entity> AdvancedBlend(
72 const FilterInput::Vector& inputs,
73 const ContentContext& renderer,
74 const Entity& entity,
75 const Rect& coverage,
76 BlendMode blend_mode,
77 std::optional<Color> foreground_color,
78 ColorFilterContents::AbsorbOpacity absorb_opacity,
79 PipelineProc pipeline_proc,
80 std::optional<Scalar> alpha) {
81 using VS = typename TPipeline::VertexShader;
82 using FS = typename TPipeline::FragmentShader;
83
84 //----------------------------------------------------------------------------
85 /// Handle inputs.
86 ///
87
88 const size_t total_inputs =
89 inputs.size() + (foreground_color.has_value() ? 1 : 0);
90 if (total_inputs < 2) {
91 return std::nullopt;
92 }
93
94 auto dst_snapshot =
95 inputs[0]->GetSnapshot("AdvancedBlend(Dst)", renderer, entity);
96 if (!dst_snapshot.has_value()) {
97 return std::nullopt;
98 }
99 auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
100 if (!maybe_dst_uvs.has_value()) {
101 return std::nullopt;
102 }
103 auto dst_uvs = maybe_dst_uvs.value();
104
105 std::optional<Snapshot> src_snapshot;
106 std::array<Point, 4> src_uvs;
107 if (!foreground_color.has_value()) {
108 src_snapshot =
109 inputs[1]->GetSnapshot("AdvancedBlend(Src)", renderer, entity);
110 if (!src_snapshot.has_value()) {
111 if (!dst_snapshot.has_value()) {
112 return std::nullopt;
113 }
114 return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(),
115 entity.GetClipDepth());
116 }
117 auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
118 if (!maybe_src_uvs.has_value()) {
119 if (!dst_snapshot.has_value()) {
120 return std::nullopt;
121 }
122 return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(),
123 entity.GetClipDepth());
124 }
125 src_uvs = maybe_src_uvs.value();
126 }
127
128 Rect subpass_coverage = coverage;
129 if (entity.GetContents()) {
130 auto coverage_hint = entity.GetContents()->GetCoverageHint();
131
132 if (coverage_hint.has_value()) {
133 auto maybe_subpass_coverage =
134 subpass_coverage.Intersection(*coverage_hint);
135 if (!maybe_subpass_coverage.has_value()) {
136 return std::nullopt; // Nothing to render.
137 }
138
139 subpass_coverage = *maybe_subpass_coverage;
140 }
141 }
142
143 //----------------------------------------------------------------------------
144 /// Render to texture.
145 ///
146
147 ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
148 RenderPass& pass) {
149 auto& host_buffer = pass.GetTransientsBuffer();
150
151 auto size = pass.GetRenderTargetSize();
152 VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
153 vtx_builder.AddVertices({
154 {Point(0, 0), dst_uvs[0], src_uvs[0]},
155 {Point(size.width, 0), dst_uvs[1], src_uvs[1]},
156 {Point(0, size.height), dst_uvs[2], src_uvs[2]},
157 {Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
158 });
159 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
160
161 auto options = OptionsFromPass(pass);
162 options.primitive_type = PrimitiveType::kTriangleStrip;
163 options.blend_mode = BlendMode::kSource;
164 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline =
165 std::invoke(pipeline_proc, renderer, options);
166
167 Command cmd;
168 DEBUG_COMMAND_INFO(cmd, SPrintF("Advanced Blend Filter (%s)",
169 BlendModeToString(blend_mode)));
170 cmd.BindVertices(std::move(vtx_buffer));
171 cmd.pipeline = std::move(pipeline);
172
173 typename FS::BlendInfo blend_info;
174 typename VS::FrameInfo frame_info;
175
176 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
177 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
178 dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
179 dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
180 }
181 auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
182 dst_sampler_descriptor);
183 FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler);
184 frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
185 blend_info.dst_input_alpha =
186 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
187 ? dst_snapshot->opacity
188 : 1.0;
189
190 if (foreground_color.has_value()) {
191 blend_info.color_factor = 1;
192 blend_info.color = foreground_color.value();
193 // This texture will not be sampled from due to the color factor. But
194 // this is present so that validation doesn't trip on a missing
195 // binding.
196 FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler);
197 } else {
198 auto src_sampler_descriptor = src_snapshot->sampler_descriptor;
199 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
200 src_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
201 src_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
202 }
203 auto src_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
204 src_sampler_descriptor);
205 blend_info.color_factor = 0;
206 blend_info.src_input_alpha = src_snapshot->opacity;
207 FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, src_sampler);
208 frame_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale();
209 }
210 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
211 FS::BindBlendInfo(cmd, blend_uniform);
212
213 frame_info.mvp = pass.GetOrthographicTransform() *
214 Matrix::MakeTranslation(coverage.GetOrigin() -
215 subpass_coverage.GetOrigin());
216
217 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
218 VS::BindFrameInfo(cmd, uniform_view);
219 pass.AddCommand(std::move(cmd));
220
221 return true;
222 };
223
224 fml::StatusOr<RenderTarget> render_target = renderer.MakeSubpass(
225 "Advanced Blend Filter", ISize(subpass_coverage.GetSize()), callback);
226 if (!render_target.ok()) {
227 return std::nullopt;
228 }
229
230 return Entity::FromSnapshot(
231 Snapshot{
232 .texture = render_target.value().GetRenderTargetTexture(),
233 .transform = Matrix::MakeTranslation(subpass_coverage.GetOrigin()),
234 // Since we absorbed the transform of the inputs and used the
235 // respective snapshot sampling modes when blending, pass on
236 // the default NN clamp sampler.
237 .sampler_descriptor = {},
238 .opacity = (absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
239 ? 1.0f
240 : dst_snapshot->opacity) *
241 alpha.value_or(1.0)},
242 entity.GetBlendMode(), entity.GetClipDepth());
243 }
244
245 std::optional<Entity> BlendFilterContents::CreateForegroundAdvancedBlend(
246 const std::shared_ptr<FilterInput>& input,
247 const ContentContext& renderer,
248 const Entity& entity,
249 const Rect& coverage,
250 Color foreground_color,
251 BlendMode blend_mode,
252 std::optional<Scalar> alpha,
253 ColorFilterContents::AbsorbOpacity absorb_opacity) const {
254 auto dst_snapshot =
255 input->GetSnapshot("ForegroundAdvancedBlend", renderer, entity);
256 if (!dst_snapshot.has_value()) {
257 return std::nullopt;
258 }
259
260 RenderProc render_proc = [foreground_color, coverage, dst_snapshot,
261 blend_mode, alpha, absorb_opacity](
262 const ContentContext& renderer,
263 const Entity& entity, RenderPass& pass) -> bool {
264 using VS = BlendScreenPipeline::VertexShader;
265 using FS = BlendScreenPipeline::FragmentShader;
266
267 auto& host_buffer = pass.GetTransientsBuffer();
268
269 auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
270 if (!maybe_dst_uvs.has_value()) {
271 return false;
272 }
273 auto dst_uvs = maybe_dst_uvs.value();
274
275 auto size = coverage.GetSize();
276 auto origin = coverage.GetOrigin();
277 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
278 vtx_builder.AddVertices({
279 {origin, dst_uvs[0], dst_uvs[0]},
280 {Point(origin.x + size.width, origin.y), dst_uvs[1], dst_uvs[1]},
281 {Point(origin.x, origin.y + size.height), dst_uvs[2], dst_uvs[2]},
282 {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3],
283 dst_uvs[3]},
284 });
285 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
286
287 Command cmd;
288 DEBUG_COMMAND_INFO(cmd, SPrintF("Foreground Advanced Blend Filter (%s)",
289 BlendModeToString(blend_mode)));
290 cmd.BindVertices(std::move(vtx_buffer));
291 cmd.stencil_reference = entity.GetClipDepth();
292 auto options = OptionsFromPass(pass);
293 options.primitive_type = PrimitiveType::kTriangleStrip;
294
295 switch (blend_mode) {
296 case BlendMode::kScreen:
297 cmd.pipeline = renderer.GetBlendScreenPipeline(options);
298 break;
299 case BlendMode::kOverlay:
300 cmd.pipeline = renderer.GetBlendOverlayPipeline(options);
301 break;
302 case BlendMode::kDarken:
303 cmd.pipeline = renderer.GetBlendDarkenPipeline(options);
304 break;
305 case BlendMode::kLighten:
306 cmd.pipeline = renderer.GetBlendLightenPipeline(options);
307 break;
308 case BlendMode::kColorDodge:
309 cmd.pipeline = renderer.GetBlendColorDodgePipeline(options);
310 break;
311 case BlendMode::kColorBurn:
312 cmd.pipeline = renderer.GetBlendColorBurnPipeline(options);
313 break;
314 case BlendMode::kHardLight:
315 cmd.pipeline = renderer.GetBlendHardLightPipeline(options);
316 break;
317 case BlendMode::kSoftLight:
318 cmd.pipeline = renderer.GetBlendSoftLightPipeline(options);
319 break;
320 case BlendMode::kDifference:
321 cmd.pipeline = renderer.GetBlendDifferencePipeline(options);
322 break;
323 case BlendMode::kExclusion:
324 cmd.pipeline = renderer.GetBlendExclusionPipeline(options);
325 break;
326 case BlendMode::kMultiply:
327 cmd.pipeline = renderer.GetBlendMultiplyPipeline(options);
328 break;
329 case BlendMode::kHue:
330 cmd.pipeline = renderer.GetBlendHuePipeline(options);
331 break;
332 case BlendMode::kSaturation:
333 cmd.pipeline = renderer.GetBlendSaturationPipeline(options);
334 break;
335 case BlendMode::kColor:
336 cmd.pipeline = renderer.GetBlendColorPipeline(options);
337 break;
338 case BlendMode::kLuminosity:
339 cmd.pipeline = renderer.GetBlendLuminosityPipeline(options);
340 break;
341 default:
342 return false;
343 }
344
345 FS::BlendInfo blend_info;
346 VS::FrameInfo frame_info;
347
348 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
349 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
350 dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
351 dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
352 }
353 auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
354 dst_sampler_descriptor);
355 FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler);
356 frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
357 blend_info.dst_input_alpha =
358 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
359 ? dst_snapshot->opacity * alpha.value_or(1.0)
360 : 1.0;
361
362 blend_info.color_factor = 1;
363 blend_info.color = foreground_color;
364 // This texture will not be sampled from due to the color factor. But
365 // this is present so that validation doesn't trip on a missing
366 // binding.
367 FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler);
368
369 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
370 FS::BindBlendInfo(cmd, blend_uniform);
371
372 frame_info.mvp = pass.GetOrthographicTransform() * entity.GetTransform();
373
374 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
375 VS::BindFrameInfo(cmd, uniform_view);
376
377 return pass.AddCommand(std::move(cmd));
378 };
379 CoverageProc coverage_proc =
380 [coverage](const Entity& entity) -> std::optional<Rect> {
381 return coverage.TransformBounds(entity.GetTransform());
382 };
383
384 auto contents = AnonymousContents::Make(render_proc, coverage_proc);
385
386 Entity sub_entity;
387 sub_entity.SetContents(std::move(contents));
388 sub_entity.SetClipDepth(entity.GetClipDepth());
389
390 return sub_entity;
391 }
392
393 std::optional<Entity> BlendFilterContents::CreateForegroundPorterDuffBlend(
394 const std::shared_ptr<FilterInput>& input,
395 const ContentContext& renderer,
396 const Entity& entity,
397 const Rect& coverage,
398 Color foreground_color,
399 BlendMode blend_mode,
400 std::optional<Scalar> alpha,
401 ColorFilterContents::AbsorbOpacity absorb_opacity) const {
402 if (blend_mode == BlendMode::kClear) {
403 return std::nullopt;
404 }
405
406 if (blend_mode == BlendMode::kSource) {
407 auto contents = std::make_shared<SolidColorContents>();
408 contents->SetGeometry(Geometry::MakeRect(coverage));
409 contents->SetColor(foreground_color);
410
411 Entity foreground_entity;
412 foreground_entity.SetBlendMode(entity.GetBlendMode());
413 foreground_entity.SetClipDepth(entity.GetClipDepth());
414 foreground_entity.SetContents(std::move(contents));
415 return foreground_entity;
416 }
417
418 auto dst_snapshot =
419 input->GetSnapshot("ForegroundPorterDuffBlend", renderer, entity);
420 if (!dst_snapshot.has_value()) {
421 return std::nullopt;
422 }
423
424 if (blend_mode == BlendMode::kDestination) {
425 return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(),
426 entity.GetClipDepth());
427 }
428
429 RenderProc render_proc = [foreground_color, coverage, dst_snapshot,
430 blend_mode, absorb_opacity, alpha](
431 const ContentContext& renderer,
432 const Entity& entity, RenderPass& pass) -> bool {
433 using VS = PorterDuffBlendPipeline::VertexShader;
434 using FS = PorterDuffBlendPipeline::FragmentShader;
435
436 auto& host_buffer = pass.GetTransientsBuffer();
437
438 auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
439 if (!maybe_dst_uvs.has_value()) {
440 return false;
441 }
442 auto dst_uvs = maybe_dst_uvs.value();
443
444 auto size = coverage.GetSize();
445 auto origin = coverage.GetOrigin();
446 auto color = foreground_color.Premultiply();
447 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
448 vtx_builder.AddVertices({
449 {origin, dst_uvs[0], color},
450 {Point(origin.x + size.width, origin.y), dst_uvs[1], color},
451 {Point(origin.x, origin.y + size.height), dst_uvs[2], color},
452 {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3],
453 color},
454 });
455 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
456
457 Command cmd;
458 DEBUG_COMMAND_INFO(cmd, SPrintF("Foreground PorterDuff Blend Filter (%s)",
459 BlendModeToString(blend_mode)));
460 cmd.BindVertices(std::move(vtx_buffer));
461 cmd.stencil_reference = entity.GetClipDepth();
462 auto options = OptionsFromPass(pass);
463 options.primitive_type = PrimitiveType::kTriangleStrip;
464 cmd.pipeline = renderer.GetPorterDuffBlendPipeline(options);
465
466 FS::FragInfo frag_info;
467 VS::FrameInfo frame_info;
468
469 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
470 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
471 dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
472 dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
473 }
474 auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
475 dst_sampler_descriptor);
476 FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler);
477 frame_info.texture_sampler_y_coord_scale =
478 dst_snapshot->texture->GetYCoordScale();
479
480 frag_info.input_alpha =
481 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
482 ? dst_snapshot->opacity * alpha.value_or(1.0)
483 : 1.0;
484 frag_info.output_alpha = 1.0;
485
486 auto blend_coefficients =
487 kPorterDuffCoefficients[static_cast<int>(blend_mode)];
488 frag_info.src_coeff = blend_coefficients[0];
489 frag_info.src_coeff_dst_alpha = blend_coefficients[1];
490 frag_info.dst_coeff = blend_coefficients[2];
491 frag_info.dst_coeff_src_alpha = blend_coefficients[3];
492 frag_info.dst_coeff_src_color = blend_coefficients[4];
493
494 FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
495
496 frame_info.mvp = pass.GetOrthographicTransform() * entity.GetTransform();
497
498 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
499 VS::BindFrameInfo(cmd, uniform_view);
500
501 return pass.AddCommand(std::move(cmd));
502 };
503
504 CoverageProc coverage_proc =
505 [coverage](const Entity& entity) -> std::optional<Rect> {
506 return coverage.TransformBounds(entity.GetTransform());
507 };
508
509 auto contents = AnonymousContents::Make(render_proc, coverage_proc);
510
511 Entity sub_entity;
512 sub_entity.SetContents(std::move(contents));
513 sub_entity.SetClipDepth(entity.GetClipDepth());
514
515 return sub_entity;
516 }
517
518 static std::optional<Entity> PipelineBlend(
519 const FilterInput::Vector& inputs,
520 const ContentContext& renderer,
521 const Entity& entity,
522 const Rect& coverage,
523 BlendMode blend_mode,
524 std::optional<Color> foreground_color,
525 ColorFilterContents::AbsorbOpacity absorb_opacity,
526 std::optional<Scalar> alpha) {
527 using VS = BlendPipeline::VertexShader;
528 using FS = BlendPipeline::FragmentShader;
529
530 auto dst_snapshot =
531 inputs[0]->GetSnapshot("PipelineBlend(Dst)", renderer, entity);
532 if (!dst_snapshot.has_value()) {
533 return std::nullopt; // Nothing to render.
534 }
535
536 Rect subpass_coverage = coverage;
537 if (entity.GetContents()) {
538 auto coverage_hint = entity.GetContents()->GetCoverageHint();
539
540 if (coverage_hint.has_value()) {
541 auto maybe_subpass_coverage =
542 subpass_coverage.Intersection(*coverage_hint);
543 if (!maybe_subpass_coverage.has_value()) {
544 return std::nullopt; // Nothing to render.
545 }
546
547 subpass_coverage = *maybe_subpass_coverage;
548 }
549 }
550
551 ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
552 RenderPass& pass) {
553 auto& host_buffer = pass.GetTransientsBuffer();
554
555 Command cmd;
556 DEBUG_COMMAND_INFO(cmd, SPrintF("Pipeline Blend Filter (%s)",
557 BlendModeToString(blend_mode)));
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 auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
571 input->sampler_descriptor);
572 FS::BindTextureSamplerSrc(cmd, input->texture, sampler);
573
574 auto size = input->texture->GetSize();
575 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
576 vtx_builder.AddVertices({
577 {Point(0, 0), Point(0, 0)},
578 {Point(size.width, 0), Point(1, 0)},
579 {Point(0, size.height), Point(0, 1)},
580 {Point(size.width, size.height), Point(1, 1)},
581 });
582 cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer));
583
584 VS::FrameInfo frame_info;
585 frame_info.mvp = pass.GetOrthographicTransform() *
586 Matrix::MakeTranslation(-subpass_coverage.GetOrigin()) *
587 input->transform;
588 frame_info.texture_sampler_y_coord_scale =
589 input->texture->GetYCoordScale();
590
591 FS::FragInfo frag_info;
592 frag_info.input_alpha =
593 absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
594 ? input->opacity
595 : 1.0;
596 FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
597 VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
598
599 pass.AddCommand(std::move(cmd));
600 return true;
601 };
602
603 // Draw the first texture using kSource.
604 options.blend_mode = BlendMode::kSource;
605 cmd.pipeline = renderer.GetBlendPipeline(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 cmd.pipeline = renderer.GetBlendPipeline(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 contents->SetGeometry(
631 Geometry::MakeRect(Rect::MakeSize(pass.GetRenderTargetSize())));
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 fml::StatusOr<RenderTarget> render_target = renderer.MakeSubpass(
646 "Pipeline Blend Filter", ISize(subpass_coverage.GetSize()), callback);
647
648 if (!render_target.ok()) {
649 return std::nullopt;
650 }
651
652 return Entity::FromSnapshot(
653 Snapshot{
654 .texture = render_target.value().GetRenderTargetTexture(),
655 .transform = Matrix::MakeTranslation(subpass_coverage.GetOrigin()),
656 // Since we absorbed the transform of the inputs and used the
657 // respective snapshot sampling modes when blending, pass on
658 // the default NN clamp sampler.
659 .sampler_descriptor = {},
660 .opacity = (absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes
661 ? 1.0f
662 : dst_snapshot->opacity) *
663 alpha.value_or(1.0)},
664 entity.GetBlendMode(), entity.GetClipDepth());
665 }
666
667 #define BLEND_CASE(mode) \
668 case BlendMode::k##mode: \
669 advanced_blend_proc_ = \
670 [](const FilterInput::Vector& inputs, const ContentContext& renderer, \
671 const Entity& entity, const Rect& coverage, BlendMode blend_mode, \
672 std::optional<Color> fg_color, \
673 ColorFilterContents::AbsorbOpacity absorb_opacity, \
674 std::optional<Scalar> alpha) { \
675 PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \
676 return AdvancedBlend<Blend##mode##Pipeline>( \
677 inputs, renderer, entity, coverage, blend_mode, fg_color, \
678 absorb_opacity, p, alpha); \
679 }; \
680 break;
681
682 void BlendFilterContents::SetBlendMode(BlendMode blend_mode) {
683 if (blend_mode > Entity::kLastAdvancedBlendMode) {
684 VALIDATION_LOG << "Invalid blend mode " << static_cast<int>(blend_mode)
685 << " assigned to BlendFilterContents.";
686 }
687
688 blend_mode_ = blend_mode;
689
690 if (blend_mode > Entity::kLastPipelineBlendMode) {
691 switch (blend_mode) {
692 BLEND_CASE(Screen)
693 BLEND_CASE(Overlay)
694 BLEND_CASE(Darken)
695 BLEND_CASE(Lighten)
696 BLEND_CASE(ColorDodge)
697 BLEND_CASE(ColorBurn)
698 BLEND_CASE(HardLight)
699 BLEND_CASE(SoftLight)
700 BLEND_CASE(Difference)
701 BLEND_CASE(Exclusion)
702 BLEND_CASE(Multiply)
703 BLEND_CASE(Hue)
704 BLEND_CASE(Saturation)
705 BLEND_CASE(Color)
706 BLEND_CASE(Luminosity)
707 default:
708 FML_UNREACHABLE();
709 }
710 }
711 }
712
713 void BlendFilterContents::SetForegroundColor(std::optional<Color> color) {
714 foreground_color_ = color;
715 }
716
717 std::optional<Entity> BlendFilterContents::RenderFilter(
718 const FilterInput::Vector& inputs,
719 const ContentContext& renderer,
720 const Entity& entity,
721 const Matrix& effect_transform,
722 const Rect& coverage,
723 const std::optional<Rect>& coverage_hint) const {
724 if (inputs.empty()) {
725 return std::nullopt;
726 }
727
728 if (inputs.size() == 1 && !foreground_color_.has_value()) {
729 // Nothing to blend.
730 return PipelineBlend(inputs, renderer, entity, coverage, BlendMode::kSource,
731 std::nullopt, GetAbsorbOpacity(), GetAlpha());
732 }
733
734 if (blend_mode_ <= Entity::kLastPipelineBlendMode) {
735 if (inputs.size() == 1 && foreground_color_.has_value() &&
736 GetAbsorbOpacity() == ColorFilterContents::AbsorbOpacity::kYes) {
737 return CreateForegroundPorterDuffBlend(
738 inputs[0], renderer, entity, coverage, foreground_color_.value(),
739 blend_mode_, GetAlpha(), GetAbsorbOpacity());
740 }
741 return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_,
742 foreground_color_, GetAbsorbOpacity(), GetAlpha());
743 }
744
745 if (blend_mode_ <= Entity::kLastAdvancedBlendMode) {
746 if (inputs.size() == 1 && foreground_color_.has_value() &&
747 GetAbsorbOpacity() == ColorFilterContents::AbsorbOpacity::kYes) {
748 return CreateForegroundAdvancedBlend(
749 inputs[0], renderer, entity, coverage, foreground_color_.value(),
750 blend_mode_, GetAlpha(), GetAbsorbOpacity());
751 }
752 return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode_,
753 foreground_color_, GetAbsorbOpacity(),
754 GetAlpha());
755 }
756
757 FML_UNREACHABLE();
758 }
759
760 } // namespace impeller
impeller::OptionsFromPass
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:20
impeller::Command
An object used to specify work to the GPU along with references to resources the GPU will used when d...
Definition: command.h:92
BLEND_CASE
#define BLEND_CASE(mode)
Definition: blend_filter_contents.cc:667
DEBUG_COMMAND_INFO
#define DEBUG_COMMAND_INFO(obj, arg)
Definition: command.h:28
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:23
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:682
impeller::ContentContext::GetBlendPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetBlendPipeline(ContentContextOptions opts) const
Definition: content_context.h:410
impeller::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:101
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:713
entity.h
impeller::BlendMode
BlendMode
Definition: color.h:59
solid_color_contents.h
impeller::Color
Definition: color.h:124
impeller::BlendMode::kLuminosity
@ kLuminosity
impeller::BlendMode::kSource
@ kSource
impeller::BlendMode::kColorDodge
@ kColorDodge
impeller::ContentContext::MakeSubpass
fml::StatusOr< RenderTarget > MakeSubpass(const std::string &label, ISize texture_size, const SubpassCallback &subpass_callback, bool msaa_enabled=true) const
Creates a new texture of size texture_size and calls subpass_callback with a RenderPass for drawing t...
Definition: content_context.cc:410
impeller::BlendMode::kDestination
@ kDestination
impeller::BlendMode::kDarken
@ kDarken
formats.h
impeller::InvertPorterDuffBlend
std::optional< BlendMode > InvertPorterDuffBlend(BlendMode blend_mode)
Definition: blend_filter_contents.cc:26
impeller::BlendMode::kColor
@ kColor
impeller::RenderPipelineT::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:93
impeller::BlendMode::kDestinationOver
@ kDestinationOver
impeller::BlendMode::kPlus
@ kPlus
impeller::BlendMode::kOverlay
@ kOverlay
impeller::VertexBufferBuilder::AddVertices
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
Definition: vertex_buffer_builder.h:70
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 when it was constructed.
Definition: rect.h:154
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:71
impeller::BlendMode::kSourceOut
@ kSourceOut
impeller::BlendMode::kSaturation
@ kSaturation
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:81
impeller::BlendMode::kDifference
@ kDifference
impeller::Entity
Definition: entity.h:21
impeller::BlendMode::kLighten
@ kLighten
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::BlendMode::kSoftLight
@ kSoftLight
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::TRect::Intersection
constexpr std::optional< TRect< T > > Intersection(const TRect &o) const
Definition: rect.h:312
render_pass.h
impeller::BlendMode::kColorBurn
@ kColorBurn
impeller::Entity::Render
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
Definition: entity.cc:159
impeller::BlendMode::kHardLight
@ kHardLight
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
impeller::BlendMode::kClear
@ kClear
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:479
impeller::VertexBufferBuilder
Definition: vertex_buffer_builder.h:24
impeller::Entity::kLastAdvancedBlendMode
static constexpr BlendMode kLastAdvancedBlendMode
Definition: entity.h:24
impeller::ColorFilterContents::GetAbsorbOpacity
AbsorbOpacity GetAbsorbOpacity() const
Definition: color_filter_contents.cc:89
impeller::Snapshot
Represents a texture and its intended draw transform/sampler configuration.
Definition: snapshot.h:25
impeller::Command::BindVertices
bool BindVertices(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: command.cc:15
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:85
impeller::PipelineProc
std::shared_ptr< Pipeline< PipelineDescriptor > >(ContentContext::*)(ContentContextOptions) const PipelineProc
Definition: blend_filter_contents.cc:68
filter_input.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:488
impeller::Luminosity
static constexpr Scalar Luminosity(Vector3 color)
Definition: color.cc:140
strings.h
color_filter_contents.h
impeller::BlendFilterContents::~BlendFilterContents
~BlendFilterContents() override
anonymous_contents.h
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:105
impeller::VertexBufferBuilder::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
Definition: vertex_buffer_builder.h:84
impeller::ContentContext::SubpassCallback
std::function< bool(const ContentContext &, RenderPass &)> SubpassCallback
Definition: content_context.h:708
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:29
impeller::Geometry::MakeRect
static std::shared_ptr< Geometry > MakeRect(const Rect &rect)
Definition: geometry.cc:179
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:93
impeller::BlendMode::kDestinationIn
@ kDestinationIn
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
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:49
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle as specified when it was constructed and which may be negative in e...
Definition: rect.h:159
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:483
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:44
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:518
impeller::BlendMode::kSourceIn
@ kSourceIn
impeller::BlendMode::kScreen
@ kScreen
color.h
impeller::BlendMode::kHue
@ kHue
blend_filter_contents.h
impeller::Contents::CoverageProc
std::function< std::optional< Rect >(const Entity &entity)> CoverageProc
Definition: contents.h:50
impeller::Snapshot::texture
std::shared_ptr< Texture > texture
Definition: snapshot.h:26
impeller::Command::pipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > pipeline
Definition: command.h:96
impeller::ColorFilterContents::AbsorbOpacity::kYes
@ kYes
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::BlendMode::kXor
@ kXor
impeller::Entity::FromSnapshot
static std::optional< Entity > FromSnapshot(const std::optional< Snapshot > &snapshot, BlendMode blend_mode=BlendMode::kSourceOver, uint32_t clip_depth=0)
Create an entity that can be used to render a given snapshot.
Definition: entity.cc:21
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::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:92
impeller::ContentContextOptions
Definition: content_context.h:276
impeller::ColorFilterContents::AbsorbOpacity
AbsorbOpacity
Definition: color_filter_contents.h:14
impeller
Definition: aiks_context.cc:10
impeller::BlendMode::kSourceATop
@ kSourceATop
impeller::BlendMode::kMultiply
@ kMultiply
impeller::ContentContext
Definition: content_context.h:332
impeller::BlendFilterContents::BlendFilterContents
BlendFilterContents()
Definition: blend_filter_contents.cc:61
impeller::TRect
Definition: rect.h:22
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::Saturation
static constexpr Scalar Saturation(Vector3 color)
Definition: color.cc:166
impeller::SamplerAddressMode::kDecal
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...