diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index dc3e6433645c7..725f5406ea764 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1193,6 +1193,8 @@ ORIGIN: ../../../flutter/impeller/entity/entity_pass.cc + ../../../flutter/LICEN ORIGIN: ../../../flutter/impeller/entity/entity_pass.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_pass_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_pass_delegate.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry.cc + ../../../flutter/LICENSE @@ -3726,6 +3728,8 @@ FILE: ../../../flutter/impeller/entity/entity_pass.cc FILE: ../../../flutter/impeller/entity/entity_pass.h FILE: ../../../flutter/impeller/entity/entity_pass_delegate.cc FILE: ../../../flutter/impeller/entity/entity_pass_delegate.h +FILE: ../../../flutter/impeller/entity/entity_pass_target.cc +FILE: ../../../flutter/impeller/entity/entity_pass_target.h FILE: ../../../flutter/impeller/entity/entity_playground.cc FILE: ../../../flutter/impeller/entity/entity_playground.h FILE: ../../../flutter/impeller/entity/geometry.cc diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index bf8ce3db73bc0..a5447768a9951 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -206,6 +206,8 @@ impeller_component("entity") { "entity_pass.h", "entity_pass_delegate.cc", "entity_pass_delegate.h", + "entity_pass_target.cc", + "entity_pass_target.h", "geometry.cc", "geometry.h", "inline_pass_context.cc", diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 2a1611c734b9f..fd58aca0677ef 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -142,9 +142,9 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { return subpass_pointer; } -static RenderTarget CreateRenderTarget(ContentContext& renderer, - ISize size, - bool readable) { +static EntityPassTarget CreateRenderTarget(ContentContext& renderer, + ISize size, + bool readable) { auto context = renderer.GetContext(); /// All of the load/store actions are managed by `InlinePassContext` when @@ -152,8 +152,9 @@ static RenderTarget CreateRenderTarget(ContentContext& renderer, /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. + RenderTarget target; if (context->GetDeviceCapabilities().SupportsOffscreenMSAA()) { - return RenderTarget::CreateOffscreenMSAA( + target = RenderTarget::CreateOffscreenMSAA( *context, // context size, // size "EntityPass", // label @@ -170,24 +171,27 @@ static RenderTarget CreateRenderTarget(ContentContext& renderer, .store_action = StoreAction::kDontCare, } // stencil_attachment_config ); + } else { + target = RenderTarget::CreateOffscreen( + *context, // context + size, // size + "EntityPass", // label + RenderTarget::AttachmentConfig{ + .storage_mode = StorageMode::kDevicePrivate, + .load_action = LoadAction::kDontCare, + .store_action = StoreAction::kDontCare, + }, // color_attachment_config + RenderTarget::AttachmentConfig{ + .storage_mode = readable ? StorageMode::kDevicePrivate + : StorageMode::kDeviceTransient, + .load_action = LoadAction::kDontCare, + .store_action = StoreAction::kDontCare, + } // stencil_attachment_config + ); } - return RenderTarget::CreateOffscreen( - *context, // context - size, // size - "EntityPass", // label - RenderTarget::AttachmentConfig{ - .storage_mode = StorageMode::kDevicePrivate, - .load_action = LoadAction::kDontCare, - .store_action = StoreAction::kDontCare, - }, // color_attachment_config - RenderTarget::AttachmentConfig{ - .storage_mode = readable ? StorageMode::kDevicePrivate - : StorageMode::kDeviceTransient, - .load_action = LoadAction::kDontCare, - .store_action = StoreAction::kDontCare, - } // stencil_attachment_config - ); + return EntityPassTarget( + target, renderer.GetDeviceCapabilities().SupportsReadFromResolve()); } uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const { @@ -202,7 +206,8 @@ bool EntityPass::Render(ContentContext& renderer, if (GetTotalPassReads(renderer) > 0) { auto offscreen_target = CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true); - if (!OnRender(renderer, offscreen_target.GetRenderTargetSize(), + if (!OnRender(renderer, + offscreen_target.GetRenderTarget().GetRenderTargetSize(), offscreen_target, Point(), Point(), 0)) { return false; } @@ -215,8 +220,9 @@ bool EntityPass::Render(ContentContext& renderer, .SupportsTextureToTextureBlits()) { auto blit_pass = command_buffer->CreateBlitPass(); - blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(), - render_target.GetRenderTargetTexture()); + blit_pass->AddCopy( + offscreen_target.GetRenderTarget().GetRenderTargetTexture(), + render_target.GetRenderTargetTexture()); if (!blit_pass->EncodeCommands( renderer.GetContext()->GetResourceAllocator())) { @@ -227,9 +233,11 @@ bool EntityPass::Render(ContentContext& renderer, render_pass->SetLabel("EntityPass Root Render Pass"); { - auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize()); + auto size_rect = Rect::MakeSize( + offscreen_target.GetRenderTarget().GetRenderTargetSize()); auto contents = TextureContents::MakeRect(size_rect); - contents->SetTexture(offscreen_target.GetRenderTargetTexture()); + contents->SetTexture( + offscreen_target.GetRenderTarget().GetRenderTargetTexture()); contents->SetSourceRect(size_rect); Entity entity; @@ -250,7 +258,11 @@ bool EntityPass::Render(ContentContext& renderer, return true; } - return OnRender(renderer, render_target.GetRenderTargetSize(), render_target, + EntityPassTarget pass_target( + render_target, + renderer.GetDeviceCapabilities().SupportsReadFromResolve()); + + return OnRender(renderer, render_target.GetRenderTargetSize(), pass_target, Point(), Point(), 0); } @@ -296,7 +308,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( subpass->delegate_->CanCollapseIntoParentPass(subpass)) { // Directly render into the parent target and move on. if (!subpass->OnRender(renderer, root_pass_size, - pass_context.GetRenderTarget(), position, position, + pass_context.GetPassTarget(), position, position, pass_depth, stencil_depth_, nullptr, pass_context.GetRenderPass(pass_depth))) { return EntityPass::EntityResult::Failure(); @@ -322,8 +334,9 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto subpass_coverage = GetSubpassCoverage(*subpass, Rect::MakeSize(root_pass_size)); if (subpass->cover_whole_screen_) { - subpass_coverage = Rect( - position, Size(pass_context.GetRenderTarget().GetRenderTargetSize())); + subpass_coverage = Rect(position, Size(pass_context.GetPassTarget() + .GetRenderTarget() + .GetRenderTargetSize())); } if (backdrop_filter_contents) { auto backdrop_coverage = backdrop_filter_contents->GetCoverage(Entity{}); @@ -350,7 +363,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( ISize(subpass_coverage->size), // subpass->GetTotalPassReads(renderer) > 0); - auto subpass_texture = subpass_target.GetRenderTargetTexture(); + auto subpass_texture = + subpass_target.GetRenderTarget().GetRenderTargetTexture(); if (!subpass_texture) { return EntityPass::EntityResult::Failure(); @@ -400,7 +414,7 @@ struct StencilLayer { bool EntityPass::OnRender(ContentContext& renderer, ISize root_pass_size, - const RenderTarget& render_target, + EntityPassTarget& pass_target, Point position, Point parent_position, uint32_t pass_depth, @@ -411,7 +425,7 @@ bool EntityPass::OnRender(ContentContext& renderer, TRACE_EVENT0("impeller", "EntityPass::OnRender"); auto context = renderer.GetContext(); - InlinePassContext pass_context(context, render_target, + InlinePassContext pass_context(context, pass_target, GetTotalPassReads(renderer), std::move(collapsed_parent_pass)); if (!pass_context.IsValid()) { @@ -419,7 +433,8 @@ bool EntityPass::OnRender(ContentContext& renderer, } std::vector stencil_stack = {StencilLayer{ - .coverage = Rect::MakeSize(render_target.GetRenderTargetSize()), + .coverage = + Rect::MakeSize(pass_target.GetRenderTarget().GetRenderTargetSize()), .stencil_depth = stencil_depth_floor}}; auto render_element = [&stencil_depth_floor, &pass_context, &pass_depth, @@ -433,6 +448,8 @@ bool EntityPass::OnRender(ContentContext& renderer, // If the pass context returns a texture, we need to draw it to the current // pass. We do this because it's faster and takes significantly less memory // than storing/loading large MSAA textures. + // Also, it's not possible to blit the non-MSAA resolve texture of the + // previous pass to MSAA textures (let alone a transient one). if (result.backdrop_texture) { auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize()); auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect); diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 8a12f44c8bbfd..1e844aa7f11cf 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -16,6 +16,7 @@ #include "impeller/entity/entity_pass_delegate.h" #include "impeller/entity/inline_pass_context.h" #include "impeller/renderer/render_target.h" +#include "impeller/renderer/texture.h" #include "impeller/typographer/lazy_glyph_atlas.h" namespace impeller { @@ -111,7 +112,7 @@ class EntityPass { bool OnRender(ContentContext& renderer, ISize root_pass_size, - const RenderTarget& render_target, + EntityPassTarget& render_target, Point position, Point parent_position, uint32_t pass_depth, diff --git a/impeller/entity/entity_pass_target.cc b/impeller/entity/entity_pass_target.cc new file mode 100644 index 0000000000000..a67345ad50893 --- /dev/null +++ b/impeller/entity/entity_pass_target.cc @@ -0,0 +1,55 @@ +// 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 "impeller/entity/entity_pass_target.h" + +#include "impeller/renderer/texture.h" + +namespace impeller { + +EntityPassTarget::EntityPassTarget(const RenderTarget& render_target, + bool supports_read_from_resolve) + : target_(render_target), + supports_read_from_resolve_(supports_read_from_resolve) {} + +std::shared_ptr EntityPassTarget::Flip(Allocator& allocator) { + auto color0 = target_.GetColorAttachments().find(0)->second; + + if (supports_read_from_resolve_ && color0.resolve_texture) { + // Just return the current resolve texture, which is safe to read in the + // next render pass that'll resolve to `target_`. + // + // Note that this can only be done when MSAA is being used. + return color0.resolve_texture; + } + + if (!secondary_color_texture_) { + // The second texture is allocated lazily to avoid unused allocations. + TextureDescriptor new_descriptor = color0.texture->GetTextureDescriptor(); + secondary_color_texture_ = allocator.CreateTexture(new_descriptor); + + if (!secondary_color_texture_) { + return nullptr; + } + } + + std::swap(color0.resolve_texture ? color0.resolve_texture : color0.texture, + secondary_color_texture_); + + target_.SetColorAttachment(color0, 0); + + // Return the previous backdrop texture, which is safe to read in the next + // render pass that attaches `target_`. + return secondary_color_texture_; +} + +const RenderTarget& EntityPassTarget::GetRenderTarget() const { + return target_; +} + +bool EntityPassTarget::IsValid() const { + return !target_.GetColorAttachments().empty(); +} + +} // namespace impeller diff --git a/impeller/entity/entity_pass_target.h b/impeller/entity/entity_pass_target.h new file mode 100644 index 0000000000000..03995f6603bf9 --- /dev/null +++ b/impeller/entity/entity_pass_target.h @@ -0,0 +1,43 @@ +// 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. + +#pragma once + +#include "fml/macros.h" +#include "impeller/renderer/render_target.h" + +namespace impeller { + +class InlinePassContext; + +class EntityPassTarget { + public: + explicit EntityPassTarget(const RenderTarget& render_target, + bool supports_read_from_resolve); + + /// @brief Flips the backdrop and returns a readable texture that can be + /// bound/sampled to restore the previous pass. + /// + /// After this method is called, a new `RenderPass` that attaches the + /// result of `GetRenderTarget` is guaranteed to be able to read the + /// previous pass's backdrop texture (which is returned by this + /// method). + std::shared_ptr Flip(Allocator& allocator); + + const RenderTarget& GetRenderTarget() const; + + bool IsValid() const; + + private: + RenderTarget target_; + std::shared_ptr secondary_color_texture_; + + bool supports_read_from_resolve_; + + friend InlinePassContext; + + FML_DISALLOW_ASSIGN(EntityPassTarget); +}; + +} // namespace impeller diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index ed085eda2e109..c29bb2b4ea89a 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -7,6 +7,7 @@ #include #include "impeller/base/validation.h" +#include "impeller/entity/entity_pass_target.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/texture_descriptor.h" @@ -15,11 +16,11 @@ namespace impeller { InlinePassContext::InlinePassContext( std::shared_ptr context, - const RenderTarget& render_target, + EntityPassTarget& pass_target, uint32_t pass_texture_reads, std::optional collapsed_parent_pass) : context_(std::move(context)), - render_target_(render_target), + pass_target_(pass_target), total_pass_reads_(pass_texture_reads), is_collapsed_(collapsed_parent_pass.has_value()) { if (collapsed_parent_pass.has_value()) { @@ -34,7 +35,7 @@ InlinePassContext::~InlinePassContext() { } bool InlinePassContext::IsValid() const { - return !render_target_.GetColorAttachments().empty(); + return pass_target_.IsValid(); } bool InlinePassContext::IsActive() const { @@ -45,7 +46,7 @@ std::shared_ptr InlinePassContext::GetTexture() { if (!IsValid()) { return nullptr; } - return render_target_.GetRenderTargetTexture(); + return pass_target_.GetRenderTarget().GetRenderTargetTexture(); } bool InlinePassContext::EndPass() { @@ -67,8 +68,8 @@ bool InlinePassContext::EndPass() { return true; } -const RenderTarget& InlinePassContext::GetRenderTarget() const { - return render_target_; +EntityPassTarget& InlinePassContext::GetPassTarget() const { + return pass_target_; } InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( @@ -87,12 +88,11 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( return {}; } - if (render_target_.GetColorAttachments().empty()) { + if (pass_target_.GetRenderTarget().GetColorAttachments().empty()) { VALIDATION_LOG << "Color attachment unexpectedly missing from the " "EntityPass render target."; return {}; } - auto color0 = render_target_.GetColorAttachments().find(0)->second; command_buffer_->SetLabel( "EntityPass Command Buffer: Depth=" + std::to_string(pass_depth) + @@ -100,20 +100,25 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( RenderPassResult result; - if (pass_count_ > 0 && color0.resolve_texture) { - result.backdrop_texture = color0.resolve_texture; + if (pass_count_ > 0) { + result.backdrop_texture = + pass_target_.Flip(*context_->GetResourceAllocator()); + if (!result.backdrop_texture) { + VALIDATION_LOG << "Could not flip the EntityPass render target."; + } } - if (color0.resolve_texture) { - color0.load_action = - pass_count_ > 0 ? LoadAction::kDontCare : LoadAction::kClear; - color0.store_action = StoreAction::kMultisampleResolve; - } else { - color0.load_action = LoadAction::kClear; - color0.store_action = StoreAction::kStore; - } + auto color0 = + pass_target_.GetRenderTarget().GetColorAttachments().find(0)->second; + + color0.load_action = + pass_count_ > 0 ? LoadAction::kDontCare : LoadAction::kClear; + + color0.store_action = color0.resolve_texture + ? StoreAction::kMultisampleResolve + : StoreAction::kStore; - auto stencil = render_target_.GetStencilAttachment(); + auto stencil = pass_target_.GetRenderTarget().GetStencilAttachment(); if (!stencil.has_value()) { VALIDATION_LOG << "Stencil attachment unexpectedly missing from the " "EntityPass render target."; @@ -129,11 +134,11 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( stencil->store_action = pass_count_ == total_pass_reads_ ? StoreAction::kDontCare : StoreAction::kStore; - render_target_.SetStencilAttachment(stencil.value()); + pass_target_.target_.SetStencilAttachment(stencil.value()); - render_target_.SetColorAttachment(color0, 0); + pass_target_.target_.SetColorAttachment(color0, 0); - pass_ = command_buffer_->CreateRenderPass(render_target_); + pass_ = command_buffer_->CreateRenderPass(pass_target_.GetRenderTarget()); if (!pass_) { VALIDATION_LOG << "Could not create render pass."; return {}; @@ -143,9 +148,16 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( "EntityPass Render Pass: Depth=" + std::to_string(pass_depth) + " Count=" + std::to_string(pass_count_)); - ++pass_count_; - result.pass = pass_; + + if (!context_->GetDeviceCapabilities().SupportsReadFromResolve() && + result.backdrop_texture == + result.pass->GetRenderTarget().GetRenderTargetTexture()) { + VALIDATION_LOG << "EntityPass backdrop restore configuration is not valid " + "for the current graphics backend."; + } + + ++pass_count_; return result; } diff --git a/impeller/entity/inline_pass_context.h b/impeller/entity/inline_pass_context.h index d7a352afd30a5..f35c1fc44772b 100644 --- a/impeller/entity/inline_pass_context.h +++ b/impeller/entity/inline_pass_context.h @@ -4,6 +4,7 @@ #pragma once +#include "impeller/entity/entity_pass_target.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -19,7 +20,7 @@ class InlinePassContext { InlinePassContext( std::shared_ptr context, - const RenderTarget& render_target, + EntityPassTarget& pass_target, uint32_t pass_texture_reads, std::optional collapsed_parent_pass = std::nullopt); ~InlinePassContext(); @@ -28,14 +29,14 @@ class InlinePassContext { bool IsActive() const; std::shared_ptr GetTexture(); bool EndPass(); - const RenderTarget& GetRenderTarget() const; + EntityPassTarget& GetPassTarget() const; uint32_t GetPassCount() const; RenderPassResult GetRenderPass(uint32_t pass_depth); private: std::shared_ptr context_; - RenderTarget render_target_; + EntityPassTarget& pass_target_; std::shared_ptr command_buffer_; std::shared_ptr pass_; uint32_t pass_count_ = 0; diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index 85e1bd3ee8f78..103dc503acc20 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -82,6 +82,7 @@ ContextGLES::ContextGLES(std::unique_ptr gl, .SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt) .SetDefaultStencilFormat(PixelFormat::kS8UInt) .SetSupportsCompute(false, false) + .SetSupportsReadFromResolve(false) .Build(); } diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 70c76592aa5fa..92edcf46a65cf 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -108,6 +108,7 @@ .SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt) .SetDefaultStencilFormat(PixelFormat::kS8UInt) .SetSupportsCompute(true, supports_subgroups) + .SetSupportsReadFromResolve(true) .Build(); } diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index a7974915d1f81..b1e753f57971f 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -559,6 +559,7 @@ ContextVK::ContextVK( .SetDefaultStencilFormat(PixelFormat::kS8UInt) // TODO(110622): detect this and enable. .SetSupportsCompute(false, false) + .SetSupportsReadFromResolve(false) .Build(); graphics_command_pool_ = std::move(graphics_command_pool.value); descriptor_pool_ = std::move(descriptor_pool.value); diff --git a/impeller/renderer/device_capabilities.cc b/impeller/renderer/device_capabilities.cc index bf88bbc4c5f6b..6d0f9febce9a1 100644 --- a/impeller/renderer/device_capabilities.cc +++ b/impeller/renderer/device_capabilities.cc @@ -15,7 +15,8 @@ IDeviceCapabilities::IDeviceCapabilities(bool has_threading_restrictions, PixelFormat default_color_format, PixelFormat default_stencil_format, bool supports_compute, - bool supports_compute_subgroups) + bool supports_compute_subgroups, + bool supports_read_from_resolve) : has_threading_restrictions_(has_threading_restrictions), supports_offscreen_msaa_(supports_offscreen_msaa), supports_ssbo_(supports_ssbo), @@ -24,7 +25,8 @@ IDeviceCapabilities::IDeviceCapabilities(bool has_threading_restrictions, default_color_format_(default_color_format), default_stencil_format_(default_stencil_format), supports_compute_(supports_compute), - supports_compute_subgroups_(supports_compute_subgroups) {} + supports_compute_subgroups_(supports_compute_subgroups), + supports_read_from_resolve_(supports_read_from_resolve) {} IDeviceCapabilities::~IDeviceCapabilities() = default; @@ -64,6 +66,10 @@ bool IDeviceCapabilities::SupportsComputeSubgroups() const { return supports_compute_subgroups_; } +bool IDeviceCapabilities::SupportsReadFromResolve() const { + return supports_read_from_resolve_; +} + DeviceCapabilitiesBuilder::DeviceCapabilitiesBuilder() = default; DeviceCapabilitiesBuilder::~DeviceCapabilitiesBuilder() = default; @@ -118,6 +124,12 @@ DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsCompute( return *this; } +DeviceCapabilitiesBuilder& +DeviceCapabilitiesBuilder::SetSupportsReadFromResolve(bool value) { + supports_read_from_resolve_ = value; + return *this; +} + std::unique_ptr DeviceCapabilitiesBuilder::Build() { FML_CHECK(default_color_format_.has_value()) << "Default color format not set"; @@ -133,7 +145,8 @@ std::unique_ptr DeviceCapabilitiesBuilder::Build() { *default_color_format_, // *default_stencil_format_, // supports_compute_, // - supports_compute_subgroups_ // + supports_compute_subgroups_, // + supports_read_from_resolve_ // ); return std::unique_ptr(capabilities); } diff --git a/impeller/renderer/device_capabilities.h b/impeller/renderer/device_capabilities.h index f74d95c27f494..c81ee35f49839 100644 --- a/impeller/renderer/device_capabilities.h +++ b/impeller/renderer/device_capabilities.h @@ -32,6 +32,8 @@ class IDeviceCapabilities { bool SupportsCompute() const; bool SupportsComputeSubgroups() const; + bool SupportsReadFromResolve() const; + private: IDeviceCapabilities(bool has_threading_restrictions, bool supports_offscreen_msaa, @@ -41,7 +43,8 @@ class IDeviceCapabilities { PixelFormat default_color_format, PixelFormat default_stencil_format, bool supports_compute, - bool supports_compute_subgroups); + bool supports_compute_subgroups, + bool supports_read_from_resolve); friend class DeviceCapabilitiesBuilder; @@ -54,6 +57,7 @@ class IDeviceCapabilities { PixelFormat default_stencil_format_; bool supports_compute_ = false; bool supports_compute_subgroups_ = false; + bool supports_read_from_resolve_ = false; FML_DISALLOW_COPY_AND_ASSIGN(IDeviceCapabilities); }; @@ -80,6 +84,8 @@ class DeviceCapabilitiesBuilder { DeviceCapabilitiesBuilder& SetSupportsCompute(bool value, bool subgroups); + DeviceCapabilitiesBuilder& SetSupportsReadFromResolve(bool value); + std::unique_ptr Build(); private: @@ -90,6 +96,7 @@ class DeviceCapabilitiesBuilder { bool supports_framebuffer_fetch_ = false; bool supports_compute_ = false; bool supports_compute_subgroups_ = false; + bool supports_read_from_resolve_ = false; std::optional default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt;