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