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