11#include "flutter/fml/logging.h"
23#include "impeller/entity/texture_fill.frag.h"
24#include "impeller/entity/texture_fill.vert.h"
72using PipelineProc = std::shared_ptr<Pipeline<PipelineDescriptor>> (
75template <
typename TPipeline>
82 std::optional<Color> foreground_color,
85 std::optional<Scalar> alpha) {
86 using VS =
typename TPipeline::VertexShader;
87 using FS =
typename TPipeline::FragmentShader;
93 const size_t total_inputs =
94 inputs.size() + (foreground_color.has_value() ? 1 : 0);
95 if (total_inputs < 2) {
100 inputs[0]->GetSnapshot(
"AdvancedBlend(Dst)", renderer, entity);
101 if (!dst_snapshot.has_value()) {
104 auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
105 if (!maybe_dst_uvs.has_value()) {
108 auto dst_uvs = maybe_dst_uvs.value();
110 std::optional<Snapshot> src_snapshot;
111 std::array<Point, 4> src_uvs;
112 if (!foreground_color.has_value()) {
114 inputs[1]->GetSnapshot(
"AdvancedBlend(Src)", renderer, entity);
115 if (!src_snapshot.has_value()) {
116 if (!dst_snapshot.has_value()) {
121 auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
122 if (!maybe_src_uvs.has_value()) {
123 if (!dst_snapshot.has_value()) {
128 src_uvs = maybe_src_uvs.value();
131 Rect subpass_coverage = coverage;
133 auto coverage_hint = entity.
GetContents()->GetCoverageHint();
135 if (coverage_hint.has_value()) {
136 auto maybe_subpass_coverage =
138 if (!maybe_subpass_coverage.has_value()) {
142 subpass_coverage = *maybe_subpass_coverage;
152 auto& host_buffer = renderer.GetTransientsBuffer();
154 auto size = pass.GetRenderTargetSize();
157 {
Point(0, 0), dst_uvs[0], src_uvs[0]},
158 {
Point(size.width, 0), dst_uvs[1], src_uvs[1]},
159 {
Point(0, size.height), dst_uvs[2], src_uvs[2]},
160 {
Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
167 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline =
168 std::invoke(pipeline_proc, renderer,
options);
171 pass.SetCommandLabel(
174 pass.SetVertexBuffer(std::move(vtx_buffer));
175 pass.SetPipeline(pipeline);
177 typename FS::BlendInfo blend_info;
178 typename VS::FrameInfo frame_info;
180 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
181 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
185 const std::unique_ptr<const Sampler>& dst_sampler =
186 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
187 dst_sampler_descriptor);
188 FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
189 frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
190 blend_info.dst_input_alpha =
192 ? dst_snapshot->opacity
195 if (foreground_color.has_value()) {
196 blend_info.color_factor = 1;
197 blend_info.color = foreground_color.value();
201 FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
203 auto src_sampler_descriptor = src_snapshot->sampler_descriptor;
204 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
208 const std::unique_ptr<const Sampler>& src_sampler =
209 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
210 src_sampler_descriptor);
211 blend_info.color_factor = 0;
212 blend_info.src_input_alpha = src_snapshot->opacity;
213 FS::BindTextureSamplerSrc(pass, src_snapshot->texture, src_sampler);
214 frame_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale();
216 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
217 FS::BindBlendInfo(pass, blend_uniform);
219 frame_info.mvp = pass.GetOrthographicTransform() *
223 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
224 VS::BindFrameInfo(pass, uniform_view);
226 return pass.Draw().ok();
229 std::shared_ptr<CommandBuffer> command_buffer =
230 renderer.GetContext()->CreateCommandBuffer();
231 if (!command_buffer) {
235 "Advanced Blend Filter",
ISize(subpass_coverage.
GetSize()),
237 if (!render_target.
ok()) {
240 if (!renderer.GetContext()
242 ->Submit({std::move(command_buffer)})
249 .
texture = render_target.
value().GetRenderTargetTexture(),
254 .sampler_descriptor = {},
257 : dst_snapshot->opacity) *
258 alpha.value_or(1.0)},
262std::optional<Entity> BlendFilterContents::CreateForegroundAdvancedBlend(
263 const std::shared_ptr<FilterInput>& input,
264 const ContentContext& renderer,
265 const Entity& entity,
266 const Rect& coverage,
267 Color foreground_color,
269 std::optional<Scalar> alpha,
272 input->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
273 if (!dst_snapshot.has_value()) {
277 RenderProc render_proc = [foreground_color, dst_snapshot, blend_mode, alpha,
278 absorb_opacity](
const ContentContext&
renderer,
279 const Entity& entity,
280 RenderPass& pass) ->
bool {
284 auto& host_buffer =
renderer.GetTransientsBuffer();
286 auto size = dst_snapshot->texture->GetSize();
287 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
288 vtx_builder.AddVertices({
289 {{0, 0}, {0, 0}, {0, 0}},
294 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
297 pass.SetCommandLabel(
SPrintF(
"Foreground Advanced Blend Filter (%s)",
300 pass.SetVertexBuffer(std::move(vtx_buffer));
304 switch (blend_mode) {
354 FS::BlendInfo blend_info;
355 VS::FrameInfo frame_info;
357 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
358 if (
renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
362 const std::unique_ptr<const Sampler>& dst_sampler =
363 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
364 dst_sampler_descriptor);
365 FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
366 frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
368 frame_info.mvp = pass.GetOrthographicTransform() * dst_snapshot->transform;
370 blend_info.dst_input_alpha =
372 ? dst_snapshot->opacity * alpha.value_or(1.0)
375 blend_info.color_factor = 1;
376 blend_info.color = foreground_color;
380 FS::BindTextureSamplerSrc(pass, dst_snapshot->texture, dst_sampler);
382 auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
383 FS::BindBlendInfo(pass, blend_uniform);
385 auto uniform_view = host_buffer.EmplaceUniform(frame_info);
386 VS::BindFrameInfo(pass, uniform_view);
388 return pass.Draw().ok();
391 [
coverage](
const Entity& entity) -> std::optional<Rect> {
392 return coverage.TransformBounds(entity.GetTransform());
398 sub_entity.SetContents(std::move(contents));
403std::optional<Entity> BlendFilterContents::CreateForegroundPorterDuffBlend(
404 const std::shared_ptr<FilterInput>& input,
405 const ContentContext& renderer,
406 const Entity& entity,
407 const Rect& coverage,
408 Color foreground_color,
410 std::optional<Scalar> alpha,
417 input->GetSnapshot(
"ForegroundPorterDuffBlend", renderer, entity);
418 if (!dst_snapshot.has_value()) {
426 RenderProc render_proc = [foreground_color, dst_snapshot, blend_mode,
427 absorb_opacity, alpha](
429 const Entity& entity, RenderPass& pass) ->
bool {
433 auto& host_buffer =
renderer.GetTransientsBuffer();
434 auto size = dst_snapshot->texture->GetSize();
435 auto color = foreground_color.Premultiply();
436 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
437 vtx_builder.AddVertices({
438 {{0, 0}, {0, 0},
color},
443 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
446 pass.SetCommandLabel(
SPrintF(
"Foreground PorterDuff Blend Filter (%s)",
449 pass.SetVertexBuffer(std::move(vtx_buffer));
454 FS::FragInfo frag_info;
455 VS::FrameInfo frame_info;
457 frame_info.mvp = pass.GetOrthographicTransform() * dst_snapshot->transform;
459 auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
460 if (
renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
464 const std::unique_ptr<const Sampler>& dst_sampler =
465 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
466 dst_sampler_descriptor);
467 FS::BindTextureSamplerDst(pass, dst_snapshot->texture, dst_sampler);
468 frame_info.texture_sampler_y_coord_scale =
469 dst_snapshot->texture->GetYCoordScale();
471 frag_info.input_alpha =
473 ? dst_snapshot->opacity * alpha.value_or(1.0)
475 frag_info.output_alpha = 1.0;
477 auto blend_coefficients =
479 frag_info.src_coeff = blend_coefficients[0];
480 frag_info.src_coeff_dst_alpha = blend_coefficients[1];
481 frag_info.dst_coeff = blend_coefficients[2];
482 frag_info.dst_coeff_src_alpha = blend_coefficients[3];
483 frag_info.dst_coeff_src_color = blend_coefficients[4];
485 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
486 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
488 return pass.Draw().ok();
492 [
coverage](
const Entity& entity) -> std::optional<Rect> {
493 return coverage.TransformBounds(entity.GetTransform());
499 sub_entity.SetContents(std::move(contents));
508 const Rect& coverage,
510 std::optional<Color> foreground_color,
512 std::optional<Scalar> alpha) {
517 inputs[0]->GetSnapshot(
"PipelineBlend(Dst)", renderer, entity);
518 if (!dst_snapshot.has_value()) {
522 Rect subpass_coverage = coverage;
524 auto coverage_hint = entity.
GetContents()->GetCoverageHint();
526 if (coverage_hint.has_value()) {
527 auto maybe_subpass_coverage =
529 if (!maybe_subpass_coverage.has_value()) {
533 subpass_coverage = *maybe_subpass_coverage;
539 auto& host_buffer = renderer.GetTransientsBuffer();
542 pass.SetCommandLabel(
548 auto add_blend_command = [&](std::optional<Snapshot> input) {
549 if (!input.has_value()) {
552 auto input_coverage = input->GetCoverage();
553 if (!input_coverage.has_value()) {
557 const std::unique_ptr<const Sampler>& sampler =
558 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
559 input->sampler_descriptor);
560 FS::BindTextureSampler(pass, input->texture, sampler);
562 auto size = input->texture->GetSize();
568 {
Point(size.width, size.height),
Point(1, 1)},
572 VS::FrameInfo frame_info;
573 frame_info.mvp = pass.GetOrthographicTransform() *
576 frame_info.texture_sampler_y_coord_scale =
577 input->texture->GetYCoordScale();
579 FS::FragInfo frag_info;
584 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
585 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
587 return pass.Draw().ok();
592 pass.SetPipeline(renderer.GetTexturePipeline(
options));
593 if (!add_blend_command(dst_snapshot)) {
599 if (inputs.size() >= 2) {
600 options.blend_mode = blend_mode;
601 pass.SetPipeline(renderer.GetTexturePipeline(
options));
603 for (
auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
605 auto src_input = texture_i->get()->GetSnapshot(
"PipelineBlend(Src)",
607 if (!add_blend_command(src_input)) {
615 if (foreground_color.has_value()) {
616 auto contents = std::make_shared<SolidColorContents>();
617 contents->SetGeometry(
619 contents->SetColor(foreground_color.value());
624 if (!foreground_entity.
Render(renderer, pass)) {
632 std::shared_ptr<CommandBuffer> command_buffer =
633 renderer.GetContext()->CreateCommandBuffer();
634 if (!command_buffer) {
639 "Pipeline Blend Filter",
ISize(subpass_coverage.
GetSize()),
642 if (!render_target.
ok()) {
646 if (!renderer.GetContext()
648 ->Submit({std::move(command_buffer)})
655 .
texture = render_target.
value().GetRenderTargetTexture(),
660 .sampler_descriptor = {},
663 : dst_snapshot->opacity) *
664 alpha.value_or(1.0)},
668std::optional<Entity> BlendFilterContents::CreateFramebufferAdvancedBlend(
670 const ContentContext& renderer,
671 const Entity& entity,
672 const Rect& coverage,
673 std::optional<Color> foreground_color,
675 std::optional<Scalar> alpha,
679 (inputs.size() == 1u && foreground_color.has_value()));
682 inputs[0]->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
683 if (!dst_snapshot.has_value()) {
692 HostBuffer& host_buffer =
renderer.GetTransientsBuffer();
695 using FS = TextureFillFragmentShader;
696 using VS = TextureFillVertexShader;
698 pass.SetCommandLabel(
"Framebuffer Advanced Blend");
701 pass.SetPipeline(
renderer.GetTexturePipeline(pipeline_options));
703 VS::FrameInfo frame_info;
705 frame_info.texture_sampler_y_coord_scale = 1.0;
707 FS::FragInfo frag_info;
708 frag_info.alpha = 1.0;
710 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
711 vtx_builder.AddVertices({
713 {
Point(1, 0), {1, 0}},
714 {
Point(0, 1), {0, 1}},
715 {
Point(1, 1), {1, 1}},
717 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
718 pass.SetVertexBuffer(std::move(vtx_buffer));
720 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
721 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
722 FS::BindTextureSampler(
723 pass, dst_snapshot->texture,
724 renderer.GetContext()->GetSamplerLibrary()->GetSampler({}));
726 if (!pass.Draw().ok()) {
737 std::shared_ptr<Texture> src_texture;
738 if (foreground_color.has_value()) {
739 TextureDescriptor
desc;
744 renderer.GetContext()->GetResourceAllocator()->CreateTexture(desc);
749 if (!src_texture->SetContents(
750 foreground_color->Premultiply().ToR8G8B8A8().data(), 4u)) {
755 inputs[0]->GetSnapshot(
"ForegroundAdvancedBlend", renderer, entity);
756 if (!src_snapshot.has_value()) {
762 src_texture = src_snapshot->texture;
765 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
766 vtx_builder.AddVertices({
777 pass.SetCommandLabel(
"Framebuffer Advanced Blend Filter");
778 pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer));
780 switch (blend_mode) {
841 VS::FrameInfo frame_info;
842 FS::FragInfo frag_info;
844 auto src_sampler_descriptor = SamplerDescriptor{};
845 if (
renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
849 const std::unique_ptr<const Sampler>& src_sampler =
850 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
851 src_sampler_descriptor);
852 FS::BindTextureSamplerSrc(pass, src_texture, src_sampler);
855 frame_info.src_y_coord_scale = src_texture->GetYCoordScale();
856 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
858 frag_info.src_input_alpha = 1.0;
859 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
861 return pass.Draw().ok();
865 std::shared_ptr<CommandBuffer> cmd_buffer =
866 renderer.GetContext()->CreateCommandBuffer();
868 renderer.MakeSubpass(
"FramebufferBlend", dst_snapshot->texture->GetSize(),
869 cmd_buffer, subpass_callback);
871 if (!render_target.ok()) {
877 ->Submit({std::move(cmd_buffer)})
884 .texture = render_target.value().GetRenderTargetTexture(),
889 .sampler_descriptor = {},
892 : dst_snapshot->opacity) *
893 alpha.value_or(1.0)},
897#define BLEND_CASE(mode) \
898 case BlendMode::k##mode: \
899 advanced_blend_proc_ = \
900 [](const FilterInput::Vector& inputs, const ContentContext& renderer, \
901 const Entity& entity, const Rect& coverage, BlendMode blend_mode, \
902 std::optional<Color> fg_color, \
903 ColorFilterContents::AbsorbOpacity absorb_opacity, \
904 std::optional<Scalar> alpha) { \
905 PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \
906 return AdvancedBlend<Blend##mode##Pipeline>( \
907 inputs, renderer, entity, coverage, blend_mode, fg_color, \
908 absorb_opacity, p, alpha); \
914 VALIDATION_LOG <<
"Invalid blend mode " <<
static_cast<int>(blend_mode)
915 <<
" assigned to BlendFilterContents.";
918 blend_mode_ = blend_mode;
921 switch (blend_mode) {
944 foreground_color_ =
color;
951 const Matrix& effect_transform,
952 const Rect& coverage,
953 const std::optional<Rect>& coverage_hint)
const {
954 if (inputs.empty()) {
958 if (inputs.size() == 1 && !foreground_color_.has_value()) {
965 if (inputs.size() == 1 && foreground_color_.has_value() &&
967 return CreateForegroundPorterDuffBlend(
968 inputs[0], renderer, entity, coverage, foreground_color_.value(),
971 return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_,
976 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
977 return CreateFramebufferAdvancedBlend(inputs, renderer, entity, coverage,
978 foreground_color_, blend_mode_,
981 if (inputs.size() == 1 && foreground_color_.has_value() &&
983 return CreateForegroundAdvancedBlend(
984 inputs[0], renderer, entity, coverage, foreground_color_.value(),
987 return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode_,
static SkBlendMode GetBlendMode(SkSVGFeBlend::Mode mode)
static std::shared_ptr< Contents > Make(RenderProc render_proc, CoverageProc coverage_proc)
~BlendFilterContents() override
void SetBlendMode(BlendMode blend_mode)
std::optional< Entity > RenderFilter(const FilterInput::Vector &inputs, const ContentContext &renderer, const Entity &entity, const Matrix &effect_transform, const Rect &coverage, const std::optional< Rect > &coverage_hint) const override
Converts zero or more filter inputs into a render instruction.
void SetForegroundColor(std::optional< Color > color)
Sets a source color which is blended after all of the inputs have been blended.
std::optional< Scalar > GetAlpha() const
AbsorbOpacity GetAbsorbOpacity() const
std::function< bool(const ContentContext &, RenderPass &)> SubpassCallback
std::function< std::optional< Rect >(const Entity &entity)> CoverageProc
std::function< bool(const ContentContext &renderer, const Entity &entity, RenderPass &pass)> RenderProc
static Entity FromSnapshot(const Snapshot &snapshot, BlendMode blend_mode=BlendMode::kSourceOver)
Create an entity that can be used to render a given snapshot.
const std::shared_ptr< Contents > & GetContents() const
BlendMode GetBlendMode() const
void SetContents(std::shared_ptr< Contents > contents)
void SetBlendMode(BlendMode blend_mode)
static constexpr BlendMode kLastAdvancedBlendMode
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
static constexpr BlendMode kLastPipelineBlendMode
static std::shared_ptr< Geometry > MakeRect(const Rect &rect)
Render passes encode render commands directed as one specific render target into an underlying comman...
VertexShader_ VertexShader
FragmentShader_ FragmentShader
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_UNREACHABLE()
#define FML_DCHECK(condition)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static constexpr Scalar Saturation(Vector3 color)
const char * BlendModeToString(BlendMode blend_mode)
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...
std::string SPrintF(const char *format,...)
constexpr std::array< std::array< Scalar, 5 >, 15 > kPorterDuffCoefficients
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)
std::optional< BlendMode > InvertPorterDuffBlend(BlendMode blend_mode)
std::shared_ptr< Pipeline< PipelineDescriptor > >(ContentContext::*)(ContentContextOptions) const PipelineProc
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)
ContentContextOptions OptionsFromPass(const RenderPass &pass)
static constexpr Scalar Luminosity(Vector3 color)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeOrthographic(TSize< T > size)
static constexpr Matrix MakeTranslation(const Vector3 &t)
Represents a texture and its intended draw transform/sampler configuration.
std::shared_ptr< Texture > texture
constexpr std::optional< TRect > Intersection(const TRect &o) const
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...
static constexpr TRect MakeSize(const TSize< U > &size)
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...