| 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/renderer/backend/metal/device_buffer_mtl.h"
11 #include "impeller/renderer/backend/metal/formats_mtl.h"
12 #include "impeller/renderer/backend/metal/texture_mtl.h"
13
14 namespace impeller {
15
16 static 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 }
34 FML_UNREACHABLE();
35 }
36
37 static 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 }
49 FML_UNREACHABLE();
50 }
51
52 static ISize DeviceMaxTextureSizeSupported(id<MTLDevice> device) {
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
80 static 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
91 AllocatorMTL::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
104 AllocatorMTL::~AllocatorMTL() = default;
105
106 bool AllocatorMTL::IsValid() const {
107 return is_valid_;
108 }
109
110 static 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 }
137 FML_UNREACHABLE();
138 }
139 FML_UNREACHABLE();
140 }
141
142 static 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 }
169 FML_UNREACHABLE();
170 }
171 FML_UNREACHABLE();
172 }
173
174 std::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
192 std::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 &&
210 SupportsLossyTextureCompression(device_)) {
211 mtl_texture_desc.compressionType = MTLTextureCompressionTypeLossy;
212 }
213 }
214
215 auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc];
216 if (!texture) {
217 return nullptr;
218 }
219 return TextureMTL::Create(desc, texture);
220 }
221
222 uint16_t AllocatorMTL::MinimumBytesPerRow(PixelFormat format) const {
223 return static_cast<uint16_t>([device_
224 minimumLinearTextureAlignmentForPixelFormat:ToMTLPixelFormat(format)]);
225 }
226
227 ISize AllocatorMTL::GetMaxTextureSizeSupported() const {
228 return max_texture_supported_;
229 }
230
231 } // namespace impeller
impeller::DeviceHasUnifiedMemoryArchitecture
static bool DeviceHasUnifiedMemoryArchitecture(id< MTLDevice > device)
Definition: allocator_mtl.mm:37
allocator_mtl.h
formats_mtl.h
impeller::SupportsLossyTextureCompression
static bool SupportsLossyTextureCompression(id< MTLDevice > device)
Definition: allocator_mtl.mm:80
impeller::AllocatorMTL::AllocatorMTL
AllocatorMTL()
validation.h
impeller::ToMTLStorageMode
static MTLStorageMode ToMTLStorageMode(StorageMode mode, bool supports_memoryless_targets, bool supports_uma)
Definition: allocator_mtl.mm:142
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:100
impeller::ToMTLTextureDescriptor
MTLTextureDescriptor * ToMTLTextureDescriptor(const TextureDescriptor &desc)
Definition: formats_mtl.mm:86
impeller::TSize< int64_t >
impeller::StorageMode
StorageMode
Specified where the allocation resides and how it is used.
Definition: formats.h:33
impeller::ToMTLResourceOptions
static MTLResourceOptions ToMTLResourceOptions(StorageMode type, bool supports_memoryless_targets, bool supports_uma)
Definition: allocator_mtl.mm:110
impeller::DeviceSupportsDeviceTransientTargets
static bool DeviceSupportsDeviceTransientTargets(id< MTLDevice > device)
Definition: allocator_mtl.mm:16
impeller::DeviceMaxTextureSizeSupported
static ISize DeviceMaxTextureSizeSupported(id< MTLDevice > device)
Definition: allocator_mtl.mm:52
impeller::ToMTLPixelFormat
constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format)
Definition: formats_mtl.h:77
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
std
Definition: comparable.h:95
texture_mtl.h
impeller
Definition: aiks_blur_unittests.cc:20
device_buffer_mtl.h