Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e353f09

Browse files
committed
Allow external texture sources when using the Metal backend.
This patch moves the responsibility of vending external texture proxies to the client rendering API specific IOS context subclasses. Some key changes in the Metal backend compared to OpenGL. * The Metal backend has a single texture cache for all external textures as opposed to a separate cache for each texture proxy in the OpenGL backend. This use is more desirable as cached entries may be reused by multiple proxies for better cache utilization. This implementation is harder in the OpenGL backend because the cache cannot be created upfront as thread local state is needed to (re)initialize the cache. This update can be made to the OpenGL backend as well but it is unrelated to the primary purpose of this patch. * Attempting to use external textures with the software backend now logs a single message to the console that this feature is only available when using the Metal or OpenGL backend on devices. Previously, an OpenGL texture proxy creation would be attempted and it would fail in an undefined spot internally with a confusing message. * The OpenGL backend seems to conflate rendering size with paint size. This puts the unnecessary limitation that the embedders must provide textures at the size at which they will be rendered. This limitation has been lifted in the Metal backend and should probably be lifted in the OpenGL backend as well (in a later patch). There are opportunities to dry up the implementations of the `IOSExternalTextureMetal` and `IOSExternalTextureGL` but that refactor can be attempted separately. Fixes flutter/flutter#41819
1 parent 9c64029 commit e353f09

17 files changed

+387
-11
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ FILE: ../../../flutter/fml/platform/android/scoped_java_ref.cc
189189
FILE: ../../../flutter/fml/platform/android/scoped_java_ref.h
190190
FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc
191191
FILE: ../../../flutter/fml/platform/darwin/cf_utils.h
192+
FILE: ../../../flutter/fml/platform/darwin/cf_utils_unittests.mm
192193
FILE: ../../../flutter/fml/platform/darwin/message_loop_darwin.h
193194
FILE: ../../../flutter/fml/platform/darwin/message_loop_darwin.mm
194195
FILE: ../../../flutter/fml/platform/darwin/paths_darwin.mm
@@ -890,6 +891,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_software.h
890891
FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_software.mm
891892
FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.h
892893
FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.mm
894+
FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_metal.h
895+
FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_metal.mm
893896
FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target_gl.h
894897
FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target_gl.mm
895898
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.h

flow/texture.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,19 @@ Texture::~Texture() = default;
1313
TextureRegistry::TextureRegistry() = default;
1414

1515
void TextureRegistry::RegisterTexture(std::shared_ptr<Texture> texture) {
16+
if (!texture) {
17+
return;
18+
}
1619
mapping_[texture->Id()] = texture;
1720
}
1821

1922
void TextureRegistry::UnregisterTexture(int64_t id) {
20-
mapping_[id]->OnTextureUnregistered();
21-
mapping_.erase(id);
23+
auto found = mapping_.find(id);
24+
if (found == mapping_.end()) {
25+
return;
26+
}
27+
found->second->OnTextureUnregistered();
28+
mapping_.erase(found);
2229
}
2330

2431
void TextureRegistry::OnGrContextCreated() {

fml/BUILD.gn

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ executable("fml_unittests") {
252252
"message_loop_unittests.cc",
253253
"message_unittests.cc",
254254
"paths_unittests.cc",
255-
"platform/darwin/string_range_sanitization_unittests.mm",
256255
"synchronization/count_down_latch_unittests.cc",
257256
"synchronization/semaphore_unittest.cc",
258257
"synchronization/sync_switch_unittest.cc",
@@ -264,6 +263,13 @@ executable("fml_unittests") {
264263
"time/time_unittest.cc",
265264
]
266265

266+
if (is_mac) {
267+
sources += [
268+
"platform/darwin/cf_utils_unittests.mm",
269+
"platform/darwin/string_range_sanitization_unittests.mm",
270+
]
271+
}
272+
267273
deps = [
268274
":fml_fixtures",
269275
"//flutter/fml",

fml/platform/darwin/cf_utils.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,29 @@ class CFRef {
1818

1919
CFRef(T instance) : instance_(instance) {}
2020

21+
CFRef(const CFRef& other) : instance_(other.instance_) {
22+
if (instance_) {
23+
CFRetain(instance_);
24+
}
25+
}
26+
27+
CFRef(CFRef&& other) : instance_(other.instance_) {
28+
other.instance_ = nullptr;
29+
}
30+
31+
CFRef& operator=(CFRef&& other) {
32+
Reset(other.Release());
33+
return *this;
34+
}
35+
2136
~CFRef() {
2237
if (instance_ != nullptr) {
2338
CFRelease(instance_);
2439
}
2540
instance_ = nullptr;
2641
}
2742

28-
void Reset(T instance) {
43+
void Reset(T instance = nullptr) {
2944
if (instance_ == instance) {
3045
return;
3146
}
@@ -36,14 +51,20 @@ class CFRef {
3651
instance_ = instance;
3752
}
3853

54+
[[nodiscard]] T Release() {
55+
auto instance = instance_;
56+
instance_ = nullptr;
57+
return instance;
58+
}
59+
3960
operator T() const { return instance_; }
4061

4162
operator bool() const { return instance_ != nullptr; }
4263

4364
private:
4465
T instance_;
4566

46-
FML_DISALLOW_COPY_AND_ASSIGN(CFRef);
67+
CFRef& operator=(const CFRef&) = delete;
4768
};
4869

4970
} // namespace fml
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/fml/platform/darwin/cf_utils.h"
6+
#include "flutter/testing/testing.h"
7+
8+
namespace fml {
9+
namespace testing {
10+
11+
TEST(CFTest, CanCreateRefs) {
12+
CFRef<CFMutableStringRef> string(CFStringCreateMutable(kCFAllocatorDefault, 100u));
13+
// Cast
14+
ASSERT_TRUE(static_cast<bool>(string));
15+
ASSERT_TRUE(string);
16+
17+
const auto ref_count = CFGetRetainCount(string);
18+
19+
// Copy & Reset
20+
{
21+
CFRef<CFMutableStringRef> string2 = string;
22+
ASSERT_TRUE(string2);
23+
ASSERT_EQ(ref_count + 1u, CFGetRetainCount(string));
24+
ASSERT_EQ(CFGetRetainCount(string2), CFGetRetainCount(string));
25+
26+
string2.Reset();
27+
ASSERT_FALSE(string2);
28+
ASSERT_EQ(ref_count, CFGetRetainCount(string));
29+
}
30+
31+
// Release
32+
{
33+
auto string3 = string;
34+
ASSERT_TRUE(string3);
35+
ASSERT_EQ(ref_count + 1u, CFGetRetainCount(string));
36+
auto raw_string3 = string3.Release();
37+
ASSERT_FALSE(string3);
38+
ASSERT_EQ(ref_count + 1u, CFGetRetainCount(string));
39+
CFRelease(raw_string3);
40+
ASSERT_EQ(ref_count, CFGetRetainCount(string));
41+
}
42+
43+
// Move
44+
{
45+
auto string_source = string;
46+
ASSERT_TRUE(string_source);
47+
auto string_move = std::move(string_source);
48+
ASSERT_FALSE(string_source);
49+
ASSERT_EQ(ref_count + 1u, CFGetRetainCount(string));
50+
string_move.Reset();
51+
ASSERT_EQ(ref_count, CFGetRetainCount(string));
52+
}
53+
54+
// Move assign.
55+
{
56+
auto string_move_assign = std::move(string);
57+
ASSERT_FALSE(string);
58+
ASSERT_EQ(ref_count, CFGetRetainCount(string_move_assign));
59+
}
60+
}
61+
62+
} // namespace testing
63+
} // namespace fml

shell/platform/darwin/ios/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ shared_library("create_flutter_framework_dylib") {
131131
sources += [
132132
"ios_context_metal.h",
133133
"ios_context_metal.mm",
134+
"ios_external_texture_metal.h",
135+
"ios_external_texture_metal.mm",
134136
"ios_surface_metal.h",
135137
"ios_surface_metal.mm",
136138
]

shell/platform/darwin/ios/ios_context.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
#include <memory>
99

10+
#include "flutter/flow/texture.h"
1011
#include "flutter/fml/macros.h"
1112
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
13+
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterTexture.h"
1214
#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
1315
#include "third_party/skia/include/gpu/GrContext.h"
1416

@@ -119,6 +121,20 @@ class IOSContext {
119121
///
120122
virtual bool ClearCurrent() = 0;
121123

124+
//----------------------------------------------------------------------------
125+
/// @brief Creates an external texture proxy of the appropriate client
126+
/// rendering API.
127+
///
128+
/// @param[in] texture_id The texture identifier
129+
/// @param[in] texture The texture
130+
///
131+
/// @return The texture proxy if the rendering backend supports embedder
132+
/// provided external textures.
133+
///
134+
virtual std::unique_ptr<Texture> CreateExternalTexture(
135+
int64_t texture_id,
136+
fml::scoped_nsobject<NSObject<FlutterTexture>> texture) = 0;
137+
122138
protected:
123139
IOSContext();
124140

shell/platform/darwin/ios/ios_context_gl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ class IOSContextGL final : public IOSContext {
4040
// |IOSContext|
4141
bool ResourceMakeCurrent() override;
4242

43+
// |IOSContext|
44+
std::unique_ptr<Texture> CreateExternalTexture(
45+
int64_t texture_id,
46+
fml::scoped_nsobject<NSObject<FlutterTexture>> texture) override;
47+
4348
FML_DISALLOW_COPY_AND_ASSIGN(IOSContextGL);
4449
};
4550

shell/platform/darwin/ios/ios_context_gl.mm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "flutter/shell/common/shell_io_manager.h"
1010
#include "flutter/shell/gpu/gpu_surface_gl_delegate.h"
11+
#include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h"
1112

1213
namespace flutter {
1314

@@ -58,4 +59,11 @@
5859
return [EAGLContext setCurrentContext:nil];
5960
}
6061

62+
// |IOSContext|
63+
std::unique_ptr<Texture> IOSContextGL::CreateExternalTexture(
64+
int64_t texture_id,
65+
fml::scoped_nsobject<NSObject<FlutterTexture>> texture) {
66+
return std::make_unique<IOSExternalTextureGL>(texture_id, std::move(texture));
67+
}
68+
6169
} // namespace flutter

shell/platform/darwin/ios/ios_context_metal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <Metal/Metal.h>
99

1010
#include "flutter/fml/macros.h"
11+
#include "flutter/fml/platform/darwin/cf_utils.h"
1112
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
1213
#include "flutter/shell/platform/darwin/ios/ios_context.h"
1314
#include "third_party/skia/include/gpu/GrContext.h"
@@ -35,6 +36,7 @@ class IOSContextMetal final : public IOSContext {
3536
fml::scoped_nsprotocol<id<MTLCommandQueue>> main_queue_;
3637
sk_sp<GrContext> main_context_;
3738
sk_sp<GrContext> resource_context_;
39+
fml::CFRef<CVMetalTextureCacheRef> texture_cache_;
3840
bool is_valid_ = false;
3941

4042
// |IOSContext|
@@ -49,6 +51,11 @@ class IOSContextMetal final : public IOSContext {
4951
// |IOSContext|
5052
bool ClearCurrent() override;
5153

54+
// |IOSContext|
55+
std::unique_ptr<Texture> CreateExternalTexture(
56+
int64_t texture_id,
57+
fml::scoped_nsobject<NSObject<FlutterTexture>> texture) override;
58+
5259
FML_DISALLOW_COPY_AND_ASSIGN(IOSContextMetal);
5360
};
5461

0 commit comments

Comments
 (0)