From 8d4dac2e0b97e5aa9a7ef053859fa924733d736e Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 27 Apr 2023 17:17:00 -0700 Subject: [PATCH 1/2] [Impeller] Manage the root stencil in EntityPass --- impeller/entity/entity_pass.cc | 78 +++++++++++++------ .../renderer/backend/metal/surface_mtl.mm | 25 ------ .../renderer/backend/vulkan/surface_vk.cc | 24 ------ 3 files changed, 53 insertions(+), 74 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index b7c7050e890eb..78684a3da8b3c 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -214,37 +214,30 @@ uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const { bool EntityPass::Render(ContentContext& renderer, const RenderTarget& render_target) const { - if (render_target.GetColorAttachments().empty()) { - VALIDATION_LOG << "The root RenderTarget must have a color attachment."; - return false; - } - - if (!render_target.GetStencilAttachment().has_value()) { - VALIDATION_LOG << "The root RenderTarget must have a stencil attachment."; - return false; - } + auto root_render_target = render_target; - auto stencil_texture = render_target.GetStencilAttachment()->texture; - if (!stencil_texture) { - VALIDATION_LOG << "The root RenderTarget must have a stencil texture."; + if (root_render_target.GetColorAttachments().empty()) { + VALIDATION_LOG << "The root RenderTarget must have a color attachment."; return false; } StencilCoverageStack stencil_coverage_stack = {StencilCoverageLayer{ - .coverage = Rect::MakeSize(render_target.GetRenderTargetSize()), + .coverage = Rect::MakeSize(root_render_target.GetRenderTargetSize()), .stencil_depth = 0}}; - bool supports_root_pass_reads = + bool supports_onscreen_backdrop_reads = renderer.GetDeviceCapabilities().SupportsReadFromOnscreenTexture() && // If the backend doesn't have `SupportsReadFromResolve`, we need to flip // between two textures when restoring a previous MSAA pass. - renderer.GetDeviceCapabilities().SupportsReadFromResolve() && - stencil_texture->GetTextureDescriptor().storage_mode != - StorageMode::kDeviceTransient; - if (!supports_root_pass_reads && GetTotalPassReads(renderer) > 0) { + renderer.GetDeviceCapabilities().SupportsReadFromResolve(); + bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0; + // In this branch path, we need to render everything to an offscreen texture + // and then blit the results onto the onscreen texture. If using this branch, + // there's no need to set up a stencil attachment on the root render target. + if (!supports_onscreen_backdrop_reads && reads_from_onscreen_backdrop) { auto offscreen_target = - CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true, - clear_color_.Premultiply()); + CreateRenderTarget(renderer, root_render_target.GetRenderTargetSize(), + true, clear_color_.Premultiply()); if (!OnRender(renderer, // renderer offscreen_target.GetRenderTarget() @@ -263,6 +256,9 @@ bool EntityPass::Render(ContentContext& renderer, auto command_buffer = renderer.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); + // If the context supports blitting, blit the offscreen texture to the + // onscreen texture. Otherwise, draw it to the parent texture using a + // pipeline (slower). if (renderer.GetContext() ->GetCapabilities() ->SupportsTextureToTextureBlits()) { @@ -270,7 +266,7 @@ bool EntityPass::Render(ContentContext& renderer, blit_pass->AddCopy( offscreen_target.GetRenderTarget().GetRenderTargetTexture(), - render_target.GetRenderTargetTexture()); + root_render_target.GetRenderTargetTexture()); if (!blit_pass->EncodeCommands( renderer.GetContext()->GetResourceAllocator())) { @@ -278,7 +274,7 @@ bool EntityPass::Render(ContentContext& renderer, return false; } } else { - auto render_pass = command_buffer->CreateRenderPass(render_target); + auto render_pass = command_buffer->CreateRenderPass(root_render_target); render_pass->SetLabel("EntityPass Root Render Pass"); { @@ -309,11 +305,43 @@ bool EntityPass::Render(ContentContext& renderer, return true; } + // If we make it this far, that means the context is capable of rendering + // everything directly to the onscreen texture. + + // The safety check for fetching this color attachment is at the beginning of + // this method. + auto color0 = root_render_target.GetColorAttachments().find(0)->second; + + // If a root stencil was provided by the caller, then verify that it has a + // configuration which can be used to render this pass. + if (root_render_target.GetStencilAttachment().has_value()) { + auto stencil_texture = root_render_target.GetStencilAttachment()->texture; + if (!stencil_texture) { + VALIDATION_LOG << "The root RenderTarget must have a stencil texture."; + return false; + } + + auto stencil_storage_mode = + stencil_texture->GetTextureDescriptor().storage_mode; + if (reads_from_onscreen_backdrop && + stencil_storage_mode == StorageMode::kDeviceTransient) { + VALIDATION_LOG << "The given root RenderTarget stencil needs to be read, " + "but it's marked as transient."; + return false; + } + } + // Setup a new root stencil with an optimal configuration if one wasn't + // provided by the caller. + else { + root_render_target.SetupStencilAttachment( + *renderer.GetContext(), color0.texture->GetSize(), + renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(), + "ImpellerOnscreen", + GetDefaultStencilConfig(reads_from_onscreen_backdrop)); + } + // Set up the clear color of the root pass. - auto color0 = render_target.GetColorAttachments().find(0)->second; color0.clear_color = clear_color_.Premultiply(); - - auto root_render_target = render_target; root_render_target.SetColorAttachment(color0, 0); EntityPassTarget pass_target( diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index 018d0afacb8be..92c075176fca2 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -108,33 +108,8 @@ color0.store_action = StoreAction::kMultisampleResolve; color0.resolve_texture = resolve_tex; - TextureDescriptor stencil_tex_desc; - stencil_tex_desc.storage_mode = StorageMode::kDevicePrivate; - stencil_tex_desc.type = TextureType::kTexture2DMultisample; - stencil_tex_desc.sample_count = SampleCount::kCount4; - stencil_tex_desc.format = - context->GetCapabilities()->GetDefaultStencilFormat(); - stencil_tex_desc.size = msaa_tex_desc.size; - stencil_tex_desc.usage = - static_cast(TextureUsage::kRenderTarget); - auto stencil_tex = - context->GetResourceAllocator()->CreateTexture(stencil_tex_desc); - - if (!stencil_tex) { - VALIDATION_LOG << "Could not create stencil texture."; - return nullptr; - } - stencil_tex->SetLabel("ImpellerOnscreenStencil"); - - StencilAttachment stencil0; - stencil0.texture = stencil_tex; - stencil0.clear_stencil = 0; - stencil0.load_action = LoadAction::kClear; - stencil0.store_action = StoreAction::kDontCare; - RenderTarget render_target_desc; render_target_desc.SetColorAttachment(color0, 0u); - render_target_desc.SetStencilAttachment(stencil0); // The constructor is private. So make_unique may not be used. return std::unique_ptr( diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index 721b2fe75790a..3f1006e331fd6 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -60,32 +60,8 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( color0.store_action = StoreAction::kMultisampleResolve; color0.resolve_texture = resolve_tex; - TextureDescriptor stencil0_tex; - stencil0_tex.storage_mode = StorageMode::kDevicePrivate; - stencil0_tex.type = TextureType::kTexture2DMultisample; - stencil0_tex.sample_count = SampleCount::kCount4; - stencil0_tex.format = context->GetCapabilities()->GetDefaultStencilFormat(); - stencil0_tex.size = msaa_tex_desc.size; - stencil0_tex.usage = - static_cast(TextureUsage::kRenderTarget); - - auto stencil_tex = - context->GetResourceAllocator()->CreateTexture(stencil0_tex); - if (!stencil_tex) { - VALIDATION_LOG << "Could not create stencil texture."; - return nullptr; - } - stencil_tex->SetLabel("ImpellerOnscreenStencil"); - - StencilAttachment stencil0; - stencil0.texture = stencil_tex; - stencil0.clear_stencil = 0; - stencil0.load_action = LoadAction::kClear; - stencil0.store_action = StoreAction::kDontCare; - RenderTarget render_target_desc; render_target_desc.SetColorAttachment(color0, 0u); - render_target_desc.SetStencilAttachment(stencil0); // The constructor is private. So make_unique may not be used. return std::unique_ptr( From dd17275de923ca38c5d8a2f895d1a31980f734a4 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 27 Apr 2023 19:41:24 -0700 Subject: [PATCH 2/2] When rendering a picture snapshot, allow EntityPass to make the stencil --- impeller/aiks/picture.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 7c810119fc264..2f696a104c301 100644 --- a/impeller/aiks/picture.cc +++ b/impeller/aiks/picture.cc @@ -56,9 +56,22 @@ std::shared_ptr Picture::RenderToTexture( auto impeller_context = context.GetContext(); RenderTarget target; if (impeller_context->GetCapabilities()->SupportsOffscreenMSAA()) { - target = RenderTarget::CreateOffscreenMSAA(*impeller_context, size); + target = RenderTarget::CreateOffscreenMSAA( + *impeller_context, // context + size, // size + "Picture Snapshot MSAA", // label + RenderTarget:: + kDefaultColorAttachmentConfigMSAA, // color_attachment_config + std::nullopt // stencil_attachment_config + ); } else { - target = RenderTarget::CreateOffscreen(*impeller_context, size); + target = RenderTarget::CreateOffscreen( + *impeller_context, // context + size, // size + "Picture Snapshot", // label + RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config + std::nullopt // stencil_attachment_config + ); } if (!target.IsValid()) { VALIDATION_LOG << "Could not create valid RenderTarget.";