[Impeller] Update partial repaint to use a fullsize onscreen. (#161626)
The existing technique of offsetting a smaller texture is very vunerable to bugs in the renderer. Rather than this approach, we can allocate a new offscreen that is full sized and then blit a smaller region. To reduce the allocation costs, we can also set up a transients cache which will reuse this texture. In total, this should be more performant than the existing partial repaint (due to lack of continual re-allocation) at the cost of higher peak memory usage. Fixes https://github.com/flutter/flutter/issues/140877 Fixes https://github.com/flutter/flutter/issues/160588 Fixes https://github.com/flutter/flutter/issues/156113
This commit is contained in:
parent
5517cc9b3b
commit
90f926edc1
@ -185,6 +185,7 @@
|
||||
../../../flutter/impeller/renderer/backend/gles/test
|
||||
../../../flutter/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc
|
||||
../../../flutter/impeller/renderer/backend/metal/allocator_mtl_unittests.mm
|
||||
../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl_unittests.mm
|
||||
../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm
|
||||
../../../flutter/impeller/renderer/backend/vulkan/allocator_vk_unittests.cc
|
||||
../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk_unittests.cc
|
||||
|
@ -42639,6 +42639,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/metal/shader_library_mtl.h +
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/shader_library_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.h + ../../../flutter/LICENSE
|
||||
@ -45584,6 +45586,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/shader_library_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/shader_library_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.h
|
||||
|
@ -185,10 +185,15 @@ void CompositorContext::ScopedFrame::PaintLayerTreeImpeller(
|
||||
flutter::LayerTree& layer_tree,
|
||||
std::optional<DlRect> clip_rect,
|
||||
bool ignore_raster_cache) {
|
||||
if (canvas() && clip_rect) {
|
||||
canvas()->Translate(-clip_rect->GetX(), -clip_rect->GetY());
|
||||
DlAutoCanvasRestore restore(canvas(), clip_rect.has_value());
|
||||
|
||||
if (canvas()) {
|
||||
if (clip_rect) {
|
||||
canvas()->ClipRect(clip_rect.value());
|
||||
}
|
||||
}
|
||||
|
||||
// The canvas()->Restore() is taken care of by the DlAutoCanvasRestore
|
||||
layer_tree.Paint(*this, ignore_raster_cache);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "flutter/fml/concurrent_message_loop.h"
|
||||
#include "flutter/fml/synchronization/sync_switch.h"
|
||||
#include "impeller/playground/playground_impl.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -36,6 +37,7 @@ class PlaygroundImplMTL final : public PlaygroundImpl {
|
||||
std::unique_ptr<Data> data_;
|
||||
std::shared_ptr<ContextMTL> context_;
|
||||
std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_loop_;
|
||||
std::shared_ptr<SwapchainTransientsMTL> swapchain_transients_;
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch_;
|
||||
|
||||
// |PlaygroundImpl|
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/playground/backend/metal/playground_impl_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#import "third_party/glfw/include/GLFW/glfw3.h"
|
||||
@ -98,6 +99,8 @@ PlaygroundImplMTL::PlaygroundImplMTL(PlaygroundSwitches switches)
|
||||
|
||||
handle_.reset(window);
|
||||
context_ = std::move(context);
|
||||
swapchain_transients_ = std::make_shared<SwapchainTransientsMTL>(
|
||||
context_->GetResourceAllocator());
|
||||
}
|
||||
|
||||
PlaygroundImplMTL::~PlaygroundImplMTL() = default;
|
||||
@ -125,7 +128,8 @@ std::unique_ptr<Surface> PlaygroundImplMTL::AcquireSurfaceFrame(
|
||||
|
||||
auto drawable =
|
||||
SurfaceMTL::GetMetalDrawableAndValidate(context, data_->metal_layer);
|
||||
return SurfaceMTL::MakeFromMetalLayerDrawable(context, drawable);
|
||||
return SurfaceMTL::MakeFromMetalLayerDrawable(context, drawable,
|
||||
swapchain_transients_);
|
||||
}
|
||||
|
||||
fml::Status PlaygroundImplMTL::SetCapabilities(
|
||||
|
@ -46,6 +46,8 @@ impeller_component("metal") {
|
||||
"shader_library_mtl.mm",
|
||||
"surface_mtl.h",
|
||||
"surface_mtl.mm",
|
||||
"swapchain_transients_mtl.h",
|
||||
"swapchain_transients_mtl.mm",
|
||||
"texture_mtl.h",
|
||||
"texture_mtl.mm",
|
||||
"texture_wrapper_mtl.h",
|
||||
@ -70,6 +72,7 @@ impeller_component("metal_unittests") {
|
||||
|
||||
sources = [
|
||||
"allocator_mtl_unittests.mm",
|
||||
"swapchain_transients_mtl_unittests.mm",
|
||||
"texture_mtl_unittests.mm",
|
||||
]
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/geometry/rect.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/surface.h"
|
||||
|
||||
@ -41,11 +42,13 @@ class SurfaceMTL final : public Surface {
|
||||
static std::unique_ptr<SurfaceMTL> MakeFromMetalLayerDrawable(
|
||||
const std::shared_ptr<Context>& context,
|
||||
id<CAMetalDrawable> drawable,
|
||||
const std::shared_ptr<SwapchainTransientsMTL>& transients,
|
||||
std::optional<IRect> clip_rect = std::nullopt);
|
||||
|
||||
static std::unique_ptr<SurfaceMTL> MakeFromTexture(
|
||||
const std::shared_ptr<Context>& context,
|
||||
id<MTLTexture> texture,
|
||||
const std::shared_ptr<SwapchainTransientsMTL>& transients,
|
||||
std::optional<IRect> clip_rect,
|
||||
id<CAMetalDrawable> drawable = nil);
|
||||
#pragma GCC diagnostic pop
|
||||
|
@ -7,9 +7,11 @@
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/impeller/renderer/command_buffer.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/texture_descriptor.h"
|
||||
#include "impeller/renderer/backend/metal/context_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/formats_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/texture_mtl.h"
|
||||
#include "impeller/renderer/render_target.h"
|
||||
|
||||
@ -47,25 +49,20 @@ id<CAMetalDrawable> SurfaceMTL::GetMetalDrawableAndValidate(
|
||||
}
|
||||
|
||||
static std::optional<RenderTarget> WrapTextureWithRenderTarget(
|
||||
Allocator& allocator,
|
||||
const std::shared_ptr<SwapchainTransientsMTL>& transients,
|
||||
id<MTLTexture> texture,
|
||||
bool requires_blit,
|
||||
std::optional<IRect> clip_rect) {
|
||||
// compositor_context.cc will offset the rendering by the clip origin. Here we
|
||||
// shrink to the size of the clip. This has the same effect as clipping the
|
||||
// rendering but also creates smaller intermediate passes.
|
||||
ISize root_size;
|
||||
if (requires_blit) {
|
||||
if (!clip_rect.has_value()) {
|
||||
VALIDATION_LOG << "Missing clip rectangle.";
|
||||
return std::nullopt;
|
||||
}
|
||||
root_size = ISize(clip_rect->GetWidth(), clip_rect->GetHeight());
|
||||
} else {
|
||||
root_size = {static_cast<ISize::Type>(texture.width),
|
||||
static_cast<ISize::Type>(texture.height)};
|
||||
ISize root_size = {static_cast<ISize::Type>(texture.width),
|
||||
static_cast<ISize::Type>(texture.height)};
|
||||
PixelFormat format = FromMTLPixelFormat(texture.pixelFormat);
|
||||
if (format == PixelFormat::kUnknown) {
|
||||
VALIDATION_LOG << "Unknown drawable color format.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
transients->SetSizeAndFormat(root_size, format);
|
||||
|
||||
TextureDescriptor resolve_tex_desc;
|
||||
resolve_tex_desc.format = FromMTLPixelFormat(texture.pixelFormat);
|
||||
resolve_tex_desc.size = root_size;
|
||||
@ -74,65 +71,58 @@ static std::optional<RenderTarget> WrapTextureWithRenderTarget(
|
||||
resolve_tex_desc.sample_count = SampleCount::kCount1;
|
||||
resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate;
|
||||
|
||||
if (resolve_tex_desc.format == PixelFormat::kUnknown) {
|
||||
VALIDATION_LOG << "Unknown drawable color format.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Create color resolve texture.
|
||||
std::shared_ptr<Texture> resolve_tex;
|
||||
if (requires_blit) {
|
||||
resolve_tex_desc.compression_type = CompressionType::kLossy;
|
||||
resolve_tex = allocator.CreateTexture(resolve_tex_desc);
|
||||
resolve_tex = transients->GetResolveTexture();
|
||||
} else {
|
||||
resolve_tex = TextureMTL::Create(resolve_tex_desc, texture);
|
||||
}
|
||||
|
||||
if (!resolve_tex) {
|
||||
VALIDATION_LOG << "Could not wrap resolve texture.";
|
||||
return std::nullopt;
|
||||
}
|
||||
resolve_tex->SetLabel("ImpellerOnscreenResolve");
|
||||
|
||||
TextureDescriptor msaa_tex_desc;
|
||||
msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient;
|
||||
msaa_tex_desc.type = TextureType::kTexture2DMultisample;
|
||||
msaa_tex_desc.sample_count = SampleCount::kCount4;
|
||||
msaa_tex_desc.format = resolve_tex->GetTextureDescriptor().format;
|
||||
msaa_tex_desc.size = resolve_tex->GetSize();
|
||||
msaa_tex_desc.usage = TextureUsage::kRenderTarget;
|
||||
|
||||
auto msaa_tex = allocator.CreateTexture(msaa_tex_desc);
|
||||
if (!msaa_tex) {
|
||||
VALIDATION_LOG << "Could not allocate MSAA color texture.";
|
||||
return std::nullopt;
|
||||
}
|
||||
msaa_tex->SetLabel("ImpellerOnscreenColorMSAA");
|
||||
|
||||
ColorAttachment color0;
|
||||
color0.texture = msaa_tex;
|
||||
color0.texture = transients->GetMSAATexture();
|
||||
color0.clear_color = Color::DarkSlateGray();
|
||||
color0.load_action = LoadAction::kClear;
|
||||
color0.store_action = StoreAction::kMultisampleResolve;
|
||||
color0.resolve_texture = std::move(resolve_tex);
|
||||
|
||||
auto render_target_desc = std::make_optional<RenderTarget>();
|
||||
render_target_desc->SetColorAttachment(color0, 0u);
|
||||
DepthAttachment depth0;
|
||||
depth0.load_action =
|
||||
RenderTarget::kDefaultStencilAttachmentConfig.load_action;
|
||||
depth0.store_action =
|
||||
RenderTarget::kDefaultStencilAttachmentConfig.store_action;
|
||||
depth0.clear_depth = 0u;
|
||||
depth0.texture = transients->GetDepthStencilTexture();
|
||||
|
||||
return render_target_desc;
|
||||
StencilAttachment stencil0;
|
||||
stencil0.load_action =
|
||||
RenderTarget::kDefaultStencilAttachmentConfig.load_action;
|
||||
stencil0.store_action =
|
||||
RenderTarget::kDefaultStencilAttachmentConfig.store_action;
|
||||
stencil0.clear_stencil = 0u;
|
||||
stencil0.texture = transients->GetDepthStencilTexture();
|
||||
|
||||
RenderTarget render_target;
|
||||
render_target.SetColorAttachment(color0, 0u);
|
||||
render_target.SetDepthAttachment(std::move(depth0));
|
||||
render_target.SetStencilAttachment(std::move(stencil0));
|
||||
|
||||
return render_target;
|
||||
}
|
||||
|
||||
std::unique_ptr<SurfaceMTL> SurfaceMTL::MakeFromMetalLayerDrawable(
|
||||
const std::shared_ptr<Context>& context,
|
||||
id<CAMetalDrawable> drawable,
|
||||
const std::shared_ptr<SwapchainTransientsMTL>& transients,
|
||||
std::optional<IRect> clip_rect) {
|
||||
return SurfaceMTL::MakeFromTexture(context, drawable.texture, clip_rect,
|
||||
drawable);
|
||||
return SurfaceMTL::MakeFromTexture(context, drawable.texture, transients,
|
||||
clip_rect, drawable);
|
||||
}
|
||||
|
||||
std::unique_ptr<SurfaceMTL> SurfaceMTL::MakeFromTexture(
|
||||
const std::shared_ptr<Context>& context,
|
||||
id<MTLTexture> texture,
|
||||
const std::shared_ptr<SwapchainTransientsMTL>& transients,
|
||||
std::optional<IRect> clip_rect,
|
||||
id<CAMetalDrawable> drawable) {
|
||||
bool partial_repaint_blit_required = ShouldPerformPartialRepaint(clip_rect);
|
||||
@ -140,9 +130,8 @@ std::unique_ptr<SurfaceMTL> SurfaceMTL::MakeFromTexture(
|
||||
// The returned render target is the texture that Impeller will render the
|
||||
// root pass to. If partial repaint is in use, this may be a new texture which
|
||||
// is smaller than the given MTLTexture.
|
||||
auto render_target =
|
||||
WrapTextureWithRenderTarget(*context->GetResourceAllocator(), texture,
|
||||
partial_repaint_blit_required, clip_rect);
|
||||
auto render_target = WrapTextureWithRenderTarget(
|
||||
transients, texture, partial_repaint_blit_required, clip_rect);
|
||||
if (!render_target) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -251,7 +240,7 @@ bool SurfaceMTL::PreparePresent() const {
|
||||
VALIDATION_LOG << "Missing clip rectangle.";
|
||||
return false;
|
||||
}
|
||||
blit_pass->AddCopy(source_texture_, destination_texture_, std::nullopt,
|
||||
blit_pass->AddCopy(source_texture_, destination_texture_, clip_rect_,
|
||||
clip_rect_->GetOrigin());
|
||||
blit_pass->EncodeCommands();
|
||||
if (!context->GetCommandQueue()->Submit({blit_command_buffer}).ok()) {
|
||||
|
@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_SWAPCHAIN_TRANSIENTS_MTL_H_
|
||||
#define FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_SWAPCHAIN_TRANSIENTS_MTL_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/geometry/rect.h"
|
||||
#include "impeller/geometry/size.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/surface.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
/// @brief A cache for the onscreen texture attachments used in surface_mtl.
|
||||
///
|
||||
/// Typically the onscreen resolve texture is created from a Metal drawable and
|
||||
/// this cache is only used for the MSAA texture and the depth+stencil
|
||||
/// attachment. When partial repaint is active, this class also provides a cache
|
||||
/// for an offscreen resolve texture that is blitted to the real onscreen during
|
||||
/// present.
|
||||
class SwapchainTransientsMTL {
|
||||
public:
|
||||
explicit SwapchainTransientsMTL(const std::shared_ptr<Allocator>& allocator);
|
||||
|
||||
~SwapchainTransientsMTL();
|
||||
|
||||
/// @brief Update the size and pixel format of the onscreens.
|
||||
///
|
||||
/// Note: this will invalidate any cached textures if either property changes.
|
||||
void SetSizeAndFormat(ISize size, PixelFormat format);
|
||||
|
||||
/// @brief Retrieve the resolve texture, creating one if needed.
|
||||
std::shared_ptr<Texture> GetResolveTexture();
|
||||
|
||||
/// @brief Retrieve the MSAA texture, creating one if needed.
|
||||
std::shared_ptr<Texture> GetMSAATexture();
|
||||
|
||||
/// @brief Retrieve the depth+stencil texture, creating one if needed.
|
||||
std::shared_ptr<Texture> GetDepthStencilTexture();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Allocator> allocator_;
|
||||
ISize size_ = {0, 0};
|
||||
PixelFormat format_ = PixelFormat::kUnknown;
|
||||
std::shared_ptr<Texture> resolve_tex_;
|
||||
std::shared_ptr<Texture> msaa_tex_;
|
||||
std::shared_ptr<Texture> depth_stencil_tex_;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_SWAPCHAIN_TRANSIENTS_MTL_H_
|
@ -0,0 +1,92 @@
|
||||
// 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/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/texture_descriptor.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
SwapchainTransientsMTL::SwapchainTransientsMTL(
|
||||
const std::shared_ptr<Allocator>& allocator)
|
||||
: allocator_(allocator) {}
|
||||
|
||||
SwapchainTransientsMTL::~SwapchainTransientsMTL() = default;
|
||||
|
||||
void SwapchainTransientsMTL::SetSizeAndFormat(ISize size, PixelFormat format) {
|
||||
if (size != size_ || format != format_) {
|
||||
resolve_tex_ = nullptr;
|
||||
msaa_tex_ = nullptr;
|
||||
depth_stencil_tex_ = nullptr;
|
||||
}
|
||||
size_ = size;
|
||||
format_ = format;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> SwapchainTransientsMTL::GetResolveTexture() {
|
||||
if (!resolve_tex_) {
|
||||
TextureDescriptor desc;
|
||||
desc.size = size_;
|
||||
desc.sample_count = SampleCount::kCount1;
|
||||
desc.format = format_;
|
||||
desc.storage_mode = StorageMode::kDevicePrivate;
|
||||
desc.usage = TextureUsage::kShaderRead | TextureUsage::kRenderTarget;
|
||||
desc.compression_type = CompressionType::kLossy;
|
||||
desc.type = TextureType::kTexture2D;
|
||||
|
||||
resolve_tex_ = allocator_->CreateTexture(desc);
|
||||
if (!resolve_tex_) {
|
||||
VALIDATION_LOG << "Failed to allocate resolve texture.";
|
||||
return nullptr;
|
||||
}
|
||||
resolve_tex_->SetLabel("ImpellerOnscreenResolve");
|
||||
}
|
||||
|
||||
return resolve_tex_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> SwapchainTransientsMTL::GetMSAATexture() {
|
||||
if (!msaa_tex_) {
|
||||
TextureDescriptor desc;
|
||||
desc.size = size_;
|
||||
desc.sample_count = SampleCount::kCount4;
|
||||
desc.format = format_;
|
||||
desc.storage_mode = StorageMode::kDeviceTransient;
|
||||
desc.usage = TextureUsage::kRenderTarget;
|
||||
desc.type = TextureType::kTexture2DMultisample;
|
||||
|
||||
msaa_tex_ = allocator_->CreateTexture(desc);
|
||||
if (!msaa_tex_) {
|
||||
VALIDATION_LOG << "Failed to allocate MSAA texture.";
|
||||
return nullptr;
|
||||
}
|
||||
msaa_tex_->SetLabel("ImpellerOnscreenMSAA");
|
||||
}
|
||||
|
||||
return msaa_tex_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> SwapchainTransientsMTL::GetDepthStencilTexture() {
|
||||
if (!depth_stencil_tex_) {
|
||||
TextureDescriptor desc;
|
||||
desc.size = size_;
|
||||
desc.sample_count = SampleCount::kCount4;
|
||||
desc.format = PixelFormat::kD32FloatS8UInt;
|
||||
desc.storage_mode = StorageMode::kDeviceTransient;
|
||||
desc.usage = TextureUsage::kRenderTarget;
|
||||
desc.type = TextureType::kTexture2DMultisample;
|
||||
|
||||
depth_stencil_tex_ = allocator_->CreateTexture(desc);
|
||||
if (!depth_stencil_tex_) {
|
||||
VALIDATION_LOG << "Failed to allocate depth-stencil texture.";
|
||||
return nullptr;
|
||||
}
|
||||
depth_stencil_tex_->SetLabel("ImpellerOnscreenDepth+Stencil");
|
||||
}
|
||||
|
||||
return depth_stencil_tex_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
@ -0,0 +1,79 @@
|
||||
// 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 "flutter/testing/testing.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/texture_descriptor.h"
|
||||
#include "impeller/playground/playground_test.h"
|
||||
#include "impeller/renderer/backend/metal/allocator_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/context_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/formats_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/texture_mtl.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using SwapchainTransientsMTLTest = PlaygroundTest;
|
||||
INSTANTIATE_METAL_PLAYGROUND_SUITE(SwapchainTransientsMTLTest);
|
||||
|
||||
TEST_P(SwapchainTransientsMTLTest, CanAllocateSwapchainTextures) {
|
||||
const auto& transients = std::make_shared<SwapchainTransientsMTL>(
|
||||
GetContext()->GetResourceAllocator());
|
||||
|
||||
transients->SetSizeAndFormat({1, 1}, PixelFormat::kB8G8R8A8UNormInt);
|
||||
|
||||
auto resolve = transients->GetResolveTexture();
|
||||
EXPECT_NE(resolve, nullptr);
|
||||
EXPECT_NE(transients->GetMSAATexture(), nullptr);
|
||||
EXPECT_NE(transients->GetDepthStencilTexture(), nullptr);
|
||||
|
||||
// Texture properties are correct for resolve.
|
||||
EXPECT_EQ(resolve->GetTextureDescriptor().size, ISize(1, 1));
|
||||
EXPECT_EQ(resolve->GetTextureDescriptor().format,
|
||||
PixelFormat::kB8G8R8A8UNormInt);
|
||||
EXPECT_EQ(resolve->GetTextureDescriptor().sample_count, SampleCount::kCount1);
|
||||
EXPECT_EQ(resolve->GetTextureDescriptor().storage_mode,
|
||||
StorageMode::kDevicePrivate);
|
||||
|
||||
// Texture properties are correct for MSAA.
|
||||
auto msaa = transients->GetMSAATexture();
|
||||
EXPECT_EQ(msaa->GetTextureDescriptor().size, ISize(1, 1));
|
||||
EXPECT_EQ(msaa->GetTextureDescriptor().format,
|
||||
PixelFormat::kB8G8R8A8UNormInt);
|
||||
EXPECT_EQ(msaa->GetTextureDescriptor().sample_count, SampleCount::kCount4);
|
||||
EXPECT_EQ(msaa->GetTextureDescriptor().storage_mode,
|
||||
StorageMode::kDeviceTransient);
|
||||
|
||||
// Texture properties are correct for Depth+Stencil.
|
||||
auto depth_stencil = transients->GetDepthStencilTexture();
|
||||
EXPECT_EQ(depth_stencil->GetTextureDescriptor().size, ISize(1, 1));
|
||||
EXPECT_EQ(depth_stencil->GetTextureDescriptor().format,
|
||||
PixelFormat::kD32FloatS8UInt);
|
||||
EXPECT_EQ(depth_stencil->GetTextureDescriptor().sample_count,
|
||||
SampleCount::kCount4);
|
||||
EXPECT_EQ(depth_stencil->GetTextureDescriptor().storage_mode,
|
||||
StorageMode::kDeviceTransient);
|
||||
|
||||
// Textures are cached.
|
||||
EXPECT_EQ(transients->GetResolveTexture(), resolve);
|
||||
|
||||
// Texture cache is invalidated when size changes.
|
||||
transients->SetSizeAndFormat({2, 2}, PixelFormat::kB8G8R8A8UNormInt);
|
||||
EXPECT_NE(resolve, transients->GetResolveTexture());
|
||||
resolve = transients->GetResolveTexture();
|
||||
|
||||
// Texture cache is invalidated when pixel format changes.
|
||||
transients->SetSizeAndFormat({2, 2}, PixelFormat::kB10G10R10A10XR);
|
||||
EXPECT_NE(resolve, transients->GetResolveTexture());
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
@ -68,13 +68,6 @@ bool BlitPass::AddCopy(std::shared_ptr<Texture> source,
|
||||
return true; // Nothing to blit.
|
||||
}
|
||||
|
||||
// Clip the destination image.
|
||||
source_region = source_region->Intersection(
|
||||
IRect::MakeOriginSize(-destination_origin, destination->GetSize()));
|
||||
if (!source_region.has_value()) {
|
||||
return true; // Nothing to blit.
|
||||
}
|
||||
|
||||
return OnCopyTextureToTextureCommand(
|
||||
std::move(source), std::move(destination), source_region.value(),
|
||||
destination_origin, label);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/impeller/display_list/aiks_context.h"
|
||||
#include "flutter/impeller/renderer/backend/metal/context_mtl.h"
|
||||
#include "flutter/impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
|
||||
#include "third_party/skia/include/gpu/ganesh/mtl/GrMtlTypes.h"
|
||||
|
||||
@ -46,6 +47,7 @@ class IMPELLER_CA_METAL_LAYER_AVAILABLE GPUSurfaceMetalImpeller
|
||||
// MTLTexture for each drawable
|
||||
std::shared_ptr<std::map<void*, SkIRect>> damage_ =
|
||||
std::make_shared<std::map<void*, SkIRect>>();
|
||||
std::shared_ptr<impeller::SwapchainTransientsMTL> swapchain_transients_;
|
||||
|
||||
// |Surface|
|
||||
std::unique_ptr<SurfaceFrame> AcquireFrame(
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "flow/surface.h"
|
||||
#include "flow/surface_frame.h"
|
||||
#include "impeller/display_list/aiks_context.h"
|
||||
#include "impeller/renderer/backend/metal/swapchain_transients_mtl.h"
|
||||
|
||||
#include "flutter/common/settings.h"
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
@ -36,6 +37,10 @@ GPUSurfaceMetalImpeller::GPUSurfaceMetalImpeller(
|
||||
if (disablePartialRepaint != nil) {
|
||||
disable_partial_repaint_ = disablePartialRepaint.boolValue;
|
||||
}
|
||||
if (aiks_context_) {
|
||||
swapchain_transients_ = std::make_shared<impeller::SwapchainTransientsMTL>(
|
||||
aiks_context_->GetContext()->GetResourceAllocator());
|
||||
}
|
||||
}
|
||||
|
||||
GPUSurfaceMetalImpeller::~GPUSurfaceMetalImpeller() = default;
|
||||
@ -107,7 +112,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa
|
||||
aiks_context = aiks_context_, //
|
||||
drawable, //
|
||||
weak_last_texture, //
|
||||
weak_layer //
|
||||
weak_layer, //
|
||||
swapchain_transients = swapchain_transients_ //
|
||||
](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
|
||||
id<MTLTexture> strong_last_texture = weak_last_texture;
|
||||
CAMetalLayer* strong_layer = weak_layer;
|
||||
@ -146,8 +152,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa
|
||||
buffer_damage->width(), buffer_damage->height());
|
||||
}
|
||||
|
||||
auto surface = impeller::SurfaceMTL::MakeFromMetalLayerDrawable(aiks_context->GetContext(),
|
||||
drawable, clip_rect);
|
||||
auto surface = impeller::SurfaceMTL::MakeFromMetalLayerDrawable(
|
||||
aiks_context->GetContext(), drawable, swapchain_transients, clip_rect);
|
||||
|
||||
// The surface may be null if we failed to allocate the onscreen render target
|
||||
// due to running out of memory.
|
||||
@ -232,8 +238,9 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur
|
||||
SurfaceFrame::EncodeCallback encode_callback =
|
||||
fml::MakeCopyable([disable_partial_repaint = disable_partial_repaint_, //
|
||||
damage = damage_,
|
||||
aiks_context = aiks_context_, //
|
||||
weak_texture //
|
||||
aiks_context = aiks_context_, //
|
||||
weak_texture, //
|
||||
swapchain_transients = swapchain_transients_ //
|
||||
](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
|
||||
id<MTLTexture> strong_texture = weak_texture;
|
||||
if (!strong_texture) {
|
||||
@ -269,8 +276,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur
|
||||
buffer_damage->width(), buffer_damage->height());
|
||||
}
|
||||
|
||||
auto surface = impeller::SurfaceMTL::MakeFromTexture(aiks_context->GetContext(),
|
||||
strong_texture, clip_rect);
|
||||
auto surface = impeller::SurfaceMTL::MakeFromTexture(
|
||||
aiks_context->GetContext(), strong_texture, swapchain_transients, clip_rect);
|
||||
|
||||
surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user