11 #include "flutter/fml/logging.h"
25 #include "impeller/entity/texture_fill.frag.h"
26 #include "impeller/entity/texture_fill.vert.h"
74 using PipelineProc = std::shared_ptr<Pipeline<PipelineDescriptor>> (
77 template <
typename TPipeline>
84 std::optional<Color> foreground_color,
87 std::optional<Scalar> alpha) {
88 using VS =
typename TPipeline::VertexShader;
89 using FS =
typename TPipeline::FragmentShader;
95 const size_t total_inputs =
96 inputs.size() + (foreground_color.has_value() ? 1 : 0);
97 if (total_inputs < 2) {
102 inputs[0]->GetSnapshot(
"AdvancedBlend(Dst)", renderer, entity);
103 if (!dst_snapshot.has_value()) {
106 auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
107 if (!maybe_dst_uvs.has_value()) {
110 auto dst_uvs = maybe_dst_uvs.value();
112 std::optional<Snapshot> src_snapshot;
113 std::array<Point, 4> src_uvs;
114 if (!foreground_color.has_value()) {
116 inputs[1]->GetSnapshot(
"AdvancedBlend(Src)", renderer, entity);
117 if (!src_snapshot.has_value()) {
118 if (!dst_snapshot.has_value()) {
123 auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
124 if (!maybe_src_uvs.has_value()) {
125 if (!dst_snapshot.has_value()) {
130 src_uvs = maybe_src_uvs.value();
133 Rect subpass_coverage = coverage;
135 auto coverage_hint = entity.
GetContents()->GetCoverageHint();
137 if (coverage_hint.has_value()) {
138 auto maybe_subpass_coverage =
140 if (!maybe_subpass_coverage.has_value()) {
144 subpass_coverage = *maybe_subpass_coverage;
156 auto size = pass.GetRenderTargetSize();
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],
162 typename VS::PerVertexData{
Point(0, size.height), dst_uvs[2],
164 typename VS::PerVertexData{
Point(size.width, size.height), dst_uvs[3],
173 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline =
174 std::invoke(pipeline_proc, renderer, options);
176 #ifdef IMPELLER_DEBUG
177 pass.SetCommandLabel(
179 #endif // IMPELLER_DEBUG
180 pass.SetVertexBuffer(std::move(vtx_buffer));
181 pass.SetPipeline(pipeline);
183 typename FS::BlendInfo blend_info;
184 typename VS::FrameInfo frame_info;
186 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
191 const std::unique_ptr<const Sampler>& dst_sampler =
192 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
193 dst_sampler_descriptor);
194 FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
195 frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
196 blend_info.dst_input_alpha =
198 ? dst_snapshot->opacity
201 if (foreground_color.has_value()) {
202 blend_info.color_factor = 1;
203 blend_info.color = foreground_color.value();
207 FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
209 auto src_sampler_descriptor = src_snapshot->sampler_descriptor;
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();
222 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
223 FS::BindBlendInfo(pass, blend_uniform);
225 frame_info.mvp = pass.GetOrthographicTransform() *
229 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
230 VS::BindFrameInfo(pass, uniform_view);
232 return pass.Draw().ok();
235 std::shared_ptr<CommandBuffer> command_buffer =
237 if (!command_buffer) {
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()) {
248 ->Submit({std::move(command_buffer)})
255 .
texture = render_target.value().GetRenderTargetTexture(),
260 .sampler_descriptor = {},
263 : dst_snapshot->opacity) *
264 alpha.value_or(1.0)},
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,
275 std::optional<Scalar> alpha,
278 input->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
279 if (!dst_snapshot.has_value()) {
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 {
290 auto& host_buffer = renderer.GetTransientsBuffer();
291 auto size = dst_snapshot->texture->GetSize();
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}},
302 #ifdef IMPELLER_DEBUG
303 pass.SetCommandLabel(
SPrintF(
"Foreground Advanced Blend Filter (%s)",
305 #endif // IMPELLER_DEBUG
306 pass.SetVertexBuffer(std::move(vtx_buffer));
310 switch (blend_mode) {
312 pass.SetPipeline(renderer.GetBlendScreenPipeline(options));
315 pass.SetPipeline(renderer.GetBlendOverlayPipeline(options));
318 pass.SetPipeline(renderer.GetBlendDarkenPipeline(options));
321 pass.SetPipeline(renderer.GetBlendLightenPipeline(options));
324 pass.SetPipeline(renderer.GetBlendColorDodgePipeline(options));
327 pass.SetPipeline(renderer.GetBlendColorBurnPipeline(options));
330 pass.SetPipeline(renderer.GetBlendHardLightPipeline(options));
333 pass.SetPipeline(renderer.GetBlendSoftLightPipeline(options));
336 pass.SetPipeline(renderer.GetBlendDifferencePipeline(options));
339 pass.SetPipeline(renderer.GetBlendExclusionPipeline(options));
342 pass.SetPipeline(renderer.GetBlendMultiplyPipeline(options));
345 pass.SetPipeline(renderer.GetBlendHuePipeline(options));
348 pass.SetPipeline(renderer.GetBlendSaturationPipeline(options));
351 pass.SetPipeline(renderer.GetBlendColorPipeline(options));
354 pass.SetPipeline(renderer.GetBlendLuminosityPipeline(options));
360 FS::BlendInfo blend_info;
361 VS::FrameInfo frame_info;
363 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
364 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
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();
375 entity.GetShaderClipDepth(), pass,
376 entity.GetTransform() * dst_snapshot->transform);
378 blend_info.dst_input_alpha =
380 ? dst_snapshot->opacity * alpha.value_or(1.0)
383 blend_info.color_factor = 1;
384 blend_info.color = foreground_color;
388 FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
390 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
391 FS::BindBlendInfo(pass, blend_uniform);
393 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
394 VS::BindFrameInfo(pass, uniform_view);
396 return pass.Draw().ok();
399 [coverage](
const Entity& entity) -> std::optional<Rect> {
400 return coverage.TransformBounds(entity.GetTransform());
406 sub_entity.SetContents(std::move(contents));
407 sub_entity.SetBlendMode(entity.GetBlendMode());
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,
419 std::optional<Scalar> alpha,
426 input->GetSnapshot(
"ForegroundPorterDuffBlend", renderer, entity);
427 if (!dst_snapshot.has_value()) {
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 {
442 auto& host_buffer = renderer.GetTransientsBuffer();
443 auto size = dst_snapshot->texture->GetSize();
444 auto color = foreground_color.Premultiply();
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},
455 #ifdef IMPELLER_DEBUG
456 pass.SetCommandLabel(
SPrintF(
"Foreground PorterDuff Blend Filter (%s)",
458 #endif // IMPELLER_DEBUG
459 pass.SetVertexBuffer(std::move(vtx_buffer));
462 pass.SetPipeline(renderer.GetPorterDuffBlendPipeline(options));
464 FS::FragInfo frag_info;
465 VS::FrameInfo frame_info;
468 entity.GetShaderClipDepth(), pass,
469 entity.GetTransform() * dst_snapshot->transform);
471 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
472 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
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();
483 frag_info.input_alpha =
485 ? dst_snapshot->opacity * alpha.value_or(1.0)
487 frag_info.output_alpha = 1.0;
489 auto blend_coefficients =
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];
497 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
498 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
500 return pass.Draw().ok();
504 [coverage](
const Entity& entity) -> std::optional<Rect> {
505 return coverage.TransformBounds(entity.GetTransform());
511 sub_entity.SetContents(std::move(contents));
512 sub_entity.SetBlendMode(entity.GetBlendMode());
521 const Rect& coverage,
523 std::optional<Color> foreground_color,
525 std::optional<Scalar> alpha) {
530 inputs[0]->GetSnapshot(
"PipelineBlend(Dst)", renderer, entity);
531 if (!dst_snapshot.has_value()) {
535 Rect subpass_coverage = coverage;
537 auto coverage_hint = entity.
GetContents()->GetCoverageHint();
539 if (coverage_hint.has_value()) {
540 auto maybe_subpass_coverage =
542 if (!maybe_subpass_coverage.has_value()) {
546 subpass_coverage = *maybe_subpass_coverage;
554 #ifdef IMPELLER_DEBUG
555 pass.SetCommandLabel(
557 #endif // IMPELLER_DEBUG
561 auto add_blend_command = [&](std::optional<Snapshot> input) {
562 if (!input.has_value()) {
565 auto input_coverage = input->GetCoverage();
566 if (!input_coverage.has_value()) {
570 const std::unique_ptr<const Sampler>& sampler =
571 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
572 input->sampler_descriptor);
573 FS::BindTextureSampler(pass, input->texture, sampler);
575 auto size = input->texture->GetSize();
576 std::array<VS::PerVertexData, 4> vertices = {
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)},
582 pass.SetVertexBuffer(
585 VS::FrameInfo frame_info;
586 frame_info.mvp = pass.GetOrthographicTransform() *
589 frame_info.texture_sampler_y_coord_scale =
590 input->texture->GetYCoordScale();
592 FS::FragInfo frag_info;
597 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
598 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
600 return pass.Draw().ok();
606 if (!add_blend_command(dst_snapshot)) {
612 if (inputs.size() >= 2) {
613 options.blend_mode = blend_mode;
616 for (
auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
618 auto src_input = texture_i->get()->GetSnapshot(
"PipelineBlend(Src)",
620 if (!add_blend_command(src_input)) {
628 if (foreground_color.has_value()) {
629 auto contents = std::make_shared<SolidColorContents>();
631 contents->SetGeometry(&geom);
632 contents->SetColor(foreground_color.value());
637 if (!foreground_entity.
Render(renderer, pass)) {
645 std::shared_ptr<CommandBuffer> command_buffer =
647 if (!command_buffer) {
651 fml::StatusOr<RenderTarget> render_target = renderer.
MakeSubpass(
652 "Pipeline Blend Filter",
ISize(subpass_coverage.
GetSize()),
653 command_buffer, callback);
655 if (!render_target.ok()) {
661 ->Submit({std::move(command_buffer)})
668 .
texture = render_target.value().GetRenderTargetTexture(),
673 .sampler_descriptor = {},
676 : dst_snapshot->opacity) *
677 alpha.value_or(1.0)},
681 std::optional<Entity> BlendFilterContents::CreateFramebufferAdvancedBlend(
683 const ContentContext& renderer,
684 const Entity& entity,
685 const Rect& coverage,
686 std::optional<Color> foreground_color,
688 std::optional<Scalar> alpha,
691 FML_DCHECK(inputs.size() == 2u ||
692 (inputs.size() == 1u && foreground_color.has_value()));
695 inputs[0]->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
696 if (!dst_snapshot.has_value()) {
700 std::shared_ptr<Texture> foreground_texture;
707 HostBuffer& host_buffer = renderer.GetTransientsBuffer();
710 using FS = TextureFillFragmentShader;
711 using VS = TextureFillVertexShader;
713 pass.SetCommandLabel(
"Framebuffer Advanced Blend");
716 pass.SetPipeline(renderer.GetTexturePipeline(pipeline_options));
718 VS::FrameInfo frame_info;
720 frame_info.texture_sampler_y_coord_scale = 1.0;
722 FS::FragInfo frag_info;
723 frag_info.alpha = 1.0;
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}},
731 pass.SetVertexBuffer(
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({}));
740 if (!pass.Draw().ok()) {
751 std::shared_ptr<Texture> src_texture;
752 if (foreground_color.has_value()) {
753 src_texture = foreground_texture;
756 inputs[0]->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
757 if (!src_snapshot.has_value()) {
763 src_texture = src_snapshot->texture;
766 std::array<VS::PerVertexData, 4> vertices = {
777 pass.SetCommandLabel(
"Framebuffer Advanced Blend Filter");
778 pass.SetVertexBuffer(
781 switch (blend_mode) {
783 pass.SetPipeline(renderer.GetFramebufferBlendScreenPipeline(options));
787 renderer.GetFramebufferBlendOverlayPipeline(options));
790 pass.SetPipeline(renderer.GetFramebufferBlendDarkenPipeline(options));
794 renderer.GetFramebufferBlendLightenPipeline(options));
798 renderer.GetFramebufferBlendColorDodgePipeline(options));
802 renderer.GetFramebufferBlendColorBurnPipeline(options));
806 renderer.GetFramebufferBlendHardLightPipeline(options));
810 renderer.GetFramebufferBlendSoftLightPipeline(options));
814 renderer.GetFramebufferBlendDifferencePipeline(options));
818 renderer.GetFramebufferBlendExclusionPipeline(options));
822 renderer.GetFramebufferBlendMultiplyPipeline(options));
825 pass.SetPipeline(renderer.GetFramebufferBlendHuePipeline(options));
829 renderer.GetFramebufferBlendSaturationPipeline(options));
832 pass.SetPipeline(renderer.GetFramebufferBlendColorPipeline(options));
836 renderer.GetFramebufferBlendLuminosityPipeline(options));
842 VS::FrameInfo frame_info;
843 FS::FragInfo frag_info;
845 auto src_sampler_descriptor = SamplerDescriptor{};
846 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
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);
856 frame_info.src_y_coord_scale = src_texture->GetYCoordScale();
857 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
859 frag_info.src_input_alpha = 1.0;
860 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
862 return pass.Draw().ok();
866 std::shared_ptr<CommandBuffer> cmd_buffer =
867 renderer.GetContext()->CreateCommandBuffer();
870 if (foreground_color.has_value()) {
871 TextureDescriptor desc;
876 renderer.GetContext()->GetResourceAllocator()->CreateTexture(desc);
877 if (!foreground_texture) {
880 auto blit_pass = cmd_buffer->CreateBlitPass();
881 auto buffer_view = renderer.GetTransientsBuffer().Emplace(
882 foreground_color->Premultiply().ToR8G8B8A8(), 4);
884 blit_pass->AddCopy(std::move(
buffer_view), foreground_texture);
885 if (!blit_pass->EncodeCommands(
886 renderer.GetContext()->GetResourceAllocator())) {
892 renderer.MakeSubpass(
"FramebufferBlend", dst_snapshot->texture->GetSize(),
893 cmd_buffer, subpass_callback);
895 if (!render_target.ok()) {
899 if (!renderer.GetContext()
901 ->Submit({std::move(cmd_buffer)})
908 .texture = render_target.value().GetRenderTargetTexture(),
913 .sampler_descriptor = {},
916 : dst_snapshot->opacity) *
917 alpha.value_or(1.0)},
918 entity.GetBlendMode());
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); \
938 VALIDATION_LOG <<
"Invalid blend mode " <<
static_cast<int>(blend_mode)
939 <<
" assigned to BlendFilterContents.";
942 blend_mode_ = blend_mode;
945 switch (blend_mode) {
968 foreground_color_ =
color;
971 std::optional<Entity> BlendFilterContents::RenderFilter(
975 const Matrix& effect_transform,
976 const Rect& coverage,
977 const std::optional<Rect>& coverage_hint)
const {
978 if (inputs.empty()) {
982 if (inputs.size() == 1 && !foreground_color_.has_value()) {
989 if (inputs.size() == 1 && foreground_color_.has_value() &&
991 return CreateForegroundPorterDuffBlend(
992 inputs[0], renderer, entity, coverage, foreground_color_.value(),
995 return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_,
1001 return CreateFramebufferAdvancedBlend(inputs, renderer, entity, coverage,
1002 foreground_color_, blend_mode_,
1005 if (inputs.size() == 1 && foreground_color_.has_value() &&
1007 return CreateForegroundAdvancedBlend(
1008 inputs[0], renderer, entity, coverage, foreground_color_.value(),
1011 return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode_,