| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "framebuffer_blend_contents.h" |
| |
| #include "impeller/entity/contents/content_context.h" |
| #include "impeller/renderer/render_pass.h" |
| |
| namespace impeller { |
| |
| FramebufferBlendContents::FramebufferBlendContents() = default; |
| |
| FramebufferBlendContents::~FramebufferBlendContents() = default; |
| |
| void FramebufferBlendContents::SetBlendMode(BlendMode blend_mode) { |
| blend_mode_ = blend_mode; |
| } |
| |
| void FramebufferBlendContents::SetChildContents( |
| std::shared_ptr<Contents> child_contents) { |
| child_contents_ = std::move(child_contents); |
| } |
| |
| // |Contents| |
| std::optional<Rect> FramebufferBlendContents::GetCoverage( |
| const Entity& entity) const { |
| return child_contents_->GetCoverage(entity); |
| } |
| |
| bool FramebufferBlendContents::Render(const ContentContext& renderer, |
| const Entity& entity, |
| RenderPass& pass) const { |
| if (!renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) { |
| return false; |
| } |
| |
| using VS = FramebufferBlendScreenPipeline::VertexShader; |
| using FS = FramebufferBlendScreenPipeline::FragmentShader; |
| |
| auto& host_buffer = renderer.GetTransientsBuffer(); |
| |
| auto src_snapshot = child_contents_->RenderToSnapshot( |
| renderer, // renderer |
| entity, // entity |
| Rect::MakeSize(pass.GetRenderTargetSize()), // coverage_limit |
| std::nullopt, // sampler_descriptor |
| true, // msaa_enabled |
| /*mip_count=*/1, |
| "FramebufferBlendContents Snapshot"); // label |
| |
| if (!src_snapshot.has_value()) { |
| return true; |
| } |
| auto coverage = src_snapshot->GetCoverage(); |
| if (!coverage.has_value()) { |
| return true; |
| } |
| Rect src_coverage = coverage.value(); |
| |
| auto size = src_coverage.GetSize(); |
| VertexBufferBuilder<VS::PerVertexData> vtx_builder; |
| vtx_builder.AddVertices({ |
| {Point(0, 0), Point(0, 0)}, |
| {Point(size.width, 0), Point(1, 0)}, |
| {Point(0, size.height), Point(0, 1)}, |
| {Point(size.width, size.height), Point(1, 1)}, |
| }); |
| |
| auto options = OptionsFromPass(pass); |
| options.blend_mode = BlendMode::kSource; |
| options.primitive_type = PrimitiveType::kTriangleStrip; |
| |
| pass.SetCommandLabel("Framebuffer Advanced Blend Filter"); |
| pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer)); |
| pass.SetStencilReference(entity.GetClipDepth()); |
| |
| switch (blend_mode_) { |
| case BlendMode::kScreen: |
| pass.SetPipeline(renderer.GetFramebufferBlendScreenPipeline(options)); |
| break; |
| case BlendMode::kOverlay: |
| pass.SetPipeline(renderer.GetFramebufferBlendOverlayPipeline(options)); |
| break; |
| case BlendMode::kDarken: |
| pass.SetPipeline(renderer.GetFramebufferBlendDarkenPipeline(options)); |
| break; |
| case BlendMode::kLighten: |
| pass.SetPipeline(renderer.GetFramebufferBlendLightenPipeline(options)); |
| break; |
| case BlendMode::kColorDodge: |
| pass.SetPipeline(renderer.GetFramebufferBlendColorDodgePipeline(options)); |
| break; |
| case BlendMode::kColorBurn: |
| pass.SetPipeline(renderer.GetFramebufferBlendColorBurnPipeline(options)); |
| break; |
| case BlendMode::kHardLight: |
| pass.SetPipeline(renderer.GetFramebufferBlendHardLightPipeline(options)); |
| break; |
| case BlendMode::kSoftLight: |
| pass.SetPipeline(renderer.GetFramebufferBlendSoftLightPipeline(options)); |
| break; |
| case BlendMode::kDifference: |
| pass.SetPipeline(renderer.GetFramebufferBlendDifferencePipeline(options)); |
| break; |
| case BlendMode::kExclusion: |
| pass.SetPipeline(renderer.GetFramebufferBlendExclusionPipeline(options)); |
| break; |
| case BlendMode::kMultiply: |
| pass.SetPipeline(renderer.GetFramebufferBlendMultiplyPipeline(options)); |
| break; |
| case BlendMode::kHue: |
| pass.SetPipeline(renderer.GetFramebufferBlendHuePipeline(options)); |
| break; |
| case BlendMode::kSaturation: |
| pass.SetPipeline(renderer.GetFramebufferBlendSaturationPipeline(options)); |
| break; |
| case BlendMode::kColor: |
| pass.SetPipeline(renderer.GetFramebufferBlendColorPipeline(options)); |
| break; |
| case BlendMode::kPlusAdvanced: |
| pass.SetPipeline( |
| renderer.GetFramebufferBlendPlusAdvancedPipeline(options)); |
| break; |
| case BlendMode::kLuminosity: |
| pass.SetPipeline(renderer.GetFramebufferBlendLuminosityPipeline(options)); |
| break; |
| default: |
| return false; |
| } |
| |
| VS::FrameInfo frame_info; |
| FS::FragInfo frag_info; |
| |
| auto src_sampler_descriptor = src_snapshot->sampler_descriptor; |
| if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) { |
| src_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; |
| src_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; |
| } |
| const std::unique_ptr<const Sampler>& src_sampler = |
| renderer.GetContext()->GetSamplerLibrary()->GetSampler( |
| src_sampler_descriptor); |
| FS::BindTextureSamplerSrc(pass, src_snapshot->texture, src_sampler); |
| |
| frame_info.mvp = Entity::GetShaderTransform(entity.GetShaderClipDepth(), pass, |
| src_snapshot->transform); |
| frame_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale(); |
| VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); |
| |
| frag_info.src_input_alpha = src_snapshot->opacity; |
| FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); |
| |
| return pass.Draw().ok(); |
| } |
| |
| } // namespace impeller |