Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 }
219 return TextureMTL::Create(desc, texture);
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
VkDevice device
Definition main.cc:53
static const uint8_t buffer[]
uint32_t uint32_t * format
#define FML_UNREACHABLE()
Definition logging.h:109
FlTexture * texture
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:33
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:100
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:77
MTLTextureDescriptor * ToMTLTextureDescriptor(const TextureDescriptor &desc)
static ISize DeviceMaxTextureSizeSupported(id< MTLDevice > device)
Definition ref_ptr.h:256
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define VALIDATION_LOG
Definition validation.h:73