Flutter Engine
The Flutter Engine
allocator_mtl.mm
Go to the documentation of this file.
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
6
7#include "flutter/fml/build_config.h"
8#include "flutter/fml/logging.h"
13
14namespace impeller {
15
16static bool DeviceSupportsDeviceTransientTargets(id<MTLDevice> device) {
17 // Refer to the "Memoryless render targets" feature in the table below:
18 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
19 if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) {
20 return [device supportsFamily:MTLGPUFamilyApple2];
21 } else {
22#if FML_OS_IOS
23 // This is perhaps redundant. But, just in case we somehow get into a case
24 // where Impeller runs on iOS versions less than 8.0 and/or without A8
25 // GPUs, we explicitly check feature set support.
26 return [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1];
27#else
28 // MacOS devices with Apple GPUs are only available with macos 10.15 and
29 // above. So, if we are here, it is safe to assume that memory-less targets
30 // are not supported.
31 return false;
32#endif
33 }
35}
36
37static bool DeviceHasUnifiedMemoryArchitecture(id<MTLDevice> device) {
38 if (@available(ios 13.0, tvos 13.0, macOS 10.15, *)) {
39 return [device hasUnifiedMemory];
40 } else {
41#if FML_OS_IOS
42 // iOS devices where the availability check can fail always have had UMA.
43 return true;
44#else
45 // Mac devices where the availability check can fail have never had UMA.
46 return false;
47#endif
48 }
50}
51
53 // Since Apple didn't expose API for us to get the max texture size, we have
54 // to use hardcoded data from
55 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
56 // According to the feature set table, there are two supported max sizes :
57 // 16384 and 8192 for devices flutter support. The former is used on macs and
58 // latest ios devices. The latter is used on old ios devices.
59 if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
60 if ([device supportsFamily:MTLGPUFamilyApple3] ||
61 [device supportsFamily:MTLGPUFamilyMacCatalyst1] ||
62 [device supportsFamily:MTLGPUFamilyMac1]) {
63 return {16384, 16384};
64 }
65 return {8192, 8192};
66 } else {
67#if FML_OS_IOS
68 if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1] ||
69 [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
70 return {16384, 16384};
71 }
72#endif
73#if FML_OS_MACOSX
74 return {16384, 16384};
75#endif
76 return {8192, 8192};
77 }
78}
79
80static bool SupportsLossyTextureCompression(id<MTLDevice> device) {
81#ifdef FML_OS_IOS_SIMULATOR
82 return false;
83#else
84 if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
85 return [device supportsFamily:MTLGPUFamilyApple8];
86 }
87 return false;
88#endif
89}
90
91AllocatorMTL::AllocatorMTL(id<MTLDevice> device, std::string label)
92 : device_(device), allocator_label_(std::move(label)) {
93 if (!device_) {
94 return;
95 }
96
97 supports_memoryless_targets_ = DeviceSupportsDeviceTransientTargets(device_);
98 supports_uma_ = DeviceHasUnifiedMemoryArchitecture(device_);
99 max_texture_supported_ = DeviceMaxTextureSizeSupported(device_);
100
101 is_valid_ = true;
102}
103
104AllocatorMTL::~AllocatorMTL() = default;
105
106bool AllocatorMTL::IsValid() const {
107 return is_valid_;
108}
109
110static MTLResourceOptions ToMTLResourceOptions(StorageMode type,
111 bool supports_memoryless_targets,
112 bool supports_uma) {
113 switch (type) {
114 case StorageMode::kHostVisible:
115#if FML_OS_IOS
116 return MTLResourceStorageModeShared;
117#else
118 if (supports_uma) {
119 return MTLResourceStorageModeShared;
120 } else {
121 return MTLResourceStorageModeManaged;
122 }
123#endif
124 case StorageMode::kDevicePrivate:
125 return MTLResourceStorageModePrivate;
126 case StorageMode::kDeviceTransient:
127 if (supports_memoryless_targets) {
128 // Device may support but the OS has not been updated.
129 if (@available(macOS 11.0, *)) {
130 return MTLResourceStorageModeMemoryless;
131 } else {
132 return MTLResourceStorageModePrivate;
133 }
134 } else {
135 return MTLResourceStorageModePrivate;
136 }
138 }
140}
141
142static MTLStorageMode ToMTLStorageMode(StorageMode mode,
143 bool supports_memoryless_targets,
144 bool supports_uma) {
145 switch (mode) {
146 case StorageMode::kHostVisible:
147#if FML_OS_IOS
148 return MTLStorageModeShared;
149#else
150 if (supports_uma) {
151 return MTLStorageModeShared;
152 } else {
153 return MTLStorageModeManaged;
154 }
155#endif
156 case StorageMode::kDevicePrivate:
157 return MTLStorageModePrivate;
158 case StorageMode::kDeviceTransient:
159 if (supports_memoryless_targets) {
160 // Device may support but the OS has not been updated.
161 if (@available(macOS 11.0, *)) {
162 return MTLStorageModeMemoryless;
163 } else {
164 return MTLStorageModePrivate;
165 }
166 } else {
167 return MTLStorageModePrivate;
168 }
170 }
172}
173
174std::shared_ptr<DeviceBuffer> AllocatorMTL::OnCreateBuffer(
175 const DeviceBufferDescriptor& desc) {
176 const auto resource_options = ToMTLResourceOptions(
177 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
178 const auto storage_mode = ToMTLStorageMode(
179 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
180
181 auto buffer = [device_ newBufferWithLength:desc.size
182 options:resource_options];
183 if (!buffer) {
184 return nullptr;
185 }
186 return std::shared_ptr<DeviceBufferMTL>(new DeviceBufferMTL(desc, //
187 buffer, //
188 storage_mode //
189 ));
190}
191
192std::shared_ptr<Texture> AllocatorMTL::OnCreateTexture(
193 const TextureDescriptor& desc) {
194 if (!IsValid()) {
195 return nullptr;
196 }
197
198 auto mtl_texture_desc = ToMTLTextureDescriptor(desc);
199
200 if (!mtl_texture_desc) {
201 VALIDATION_LOG << "Texture descriptor was invalid.";
202 return nullptr;
203 }
204
205 mtl_texture_desc.storageMode = ToMTLStorageMode(
206 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
207
208 if (@available(macOS 12.5, ios 15.0, *)) {
209 if (desc.compression_type == CompressionType::kLossy &&
211 mtl_texture_desc.compressionType = MTLTextureCompressionTypeLossy;
212 }
213 }
214
215 auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc];
216 if (!texture) {
217 return nullptr;
218 }
220}
221
222uint16_t AllocatorMTL::MinimumBytesPerRow(PixelFormat format) const {
223 return static_cast<uint16_t>([device_
224 minimumLinearTextureAlignmentForPixelFormat:ToMTLPixelFormat(format)]);
225}
226
227ISize AllocatorMTL::GetMaxTextureSizeSupported() const {
228 return max_texture_supported_;
229}
230
231} // namespace impeller
const char * options
static sk_sp< Effect > Create()
Definition: RefCntTest.cpp:117
GLenum type
VkDevice device
Definition: main.cc:53
uint32_t uint32_t * format
#define FML_UNREACHABLE()
Definition: logging.h:109
FlTexture * texture
SK_API sk_sp< SkSurface > ios(9.0)
SK_API sk_sp< SkSurface > tvos(9.0))
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
static MTLStorageMode ToMTLStorageMode(StorageMode mode, bool supports_memoryless_targets, bool supports_uma)
static bool DeviceHasUnifiedMemoryArchitecture(id< MTLDevice > device)
StorageMode
Specified where the allocation resides and how it is used.
Definition: formats.h:32
static bool SupportsLossyTextureCompression(id< MTLDevice > device)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
static MTLResourceOptions ToMTLResourceOptions(StorageMode type, bool supports_memoryless_targets, bool supports_uma)
static bool DeviceSupportsDeviceTransientTargets(id< MTLDevice > device)
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:76
ISize64 ISize
Definition: size.h:140
MTLTextureDescriptor * ToMTLTextureDescriptor(const TextureDescriptor &desc)
Definition: formats_mtl.mm:86
static ISize DeviceMaxTextureSizeSupported(id< MTLDevice > device)
Definition: ref_ptr.h:256
#define VALIDATION_LOG
Definition: validation.h:73