6#include <Metal/Metal.h>
25#if FML_OS_IOS_SIMULATOR
32 return [
device supportsFamily:MTLGPUFamilyApple2];
39 return [
device supportsFamily:MTLGPUFamilyApple7] ||
40 [
device supportsFamily:MTLGPUFamilyMac2];
49 return [
device supportsFamily:MTLGPUFamilyApple3];
56 return [
device supportsFamily:MTLGPUFamilyMac2] ||
57 [
device supportsFamily:MTLGPUFamilyApple7];
63 return [
device supportsFamily:MTLGPUFamilyApple2];
68 return [
device supportsFamily:MTLGPUFamilyApple6];
106#if FML_OS_IOS && !TARGET_OS_SIMULATOR
114ContextMTL::ContextMTL(
117 id<MTLCommandQueue> command_queue,
118 NSArray<id<MTLLibrary>>* shader_libraries,
119 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
120 std::optional<PixelFormat> pixel_format_override)
123 command_queue_(command_queue),
124 is_gpu_disabled_sync_switch_(
std::move(is_gpu_disabled_sync_switch)) {
131 sync_switch_observer_.reset(
new SyncSwitchObserver(*
this));
132 is_gpu_disabled_sync_switch_->AddObserver(sync_switch_observer_.get());
136 if (shader_libraries == nil) {
142 auto library = std::shared_ptr<ShaderLibraryMTL>(
143 new ShaderLibraryMTL(shader_libraries));
144 if (!library->IsValid()) {
148 shader_library_ = std::move(library);
154 std::shared_ptr<PipelineLibraryMTL>(
new PipelineLibraryMTL(device_));
160 std::shared_ptr<SamplerLibraryMTL>(
new SamplerLibraryMTL(device_));
165 resource_allocator_ = std::shared_ptr<AllocatorMTL>(
166 new AllocatorMTL(device_,
"Impeller Permanents Allocator"));
167 if (!resource_allocator_) {
173 device_capabilities_ =
175 ? pixel_format_override.value()
177 command_queue_ip_ = std::make_shared<CommandQueue>();
179 gpu_tracer_ = std::make_shared<GPUTracerMTL>();
180 capture_manager_ = std::make_shared<ImpellerMetalCaptureManager>(device_);
187 const std::vector<std::string>& libraries_paths) {
188 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
189 for (
const auto& library_path : libraries_paths) {
192 << library_path <<
"'";
195 NSError* shader_library_error = nil;
196 auto library = [
device newLibraryWithFile:@(library_path.c_str())
197 error:&shader_library_error];
199 FML_LOG(ERROR) <<
"Could not create shader library: "
200 << shader_library_error.localizedDescription.UTF8String;
203 [found_libraries addObject:library];
205 return found_libraries;
210 const std::vector<std::shared_ptr<fml::Mapping>>& libraries_data,
211 const std::string& label) {
212 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
213 for (
const auto& library_data : libraries_data) {
214 if (library_data ==
nullptr) {
215 FML_LOG(ERROR) <<
"Shader library data was null.";
219 __block
auto data = library_data;
222 ::dispatch_data_create(library_data->GetMapping(),
223 library_data->GetSize(),
224 dispatch_get_main_queue(),
230 if (!dispatch_data) {
231 FML_LOG(ERROR) <<
"Could not wrap shader data in dispatch data.";
235 NSError* shader_library_error = nil;
236 auto library = [
device newLibraryWithData:dispatch_data
237 error:&shader_library_error];
239 FML_LOG(ERROR) <<
"Could not create shader library: "
240 << shader_library_error.localizedDescription.UTF8String;
243 if (!label.empty()) {
244 library.label = @(label.c_str());
246 [found_libraries addObject:library];
248 return found_libraries;
252 return ::MTLCreateSystemDefaultDevice();
256 auto command_queue =
device.newCommandQueue;
257 if (!command_queue) {
261 command_queue.label =
@"Impeller Command Queue";
262 return command_queue;
265std::shared_ptr<ContextMTL> ContextMTL::Create(
267 const std::vector<std::string>& shader_library_paths,
268 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
271 if (!command_queue) {
275 flags,
device, command_queue,
277 std::move(is_gpu_disabled_sync_switch)));
279 FML_LOG(ERROR) <<
"Could not create Metal context.";
285std::shared_ptr<ContextMTL> ContextMTL::Create(
287 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
288 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
289 const std::string& library_label,
290 std::optional<PixelFormat> pixel_format_override) {
293 if (!command_queue) {
297 flags,
device, command_queue,
300 std::move(is_gpu_disabled_sync_switch), pixel_format_override));
302 FML_LOG(ERROR) <<
"Could not create Metal context.";
308std::shared_ptr<ContextMTL> ContextMTL::Create(
311 id<MTLCommandQueue> command_queue,
312 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
313 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
314 const std::string& library_label) {
315 auto context = std::shared_ptr<ContextMTL>(
319 std::move(is_gpu_disabled_sync_switch)));
321 FML_LOG(ERROR) <<
"Could not create Metal context.";
327ContextMTL::~ContextMTL() {
328 is_gpu_disabled_sync_switch_->RemoveObserver(sync_switch_observer_.get());
332 return Context::BackendType::kMetal;
336std::string ContextMTL::DescribeGpuModel()
const {
337 return std::string([[device_
name] UTF8String]);
341bool ContextMTL::IsValid()
const {
346std::shared_ptr<ShaderLibrary> ContextMTL::GetShaderLibrary()
const {
347 return shader_library_;
351std::shared_ptr<PipelineLibrary> ContextMTL::GetPipelineLibrary()
const {
352 return pipeline_library_;
356std::shared_ptr<SamplerLibrary> ContextMTL::GetSamplerLibrary()
const {
357 return sampler_library_;
361std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBuffer()
const {
362 return CreateCommandBufferInQueue(command_queue_);
366void ContextMTL::Shutdown() {}
369std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer()
const {
374std::shared_ptr<const fml::SyncSwitch> ContextMTL::GetIsGpuDisabledSyncSwitch()
376 return is_gpu_disabled_sync_switch_;
379std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
380 id<MTLCommandQueue>
queue)
const {
385 auto buffer = std::shared_ptr<CommandBufferMTL>(
386 new CommandBufferMTL(weak_from_this(), device_,
queue));
387 if (!buffer->IsValid()) {
393std::shared_ptr<Allocator> ContextMTL::GetResourceAllocator()
const {
394 return resource_allocator_;
397id<MTLDevice> ContextMTL::GetMTLDevice()
const {
401const std::shared_ptr<const Capabilities>& ContextMTL::GetCapabilities()
const {
402 return device_capabilities_;
405void ContextMTL::SetCapabilities(
406 const std::shared_ptr<const Capabilities>& capabilities) {
407 device_capabilities_ = capabilities;
411bool ContextMTL::UpdateOffscreenLayerPixelFormat(
PixelFormat format) {
416id<MTLCommandBuffer> ContextMTL::CreateMTLCommandBuffer(
417 const std::string& label)
const {
418 auto buffer = [command_queue_ commandBuffer];
419 if (!label.empty()) {
420 [buffer setLabel:@(label.data())];
427 std::vector<PendingTasks> failed_tasks;
429 Lock lock(tasks_awaiting_gpu_mutex_);
430 tasks_awaiting_gpu_.push_back(PendingTasks{task, failure});
431 int32_t failed_task_count =
432 tasks_awaiting_gpu_.size() - kMaxTasksAwaitingGPU;
433 if (failed_task_count > 0) {
434 failed_tasks.reserve(failed_task_count);
435 failed_tasks.insert(failed_tasks.end(),
436 std::make_move_iterator(tasks_awaiting_gpu_.begin()),
437 std::make_move_iterator(tasks_awaiting_gpu_.begin() +
439 tasks_awaiting_gpu_.erase(
440 tasks_awaiting_gpu_.begin(),
441 tasks_awaiting_gpu_.begin() + failed_task_count);
444 for (
const PendingTasks& task : failed_tasks) {
451void ContextMTL::FlushTasksAwaitingGPU() {
452 std::deque<PendingTasks> tasks_awaiting_gpu;
454 Lock lock(tasks_awaiting_gpu_mutex_);
455 std::swap(tasks_awaiting_gpu, tasks_awaiting_gpu_);
457 std::vector<PendingTasks> tasks_to_queue;
458 for (
const auto& task : tasks_awaiting_gpu) {
470 tasks_to_queue.push_back(task);
473 if (!tasks_to_queue.empty()) {
474 Lock lock(tasks_awaiting_gpu_mutex_);
475 tasks_awaiting_gpu_.insert(tasks_awaiting_gpu_.end(),
476 tasks_to_queue.begin(), tasks_to_queue.end());
480bool ContextMTL::FinishQueue() {
482 ContextMTL::Cast(
this)->CreateMTLCommandBuffer(
"Finish Queue Waiter");
494ContextMTL::SyncSwitchObserver::SyncSwitchObserver(
ContextMTL& parent)
497void ContextMTL::SyncSwitchObserver::OnSyncSwitchUpdate(
bool new_is_disabled) {
498 if (!new_is_disabled) {
499 parent_.FlushTasksAwaitingGPU();
505 return command_queue_ip_;
514const std::shared_ptr<ImpellerMetalCaptureManager>
515ContextMTL::GetCaptureManager()
const {
516 return capture_manager_;
521 current_capture_scope_ = [[MTLCaptureManager sharedCaptureManager]
522 newCaptureScopeWithDevice:
device];
523 [current_capture_scope_ setLabel:
@"Impeller Frame"];
524 [[MTLCaptureManager sharedCaptureManager]
525 setDefaultCaptureScope:current_capture_scope_];
529 return scope_active_;
536 scope_active_ =
true;
537 [current_capture_scope_ beginScope];
542 [current_capture_scope_ endScope];
543 scope_active_ =
false;
CapabilitiesBuilder & SetDefaultColorFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsComputeSubgroups(bool value)
CapabilitiesBuilder & SetMinimumUniformAlignment(size_t value)
CapabilitiesBuilder & SetSupportsTextureToTextureBlits(bool value)
CapabilitiesBuilder & SetDefaultStencilFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsDeviceTransientTextures(bool value)
CapabilitiesBuilder & SetSupportsTriangleFan(bool value)
CapabilitiesBuilder & SetMaxSamplerAnisotropy(uint32_t value)
CapabilitiesBuilder & SetSupportsFramebufferFetch(bool value)
CapabilitiesBuilder & SetSupportsDecalSamplerAddressMode(bool value)
CapabilitiesBuilder & SetSupportsTextureCompression(CompressedTextureFamily family, bool value)
CapabilitiesBuilder & SetSupportsOffscreenMSAA(bool value)
CapabilitiesBuilder & SetSupportsSSBO(bool value)
CapabilitiesBuilder & SetMaximumRenderPassAttachmentSize(ISize size)
CapabilitiesBuilder & SetSupportsExtendedRangeFormats(bool value)
CapabilitiesBuilder & SetDefaultGlyphAtlasFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsCompute(bool value)
std::unique_ptr< Capabilities > Build()
CapabilitiesBuilder & SetDefaultDepthStencilFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsReadFromResolve(bool value)
std::shared_ptr< CommandQueue > GetCommandQueue() const override
Return the graphics queue for submitting command buffers.
RuntimeStageBackend GetRuntimeStageBackend() const override
Retrieve the runtime stage for this context type.
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
#define FML_LOG(severity)
#define FML_DCHECK(condition)
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
bool IsFile(const std::string &path)
std::function< void()> closure
static bool DeviceSupportsExtendedRangeFormats(id< MTLDevice > device)
static bool DeviceSupportsTextureCompressionMobile(id< MTLDevice > device)
static NSArray< id< MTLLibrary > > * MTLShaderLibraryFromFilePaths(id< MTLDevice > device, const std::vector< std::string > &libraries_paths)
static id< MTLCommandQueue > CreateMetalCommandQueue(id< MTLDevice > device)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
static id< MTLDevice > CreateMetalDevice()
static NSArray< id< MTLLibrary > > * MTLShaderLibraryFromFileData(id< MTLDevice > device, const std::vector< std::shared_ptr< fml::Mapping > > &libraries_data, const std::string &label)
@ kASTCHDR
ASTC HDR. A separate device feature from ASTC LDR.
@ kBC
S3TC, RGTC, and BPTC (BC1 through BC7). Desktop GPUs.
@ kETC2
ETC2 and EAC. Mobile, OpenGL ES 3.0, and WebGL2.
@ kASTC
ASTC LDR. Modern mobile and some desktop.
ISize DeviceMaxTextureSizeSupported(id< MTLDevice > device)
static bool DeviceSupportsTextureCompressionAstcHdr(id< MTLDevice > device)
static bool DeviceSupportsComputeSubgroups(id< MTLDevice > device)
static bool DeviceSupportsFramebufferFetch(id< MTLDevice > device)
static std::unique_ptr< Capabilities > InferMetalCapabilities(id< MTLDevice > device, PixelFormat color_format)
static bool DeviceSupportsTextureCompressionBC(id< MTLDevice > device)
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
Represents the 2 code paths available when calling |SyncSwitchExecute|.
Handlers & SetIfFalse(const std::function< void()> &handler)
Sets the handler that will be executed if the |SyncSwitch| is false.