Skip to content

Commit

Permalink
Make the filter DAG render all textures at the correct resolution (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdero authored and dnfield committed Apr 27, 2022
1 parent 32b5a8d commit 39f4ebd
Show file tree
Hide file tree
Showing 22 changed files with 609 additions and 246 deletions.
1 change: 1 addition & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ TEST_F(AiksTest, TransformMultipliesCorrectly) {
-3, 0, 0, 0,
0, 0, 0, 0,
-500, 400, 0, 1));
// clang-format on
}

} // namespace testing
Expand Down
77 changes: 77 additions & 0 deletions impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
// found in the LICENSE file.

#include "impeller/entity/contents/contents.h"
#include <optional>

#include "impeller/entity/contents/content_context.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/render_pass.h"

namespace impeller {
Expand All @@ -27,4 +29,79 @@ Contents::Contents() = default;

Contents::~Contents() = default;

Rect Contents::GetBounds(const Entity& entity) const {
const auto& transform = entity.GetTransformation();
auto points = entity.GetPath().GetBoundingBox()->GetPoints();
for (uint i = 0; i < points.size(); i++) {
points[i] = transform * points[i];
}
return Rect::MakePointBounds({points.begin(), points.end()});
}

std::optional<Contents::Snapshot> Contents::RenderToTexture(
const ContentContext& renderer,
const Entity& entity) const {
auto bounds = GetBounds(entity);

auto texture = MakeSubpass(
renderer, ISize(bounds.size),
[&contents = *this, &entity, &bounds](const ContentContext& renderer,
RenderPass& pass) -> bool {
Entity sub_entity;
sub_entity.SetPath(entity.GetPath());
sub_entity.SetBlendMode(Entity::BlendMode::kSource);
sub_entity.SetTransformation(
Matrix::MakeTranslation(Vector3(-bounds.origin)) *
entity.GetTransformation());
return contents.Render(renderer, sub_entity, pass);
});

if (!texture.has_value()) {
return std::nullopt;
}

return Snapshot{.texture = texture.value(), .position = bounds.origin};
}

using SubpassCallback = std::function<bool(const ContentContext&, RenderPass&)>;

std::optional<std::shared_ptr<Texture>> Contents::MakeSubpass(
const ContentContext& renderer,
ISize texture_size,
SubpassCallback subpass_callback) {
auto context = renderer.GetContext();

auto subpass_target = RenderTarget::CreateOffscreen(*context, texture_size);
auto subpass_texture = subpass_target.GetRenderTargetTexture();
if (!subpass_texture) {
return std::nullopt;
}

auto sub_command_buffer = context->CreateRenderCommandBuffer();
sub_command_buffer->SetLabel("Offscreen Contents Command Buffer");
if (!sub_command_buffer) {
return std::nullopt;
}

auto sub_renderpass = sub_command_buffer->CreateRenderPass(subpass_target);
if (!sub_renderpass) {
return std::nullopt;
}
sub_renderpass->SetLabel("OffscreenContentsPass");

if (!subpass_callback(renderer, *sub_renderpass)) {
return std::nullopt;
}

if (!sub_renderpass->EncodeCommands(*context->GetTransientsAllocator())) {
return std::nullopt;
}

if (!sub_command_buffer->SubmitCommands()) {
return std::nullopt;
}

return subpass_texture;
}

} // namespace impeller
30 changes: 30 additions & 0 deletions impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <vector>

#include "flutter/fml/macros.h"
#include "impeller/geometry/rect.h"
#include "impeller/renderer/texture.h"

namespace impeller {

Expand All @@ -25,6 +27,14 @@ ContentContextOptions OptionsFromPassAndEntity(const RenderPass& pass,

class Contents {
public:
/// Represents a screen space texture and it's intended draw position.
struct Snapshot {
std::shared_ptr<Texture> texture;
/// The offset from the origin where this texture is intended to be
/// rendered.
Vector2 position;
};

Contents();

virtual ~Contents();
Expand All @@ -33,6 +43,26 @@ class Contents {
const Entity& entity,
RenderPass& pass) const = 0;

/// @brief Get the bounding rectangle that this contents modifies in screen
/// space.
virtual Rect GetBounds(const Entity& entity) const;

/// @brief Render this contents to a texture, respecting the entity's
/// transform, path, stencil depth, blend mode, etc.
/// The result texture size is always the size of `GetBounds(entity)`.
virtual std::optional<Snapshot> RenderToTexture(
const ContentContext& renderer,
const Entity& entity) const;

using SubpassCallback =
std::function<bool(const ContentContext&, RenderPass&)>;
static std::optional<std::shared_ptr<Texture>> MakeSubpass(
const ContentContext& renderer,
ISize texture_size,
SubpassCallback subpass_callback);

protected:

private:
FML_DISALLOW_COPY_AND_ASSIGN(Contents);
};
Expand Down
125 changes: 73 additions & 52 deletions impeller/entity/contents/filters/blend_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,28 @@ using PipelineProc =
std::shared_ptr<Pipeline> (ContentContext::*)(ContentContextOptions) const;

template <typename VS, typename FS>
static void AdvancedBlendPass(std::shared_ptr<Texture> input_d,
std::shared_ptr<Texture> input_s,
std::shared_ptr<const Sampler> sampler,
const ContentContext& renderer,
RenderPass& pass,
Command& cmd) {}

template <typename VS, typename FS>
static bool AdvancedBlend(
const std::vector<std::shared_ptr<Texture>>& input_textures,
const ContentContext& renderer,
RenderPass& pass,
PipelineProc pipeline_proc) {
static bool AdvancedBlend(const std::vector<Contents::Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass,
PipelineProc pipeline_proc) {
if (input_textures.size() < 2) {
return false;
}

auto& host_buffer = pass.GetTransientsBuffer();

auto size = pass.GetRenderTargetSize();
VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), Point(0, 0)},
{Point(1, 0), Point(1, 0)},
{Point(1, 1), Point(1, 1)},
{Point(size.width, 0), Point(1, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, 0), Point(0, 0)},
{Point(1, 1), Point(1, 1)},
{Point(0, 1), Point(0, 1)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, size.height), Point(0, 1)},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);

typename VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});

auto options = OptionsFromPass(pass);
options.blend_mode = Entity::BlendMode::kSource;
std::shared_ptr<Pipeline> pipeline =
Expand All @@ -65,10 +51,27 @@ static bool AdvancedBlend(
cmd.label = "Advanced Blend Filter";
cmd.BindVertices(vtx_buffer);
cmd.pipeline = std::move(pipeline);
VS::BindFrameInfo(cmd, uniform_view);

FS::BindTextureSamplerDst(cmd, input_textures[0], sampler);
FS::BindTextureSamplerSrc(cmd, input_textures[1], sampler);
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
typename VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(size);

auto dst_snapshot = input_textures[1];
FS::BindTextureSamplerSrc(cmd, dst_snapshot.texture, sampler);
frame_info.dst_uv_transform =
Matrix::MakeTranslation(-dst_snapshot.position / size) *
Matrix::MakeScale(
Vector3(Size(size) / Size(dst_snapshot.texture->GetSize())));

auto src_snapshot = input_textures[0];
FS::BindTextureSamplerDst(cmd, src_snapshot.texture, sampler);
frame_info.src_uv_transform =
Matrix::MakeTranslation(-src_snapshot.position / size) *
Matrix::MakeScale(
Vector3(Size(size) / Size(src_snapshot.texture->GetSize())));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);
pass.AddCommand(cmd);

return true;
Expand All @@ -88,46 +91,42 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {

switch (blend_mode) {
case Entity::BlendMode::kScreen:
advanced_blend_proc_ =
[](const std::vector<std::shared_ptr<Texture>>& input_textures,
const ContentContext& renderer, RenderPass& pass) {
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
TextureBlendScreenPipeline::FragmentShader>(
input_textures, renderer, pass, p);
};
advanced_blend_proc_ = [](const std::vector<Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass) {
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
TextureBlendScreenPipeline::FragmentShader>(
input_textures, renderer, pass, p);
};
break;
default:
FML_UNREACHABLE();
}
}
}

static bool BasicBlend(
const std::vector<std::shared_ptr<Texture>>& input_textures,
const ContentContext& renderer,
RenderPass& pass,
Entity::BlendMode basic_blend) {
static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass,
Entity::BlendMode basic_blend) {
using VS = TextureBlendPipeline::VertexShader;
using FS = TextureBlendPipeline::FragmentShader;

auto& host_buffer = pass.GetTransientsBuffer();

auto size = pass.GetRenderTargetSize();
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), Point(0, 0)},
{Point(1, 0), Point(1, 0)},
{Point(1, 1), Point(1, 1)},
{Point(size.width, 0), Point(1, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, 0), Point(0, 0)},
{Point(1, 1), Point(1, 1)},
{Point(0, 1), Point(0, 1)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, size.height), Point(0, 1)},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);

VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});

// Draw the first texture using kSource.
Expand All @@ -138,8 +137,19 @@ static bool BasicBlend(
auto options = OptionsFromPass(pass);
options.blend_mode = Entity::BlendMode::kSource;
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
FS::BindTextureSamplerSrc(cmd, input_textures[0], sampler);
VS::BindFrameInfo(cmd, uniform_view);
{
auto input = input_textures[0];
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);

VS::FrameInfo frame_info;
frame_info.mvp =
Matrix::MakeOrthographic(size) *
Matrix::MakeTranslation(input.position) *
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);
}
pass.AddCommand(cmd);

if (input_textures.size() < 2) {
Expand All @@ -153,17 +163,28 @@ static bool BasicBlend(

for (auto texture_i = input_textures.begin() + 1;
texture_i < input_textures.end(); texture_i++) {
FS::BindTextureSamplerSrc(cmd, *texture_i, sampler);
auto input = *texture_i;
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);

VS::FrameInfo frame_info;
frame_info.mvp = frame_info.mvp =
Matrix::MakeOrthographic(size) *
Matrix::MakeTranslation(input.position) *
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);
pass.AddCommand(cmd);
}

return true;
}

bool BlendFilterContents::RenderFilter(
const std::vector<std::shared_ptr<Texture>>& input_textures,
const std::vector<Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass) const {
RenderPass& pass,
const Matrix& transform) const {
if (input_textures.empty()) {
return true;
}
Expand Down
13 changes: 7 additions & 6 deletions impeller/entity/contents/filters/blend_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ namespace impeller {

class BlendFilterContents : public FilterContents {
public:
using AdvancedBlendProc = std::function<bool(
const std::vector<std::shared_ptr<Texture>>& input_textures,
const ContentContext& renderer,
RenderPass& pass)>;
using AdvancedBlendProc =
std::function<bool(const std::vector<Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass)>;

BlendFilterContents();

Expand All @@ -23,9 +23,10 @@ class BlendFilterContents : public FilterContents {

private:
// |FilterContents|
bool RenderFilter(const std::vector<std::shared_ptr<Texture>>& input_textures,
bool RenderFilter(const std::vector<Snapshot>& input_textures,
const ContentContext& renderer,
RenderPass& pass) const override;
RenderPass& pass,
const Matrix& transform) const override;

Entity::BlendMode blend_mode_;
AdvancedBlendProc advanced_blend_proc_;
Expand Down
Loading

0 comments on commit 39f4ebd

Please sign in to comment.