diff --git a/impeller/aiks/canvas_pass.cc b/impeller/aiks/canvas_pass.cc index 09eea3934e645..cd8575f2c60e1 100644 --- a/impeller/aiks/canvas_pass.cc +++ b/impeller/aiks/canvas_pass.cc @@ -5,6 +5,10 @@ #include "impeller/aiks/canvas_pass.h" #include "impeller/entity/content_renderer.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/renderer/command_buffer.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/render_target.h" namespace impeller { @@ -80,10 +84,59 @@ bool CanvasPass::Render(ContentRenderer& renderer, } } for (const auto& subpass : subpasses_) { - if (!subpass->Render(renderer, parent_pass)) { + const auto subpass_coverage = subpass->GetCoverageRect(); + + if (subpass_coverage.IsEmpty()) { + // It is not an error to have an empty subpass. But subpasses that can't + // create their intermediates must trip errors. + continue; + } + + auto context = renderer.GetContext(); + + auto subpass_target = RenderTarget::CreateOffscreen( + *context, ISize::Ceil(subpass_coverage.size)); + + auto sub_command_buffer = context->CreateRenderCommandBuffer(); + + if (!sub_command_buffer) { + return false; + } + + auto sub_renderpass = sub_command_buffer->CreateRenderPass(subpass_target); + + if (!sub_renderpass) { + return false; + } + + if (!subpass) { + return false; + } + + if (!subpass->Render(renderer, *sub_renderpass)) { + return false; + } + + if (!sub_renderpass->EncodeCommands(*context->GetTransientsAllocator())) { + return false; + } + + sub_command_buffer->SubmitCommands(); + + auto offscreen_texture_contents = std::make_shared(); + offscreen_texture_contents->SetTexture( + subpass_target.GetRenderTargetTexture()); + offscreen_texture_contents->SetSourceRect( + IRect::MakeSize(subpass_target.GetRenderTargetTexture()->GetSize())); + + Entity entity; + entity.SetPath(PathBuilder{}.AddRect(subpass_coverage).CreatePath()); + entity.SetContents(std::move(offscreen_texture_contents)); + if (!entity.Render(renderer, parent_pass)) { return false; } } + return true; } diff --git a/impeller/geometry/size.h b/impeller/geometry/size.h index 62f4529b02940..2c24c05456c9a 100644 --- a/impeller/geometry/size.h +++ b/impeller/geometry/size.h @@ -75,6 +75,12 @@ struct TSize { constexpr bool IsEmpty() const { return !IsPositive(); } + template + static constexpr TSize Ceil(const TSize& other) { + return TSize{static_cast(std::ceil(other.width)), + static_cast(std::ceil(other.height))}; + } + constexpr size_t MipCount() const { if (!IsPositive()) { return 1u; diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 5ff8392faa476..803a4bff26f0c 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -69,8 +69,8 @@ static bool ConfigureStencilAttachment( for (const auto& color : colors) { if (!ConfigureColorAttachment(color.second, result.colorAttachments[color.first])) { - FML_LOG(ERROR) << "Could not configure color attachment at index " - << color.first; + FML_DLOG(ERROR) << "Could not configure color attachment at index " + << color.first; return nil; } } @@ -79,6 +79,7 @@ static bool ConfigureStencilAttachment( if (depth.has_value() && !ConfigureDepthAttachment(depth.value(), result.depthAttachment)) { + FML_DLOG(ERROR) << "Could not configure depth attachment."; return nil; } @@ -86,6 +87,7 @@ static bool ConfigureStencilAttachment( if (stencil.has_value() && !ConfigureStencilAttachment(stencil.value(), result.stencilAttachment)) { + FML_DLOG(ERROR) << "Could not configure stencil attachment."; return nil; } diff --git a/impeller/renderer/command_buffer.cc b/impeller/renderer/command_buffer.cc index 9398bc6822ba0..73f4b71c70c0b 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -10,4 +10,8 @@ CommandBuffer::CommandBuffer() = default; CommandBuffer::~CommandBuffer() = default; +void CommandBuffer::SubmitCommands() { + SubmitCommands(nullptr); +} + } // namespace impeller diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index a1240badbfaeb..3c53d917ec5cf 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h @@ -51,6 +51,8 @@ class CommandBuffer { /// virtual void SubmitCommands(CompletionCallback callback) = 0; + void SubmitCommands(); + //---------------------------------------------------------------------------- /// @brief Create a render pass to record render commands into. /// diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index b2710a1f6c917..0fabd12ced91c 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -36,6 +36,14 @@ ISize RenderTarget::GetRenderTargetSize() const { return size.has_value() ? size.value() : ISize{}; } +std::shared_ptr RenderTarget::GetRenderTargetTexture() const { + auto found = colors_.find(0u); + if (found == colors_.end()) { + return nullptr; + } + return found->second.texture; +} + RenderTarget& RenderTarget::SetColorAttachment(ColorAttachment attachment, size_t index) { if (attachment) { @@ -75,10 +83,15 @@ const std::optional& RenderTarget::GetStencilAttachment() RenderTarget RenderTarget::CreateOffscreen(const Context& context, ISize size, std::string label) { + if (size.IsEmpty()) { + return {}; + } + TextureDescriptor color_tex0; color_tex0.format = PixelFormat::kB8G8R8A8UNormInt; color_tex0.size = size; - color_tex0.usage = static_cast(TextureUsage::kRenderTarget); + color_tex0.usage = static_cast(TextureUsage::kRenderTarget) | + static_cast(TextureUsage::kShaderRead); TextureDescriptor stencil_tex0; stencil_tex0.format = PixelFormat::kD32FloatS8UNormInt; diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 66ecf2cc98a7c..9b00c82fbd75c 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -29,6 +29,8 @@ class RenderTarget { ISize GetRenderTargetSize() const; + std::shared_ptr GetRenderTargetTexture() const; + std::optional GetColorAttachmentSize(size_t index) const; RenderTarget& SetColorAttachment(ColorAttachment attachment, size_t index);