Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
1 change: 1 addition & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
../../../flutter/impeller/image/README.md
../../../flutter/impeller/playground
../../../flutter/impeller/renderer/backend/gles/test
../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm
../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc
Expand Down
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -3317,6 +3317,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.h + ../../.
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/lazy_drawable_holder.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/lazy_drawable_holder.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_mtl.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -6081,6 +6083,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/lazy_drawable_holder.h
FILE: ../../../flutter/impeller/renderer/backend/metal/lazy_drawable_holder.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_mtl.h
Expand Down
1 change: 1 addition & 0 deletions impeller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ impeller_component("impeller_unittests") {
"core:allocator_unittests",
"display_list:skia_conversions_unittests",
"geometry:geometry_unittests",
"renderer/backend/metal:metal_unittests",
"runtime_stage:runtime_stage_unittests",
"scene/importer:importer_unittests",
"shader_archive:shader_archive_unittests",
Expand Down
18 changes: 18 additions & 0 deletions impeller/renderer/backend/metal/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ impeller_component("metal") {
"formats_mtl.mm",
"gpu_tracer_mtl.h",
"gpu_tracer_mtl.mm",
"lazy_drawable_holder.h",
"lazy_drawable_holder.mm",
"pipeline_library_mtl.h",
"pipeline_library_mtl.mm",
"pipeline_mtl.h",
Expand Down Expand Up @@ -57,3 +59,19 @@ impeller_component("metal") {

frameworks = [ "Metal.framework" ]
}

impeller_component("metal_unittests") {
testonly = true

sources = [ "texture_mtl_unittests.mm" ]

deps = [
":metal",
"//flutter/testing:testing_lib",
]

frameworks = [
"AppKit.framework",
"QuartzCore.framework",
]
}
2 changes: 1 addition & 1 deletion impeller/renderer/backend/metal/allocator_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ static MTLStorageMode ToMTLStorageMode(StorageMode mode,
if (!texture) {
return nullptr;
}
return std::make_shared<TextureMTL>(desc, texture);
return TextureMTL::Create(desc, texture);
}

uint16_t AllocatorMTL::MinimumBytesPerRow(PixelFormat format) const {
Expand Down
2 changes: 1 addition & 1 deletion impeller/renderer/backend/metal/device_buffer_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
if (!texture) {
return nullptr;
}
return std::make_shared<TextureMTL>(descriptor, texture);
return TextureMTL::Create(descriptor, texture);
}

[[nodiscard]] bool DeviceBufferMTL::OnCopyHostBuffer(const uint8_t* source,
Expand Down
30 changes: 30 additions & 0 deletions impeller/renderer/backend/metal/lazy_drawable_holder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 <Metal/Metal.h>

#include <future>
#include "impeller/core/texture_descriptor.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"

@protocol CAMetalDrawable;
@class CAMetalLayer;

namespace impeller {

/// @brief Create a deferred drawable from a CAMetalLayer.
std::shared_future<id<CAMetalDrawable>> GetDrawableDeferred(
CAMetalLayer* layer);

/// @brief Create a TextureMTL from a deferred drawable.
///
/// This function is safe to call multiple times and will only call
/// nextDrawable once.
std::shared_ptr<TextureMTL> CreateTextureFromDrawableFuture(
TextureDescriptor desc,
const std::shared_future<id<CAMetalDrawable>>& drawble_future);

} // namespace impeller
51 changes: 51 additions & 0 deletions impeller/renderer/backend/metal/lazy_drawable_holder.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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/lazy_drawable_holder.h"

#include <QuartzCore/CAMetalLayer.h>
#include <future>
#include <memory>

#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"

namespace impeller {

#pragma GCC diagnostic push
// Disable the diagnostic for iOS Simulators. Metal without emulation isn't
// available prior to iOS 13 and that's what the simulator headers say when
// support for CAMetalLayer begins. CAMetalLayer is available on iOS 8.0 and
// above which is well below Flutters support level.
#pragma GCC diagnostic ignored "-Wunguarded-availability-new"

std::shared_future<id<CAMetalDrawable>> GetDrawableDeferred(
CAMetalLayer* layer) {
auto future =
std::async(std::launch::deferred, [layer]() -> id<CAMetalDrawable> {
id<CAMetalDrawable> current_drawable = nil;
{
TRACE_EVENT0("impeller", "WaitForNextDrawable");
current_drawable = [layer nextDrawable];
}
if (!current_drawable) {
VALIDATION_LOG << "Could not acquire current drawable.";
return nullptr;
}
return current_drawable;
});
return std::shared_future<id<CAMetalDrawable>>(std::move(future));
}

std::shared_ptr<TextureMTL> CreateTextureFromDrawableFuture(
TextureDescriptor desc,
const std::shared_future<id<CAMetalDrawable>>& drawble_future) {
return std::make_shared<TextureMTL>(
desc, [drawble_future]() { return drawble_future.get().texture; },
/*wrapped=*/false, /*drawable=*/true);
}

#pragma GCC diagnostic pop

} // namespace impeller
2 changes: 1 addition & 1 deletion impeller/renderer/backend/metal/surface_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
resolve_tex_desc.compression_type = CompressionType::kLossy;
resolve_tex = allocator.CreateTexture(resolve_tex_desc);
} else {
resolve_tex = std::make_shared<TextureMTL>(resolve_tex_desc, texture);
resolve_tex = TextureMTL::Create(resolve_tex_desc, texture);
}

if (!resolve_tex) {
Expand Down
25 changes: 18 additions & 7 deletions impeller/renderer/backend/metal/texture_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,43 @@ namespace impeller {
class TextureMTL final : public Texture,
public BackendCast<TextureMTL, Texture> {
public:
/// @brief This callback needs to always return the same texture when called
/// multiple times.
using AcquireTextureProc = std::function<id<MTLTexture>()>;

TextureMTL(TextureDescriptor desc,
id<MTLTexture> texture,
bool wrapped = false);
const AcquireTextureProc& aquire_proc,
bool wrapped = false,
bool drawable = false);

static std::shared_ptr<TextureMTL> Wrapper(
TextureDescriptor desc,
id<MTLTexture> texture,
std::function<void()> deletion_proc = nullptr);

static std::shared_ptr<TextureMTL> Create(TextureDescriptor desc,
id<MTLTexture> texture);

// |Texture|
~TextureMTL() override;

id<MTLTexture> GetMTLTexture() const;

bool IsWrapped() const;

/// @brief Whether or not this texture is wrapping a Metal drawable.
bool IsDrawable() const;

// |Texture|
bool IsValid() const override;

bool GenerateMipmap(id<MTLBlitCommandEncoder> encoder);

private:
id<MTLTexture> texture_ = nullptr;
AcquireTextureProc aquire_proc_ = {};
bool is_valid_ = false;
bool is_wrapped_ = false;
bool is_drawable_ = false;

// |Texture|
void SetLabel(std::string_view label) override;
Expand All @@ -49,10 +64,6 @@ class TextureMTL final : public Texture,
// |Texture|
bool OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
size_t slice) override;

// |Texture|
bool IsValid() const override;

// |Texture|
ISize GetSize() const override;

Expand Down
63 changes: 44 additions & 19 deletions impeller/renderer/backend/metal/texture_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "impeller/renderer/backend/metal/texture_mtl.h"
#include <memory>

#include "impeller/base/validation.h"
#include "impeller/core/texture_descriptor.h"
Expand All @@ -17,12 +18,13 @@
}

TextureMTL::TextureMTL(TextureDescriptor p_desc,
id<MTLTexture> texture,
bool wrapped)
: Texture(p_desc), texture_(texture) {
const AcquireTextureProc& aquire_proc,
bool wrapped,
bool drawable)
: Texture(p_desc), aquire_proc_(aquire_proc), is_drawable_(drawable) {
const auto& desc = GetTextureDescriptor();

if (!desc.IsValid() || !texture_) {
if (!desc.IsValid() || !aquire_proc) {
return;
}

Expand All @@ -41,19 +43,29 @@
std::function<void()> deletion_proc) {
if (deletion_proc) {
return std::shared_ptr<TextureMTL>(
new TextureMTL(desc, texture, true),
new TextureMTL(
desc, [texture]() { return texture; }, true),
[deletion_proc = std::move(deletion_proc)](TextureMTL* t) {
deletion_proc();
delete t;
});
}
return std::shared_ptr<TextureMTL>(new TextureMTL(desc, texture, true));
return std::shared_ptr<TextureMTL>(
new TextureMTL(desc, [texture]() { return texture; }, true));
}

std::shared_ptr<TextureMTL> TextureMTL::Create(TextureDescriptor desc,
id<MTLTexture> texture) {
return std::make_shared<TextureMTL>(desc, [texture]() { return texture; });
}

TextureMTL::~TextureMTL() = default;

void TextureMTL::SetLabel(std::string_view label) {
[texture_ setLabel:@(label.data())];
if (is_drawable_) {
return;
}
[aquire_proc_() setLabel:@(label.data())];
}

// |Texture|
Expand All @@ -68,7 +80,7 @@ new TextureMTL(desc, texture, true),
bool TextureMTL::OnSetContents(const uint8_t* contents,
size_t length,
size_t slice) {
if (!IsValid() || !contents || is_wrapped_) {
if (!IsValid() || !contents || is_wrapped_ || is_drawable_) {
return false;
}

Expand All @@ -81,24 +93,28 @@ new TextureMTL(desc, texture, true),

const auto region =
MTLRegionMake2D(0u, 0u, desc.size.width, desc.size.height);
[texture_ replaceRegion:region //
mipmapLevel:0u //
slice:slice //
withBytes:contents //
bytesPerRow:desc.GetBytesPerRow() //
bytesPerImage:desc.GetByteSizeOfBaseMipLevel() //
[aquire_proc_() replaceRegion:region //
mipmapLevel:0u //
slice:slice //
withBytes:contents //
bytesPerRow:desc.GetBytesPerRow() //
bytesPerImage:desc.GetByteSizeOfBaseMipLevel() //
];

return true;
}

ISize TextureMTL::GetSize() const {
return {static_cast<ISize::Type>(texture_.width),
static_cast<ISize::Type>(texture_.height)};
if (is_drawable_) {
return GetTextureDescriptor().size;
}
const auto& texture = aquire_proc_();
return {static_cast<ISize::Type>(texture.width),
static_cast<ISize::Type>(texture.height)};
}

id<MTLTexture> TextureMTL::GetMTLTexture() const {
return texture_;
return aquire_proc_();
}

bool TextureMTL::IsValid() const {
Expand All @@ -109,12 +125,21 @@ new TextureMTL(desc, texture, true),
return is_wrapped_;
}

bool TextureMTL::IsDrawable() const {
return is_drawable_;
}

bool TextureMTL::GenerateMipmap(id<MTLBlitCommandEncoder> encoder) {
if (!texture_) {
if (is_drawable_) {
return false;
}

auto texture = aquire_proc_();
if (!texture) {
return false;
}

[encoder generateMipmapsForTexture:texture_];
[encoder generateMipmapsForTexture:texture];
mipmap_generated_ = true;

return true;
Expand Down
Loading