blob: 6e8adafbec76ab89b669686c99a828b808619c5d [file] [log] [blame]
// 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"
#include "impeller/renderer/sampler_library.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 = pass.GetTransientsBuffer();
auto src_snapshot = child_contents_->RenderToSnapshot(
renderer, // renderer
entity, // entity
Rect::MakeSize(pass.GetRenderTargetSize()), // coverage_limit
std::nullopt, // sampler_descriptor
true, // msaa_enabled
"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 maybe_src_uvs = src_snapshot->GetCoverageUVs(src_coverage);
if (!maybe_src_uvs.has_value()) {
return true;
}
std::array<Point, 4> src_uvs = maybe_src_uvs.value();
auto size = src_coverage.size;
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), src_uvs[0]},
{Point(size.width, 0), src_uvs[1]},
{Point(size.width, size.height), src_uvs[3]},
{Point(0, 0), src_uvs[0]},
{Point(size.width, size.height), src_uvs[3]},
{Point(0, size.height), src_uvs[2]},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
auto options = OptionsFromPass(pass);
options.blend_mode = BlendMode::kSource;
Command cmd;
cmd.label = "Framebuffer Advanced Blend Filter";
cmd.BindVertices(vtx_buffer);
cmd.stencil_reference = entity.GetStencilDepth();
switch (blend_mode_) {
case BlendMode::kScreen:
cmd.pipeline = renderer.GetFramebufferBlendScreenPipeline(options);
break;
case BlendMode::kOverlay:
cmd.pipeline = renderer.GetFramebufferBlendOverlayPipeline(options);
break;
case BlendMode::kDarken:
cmd.pipeline = renderer.GetFramebufferBlendDarkenPipeline(options);
break;
case BlendMode::kLighten:
cmd.pipeline = renderer.GetFramebufferBlendLightenPipeline(options);
break;
case BlendMode::kColorDodge:
cmd.pipeline = renderer.GetFramebufferBlendColorDodgePipeline(options);
break;
case BlendMode::kColorBurn:
cmd.pipeline = renderer.GetFramebufferBlendColorBurnPipeline(options);
break;
case BlendMode::kHardLight:
cmd.pipeline = renderer.GetFramebufferBlendHardLightPipeline(options);
break;
case BlendMode::kSoftLight:
cmd.pipeline = renderer.GetFramebufferBlendSoftLightPipeline(options);
break;
case BlendMode::kDifference:
cmd.pipeline = renderer.GetFramebufferBlendDifferencePipeline(options);
break;
case BlendMode::kExclusion:
cmd.pipeline = renderer.GetFramebufferBlendExclusionPipeline(options);
break;
case BlendMode::kMultiply:
cmd.pipeline = renderer.GetFramebufferBlendMultiplyPipeline(options);
break;
case BlendMode::kHue:
cmd.pipeline = renderer.GetFramebufferBlendHuePipeline(options);
break;
case BlendMode::kSaturation:
cmd.pipeline = renderer.GetFramebufferBlendSaturationPipeline(options);
break;
case BlendMode::kColor:
cmd.pipeline = renderer.GetFramebufferBlendColorPipeline(options);
break;
case BlendMode::kLuminosity:
cmd.pipeline = 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().SupportsDecalTileMode()) {
// No known devices that support framebuffer fetch but not decal tile mode.
return false;
}
src_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
src_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
auto src_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
src_sampler_descriptor);
FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, src_sampler);
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
src_snapshot->transform;
frame_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale();
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
frag_info.src_input_alpha = src_snapshot->opacity;
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
return pass.AddCommand(cmd);
}
} // namespace impeller