| Flutter Impeller |

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
5 #include "impeller/renderer/backend/metal/allocator_mtl.h"
6
7 #include "flutter/fml/build_config.h"
8 #include "flutter/fml/logging.h"
9 #include "impeller/base/validation.h"
10 #include "impeller/core/buffer.h"
11 #include "impeller/renderer/backend/metal/device_buffer_mtl.h"
12 #include "impeller/renderer/backend/metal/formats_mtl.h"
13 #include "impeller/renderer/backend/metal/texture_mtl.h"
14
15 namespace impeller {
16
17 static bool DeviceSupportsDeviceTransientTargets(id<MTLDevice> device) {
18 // Refer to the "Memoryless render targets" feature in the table below:
19 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
20 if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) {
21 return [device supportsFamily:MTLGPUFamilyApple2];
22 } else {
23 #if FML_OS_IOS
24 // This is perhaps redundant. But, just in case we somehow get into a case
25 // where Impeller runs on iOS versions less than 8.0 and/or without A8
26 // GPUs, we explicitly check feature set support.
27 return [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1];
28 #else
29 // MacOS devices with Apple GPUs are only available with macos 10.15 and
30 // above. So, if we are here, it is safe to assume that memory-less targets
31 // are not supported.
32 return false;
33 #endif
34 }
35 FML_UNREACHABLE();
36 }
37
38 static bool DeviceHasUnifiedMemoryArchitecture(id<MTLDevice> device) {
39 if (@available(ios 13.0, tvos 13.0, macOS 10.15, *)) {
40 return [device hasUnifiedMemory];
41 } else {
42 #if FML_OS_IOS
43 // iOS devices where the availability check can fail always have had UMA.
44 return true;
45 #else
46 // Mac devices where the availability check can fail have never had UMA.
47 return false;
48 #endif
49 }
50 FML_UNREACHABLE();
51 }
52
53 static ISize DeviceMaxTextureSizeSupported(id<MTLDevice> device) {
54 // Since Apple didn't expose API for us to get the max texture size, we have
55 // to use hardcoded data from
56 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
57 // According to the feature set table, there are two supported max sizes :
58 // 16384 and 8192 for devices flutter support. The former is used on macs and
59 // latest ios devices. The latter is used on old ios devices.
60 if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
61 if ([device supportsFamily:MTLGPUFamilyApple3] ||
62 [device supportsFamily:MTLGPUFamilyMacCatalyst1] ||
63 [device supportsFamily:MTLGPUFamilyMac1]) {
64 return {16384, 16384};
65 }
66 return {8192, 8192};
67 } else {
68 #if FML_OS_IOS
69 if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1] ||
70 [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
71 return {16384, 16384};
72 }
73 #endif
74 #if FML_OS_MACOSX
75 return {16384, 16384};
76 #endif
77 return {8192, 8192};
78 }
79 }
80
81 static bool SupportsLossyTextureCompression(id<MTLDevice> device) {
82 #ifdef FML_OS_IOS_SIMULATOR
83 return false;
84 #else
85 if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
86 return [device supportsFamily:MTLGPUFamilyApple8];
87 }
88 return false;
89 #endif
90 }
91
92 AllocatorMTL::AllocatorMTL(id<MTLDevice> device, std::string label)
93 : device_(device), allocator_label_(std::move(label)) {
94 if (!device_) {
95 return;
96 }
97
98 supports_memoryless_targets_ = DeviceSupportsDeviceTransientTargets(device_);
99 supports_uma_ = DeviceHasUnifiedMemoryArchitecture(device_);
100 max_texture_supported_ = DeviceMaxTextureSizeSupported(device_);
101
102 is_valid_ = true;
103 }
104
105 AllocatorMTL::~AllocatorMTL() = default;
106
107 bool AllocatorMTL::IsValid() const {
108 return is_valid_;
109 }
110
111 static MTLResourceOptions ToMTLResourceOptions(StorageMode type,
112 bool supports_memoryless_targets,
113 bool supports_uma) {
114 switch (type) {
115 case StorageMode::kHostVisible:
116 #if FML_OS_IOS
117 return MTLResourceStorageModeShared;
118 #else
119 if (supports_uma) {
120 return MTLResourceStorageModeShared;
121 } else {
122 return MTLResourceStorageModeManaged;
123 }
124 #endif
125 case StorageMode::kDevicePrivate:
126 return MTLResourceStorageModePrivate;
127 case StorageMode::kDeviceTransient:
128 if (supports_memoryless_targets) {
129 // Device may support but the OS has not been updated.
130 if (@available(macOS 11.0, *)) {
131 return MTLResourceStorageModeMemoryless;
132 } else {
133 return MTLResourceStorageModePrivate;
134 }
135 } else {
136 return MTLResourceStorageModePrivate;
137 }
138 FML_UNREACHABLE();
139 }
140 FML_UNREACHABLE();
141 }
142
143 static MTLStorageMode ToMTLStorageMode(StorageMode mode,
144 bool supports_memoryless_targets,
145 bool supports_uma) {
146 switch (mode) {
147 case StorageMode::kHostVisible:
148 #if FML_OS_IOS
149 return MTLStorageModeShared;
150 #else
151 if (supports_uma) {
152 return MTLStorageModeShared;
153 } else {
154 return MTLStorageModeManaged;
155 }
156 #endif
157 case StorageMode::kDevicePrivate:
158 return MTLStorageModePrivate;
159 case StorageMode::kDeviceTransient:
160 if (supports_memoryless_targets) {
161 // Device may support but the OS has not been updated.
162 if (@available(macOS 11.0, *)) {
163 return MTLStorageModeMemoryless;
164 } else {
165 return MTLStorageModePrivate;
166 }
167 } else {
168 return MTLStorageModePrivate;
169 }
170 FML_UNREACHABLE();
171 }
172 FML_UNREACHABLE();
173 }
174
175 std::shared_ptr<DeviceBuffer> AllocatorMTL::OnCreateBuffer(
176 const DeviceBufferDescriptor& desc) {
177 const auto resource_options = ToMTLResourceOptions(
178 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
179 const auto storage_mode = ToMTLStorageMode(
180 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
181
182 auto buffer = [device_ newBufferWithLength:desc.size
183 options:resource_options];
184 if (!buffer) {
185 return nullptr;
186 }
187 return std::shared_ptr<DeviceBufferMTL>(new DeviceBufferMTL(desc, //
188 buffer, //
189 storage_mode //
190 ));
191 }
192
193 std::shared_ptr<Texture> AllocatorMTL::OnCreateTexture(
194 const TextureDescriptor& desc) {
195 if (!IsValid()) {
196 return nullptr;
197 }
198
199 auto mtl_texture_desc = ToMTLTextureDescriptor(desc);
200
201 if (!mtl_texture_desc) {
202 VALIDATION_LOG << "Texture descriptor was invalid.";
203 return nullptr;
204 }
205
206 mtl_texture_desc.storageMode = ToMTLStorageMode(
207 desc.storage_mode, supports_memoryless_targets_, supports_uma_);
208
209 if (@available(macOS 12.5, ios 15.0, *)) {
210 if (desc.compression_type == CompressionType::kLossy &&
211 SupportsLossyTextureCompression(device_)) {
212 mtl_texture_desc.compressionType = MTLTextureCompressionTypeLossy;
213 }
214 }
215
216 auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc];
217 if (!texture) {
218 return nullptr;
219 }
220 return std::make_shared<TextureMTL>(desc, texture);
221 }
222
223 uint16_t AllocatorMTL::MinimumBytesPerRow(PixelFormat format) const {
224 return static_cast<uint16_t>([device_
225 minimumLinearTextureAlignmentForPixelFormat:ToMTLPixelFormat(format)]);
226 }
227
228 ISize AllocatorMTL::GetMaxTextureSizeSupported() const {
229 return max_texture_supported_;
230 }
231
232 } // namespace impeller
impeller::DeviceHasUnifiedMemoryArchitecture
static bool DeviceHasUnifiedMemoryArchitecture(id< MTLDevice > device)
Definition: allocator_mtl.mm:38
allocator_mtl.h
formats_mtl.h
impeller::SupportsLossyTextureCompression
static bool SupportsLossyTextureCompression(id< MTLDevice > device)
Definition: allocator_mtl.mm:81
impeller::AllocatorMTL::AllocatorMTL
AllocatorMTL()
validation.h
impeller::ToMTLStorageMode
static MTLStorageMode ToMTLStorageMode(StorageMode mode, bool supports_memoryless_targets, bool supports_uma)
Definition: allocator_mtl.mm:143
impeller::ToMTLTextureDescriptor
MTLTextureDescriptor * ToMTLTextureDescriptor(const TextureDescriptor &desc)
Definition: formats_mtl.mm:86
impeller::TSize
Definition: size.h:18
impeller::StorageMode
StorageMode
Specified where the allocation resides and how it is used.
Definition: formats.h:27
impeller::ToMTLResourceOptions
static MTLResourceOptions ToMTLResourceOptions(StorageMode type, bool supports_memoryless_targets, bool supports_uma)
Definition: allocator_mtl.mm:111
impeller::DeviceSupportsDeviceTransientTargets
static bool DeviceSupportsDeviceTransientTargets(id< MTLDevice > device)
Definition: allocator_mtl.mm:17
impeller::DeviceMaxTextureSizeSupported
static ISize DeviceMaxTextureSizeSupported(id< MTLDevice > device)
Definition: allocator_mtl.mm:53
buffer.h
impeller::ToMTLPixelFormat
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:75
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:136
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
std
Definition: comparable.h:98
texture_mtl.h
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:94
impeller
Definition: aiks_context.cc:10
device_buffer_mtl.h