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];
103#if FML_OS_IOS && !TARGET_OS_SIMULATOR
111ContextMTL::ContextMTL(
114 id<MTLCommandQueue> command_queue,
115 NSArray<id<MTLLibrary>>* shader_libraries,
116 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
117 std::optional<PixelFormat> pixel_format_override)
120 command_queue_(command_queue),
121 is_gpu_disabled_sync_switch_(
std::move(is_gpu_disabled_sync_switch)) {
128 sync_switch_observer_.reset(
new SyncSwitchObserver(*
this));
129 is_gpu_disabled_sync_switch_->AddObserver(sync_switch_observer_.get());
133 if (shader_libraries == nil) {
139 auto library = std::shared_ptr<ShaderLibraryMTL>(
140 new ShaderLibraryMTL(shader_libraries));
141 if (!library->IsValid()) {
145 shader_library_ = std::move(library);
151 std::shared_ptr<PipelineLibraryMTL>(
new PipelineLibraryMTL(device_));
157 std::shared_ptr<SamplerLibraryMTL>(
new SamplerLibraryMTL(device_));
162 resource_allocator_ = std::shared_ptr<AllocatorMTL>(
163 new AllocatorMTL(device_,
"Impeller Permanents Allocator"));
164 if (!resource_allocator_) {
170 device_capabilities_ =
172 ? pixel_format_override.value()
174 command_queue_ip_ = std::make_shared<CommandQueue>();
176 gpu_tracer_ = std::make_shared<GPUTracerMTL>();
177 capture_manager_ = std::make_shared<ImpellerMetalCaptureManager>(device_);
184 const std::vector<std::string>& libraries_paths) {
185 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
186 for (
const auto& library_path : libraries_paths) {
189 << library_path <<
"'";
192 NSError* shader_library_error = nil;
193 auto library = [
device newLibraryWithFile:@(library_path.c_str())
194 error:&shader_library_error];
196 FML_LOG(ERROR) <<
"Could not create shader library: "
197 << shader_library_error.localizedDescription.UTF8String;
200 [found_libraries addObject:library];
202 return found_libraries;
207 const std::vector<std::shared_ptr<fml::Mapping>>& libraries_data,
208 const std::string& label) {
209 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
210 for (
const auto& library_data : libraries_data) {
211 if (library_data ==
nullptr) {
212 FML_LOG(ERROR) <<
"Shader library data was null.";
216 __block
auto data = library_data;
219 ::dispatch_data_create(library_data->GetMapping(),
220 library_data->GetSize(),
221 dispatch_get_main_queue(),
227 if (!dispatch_data) {
228 FML_LOG(ERROR) <<
"Could not wrap shader data in dispatch data.";
232 NSError* shader_library_error = nil;
233 auto library = [
device newLibraryWithData:dispatch_data
234 error:&shader_library_error];
236 FML_LOG(ERROR) <<
"Could not create shader library: "
237 << shader_library_error.localizedDescription.UTF8String;
240 if (!label.empty()) {
241 library.label = @(label.c_str());
243 [found_libraries addObject:library];
245 return found_libraries;
249 return ::MTLCreateSystemDefaultDevice();
253 auto command_queue =
device.newCommandQueue;
254 if (!command_queue) {
258 command_queue.label =
@"Impeller Command Queue";
259 return command_queue;
262std::shared_ptr<ContextMTL> ContextMTL::Create(
264 const std::vector<std::string>& shader_library_paths,
265 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
268 if (!command_queue) {
272 flags,
device, command_queue,
274 std::move(is_gpu_disabled_sync_switch)));
276 FML_LOG(ERROR) <<
"Could not create Metal context.";
282std::shared_ptr<ContextMTL> ContextMTL::Create(
284 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
285 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
286 const std::string& library_label,
287 std::optional<PixelFormat> pixel_format_override) {
290 if (!command_queue) {
294 flags,
device, command_queue,
297 std::move(is_gpu_disabled_sync_switch), pixel_format_override));
299 FML_LOG(ERROR) <<
"Could not create Metal context.";
305std::shared_ptr<ContextMTL> ContextMTL::Create(
308 id<MTLCommandQueue> command_queue,
309 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
310 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
311 const std::string& library_label) {
312 auto context = std::shared_ptr<ContextMTL>(
316 std::move(is_gpu_disabled_sync_switch)));
318 FML_LOG(ERROR) <<
"Could not create Metal context.";
324ContextMTL::~ContextMTL() {
325 is_gpu_disabled_sync_switch_->RemoveObserver(sync_switch_observer_.get());
329 return Context::BackendType::kMetal;
333std::string ContextMTL::DescribeGpuModel()
const {
334 return std::string([[device_
name] UTF8String]);
338bool ContextMTL::IsValid()
const {
343std::shared_ptr<ShaderLibrary> ContextMTL::GetShaderLibrary()
const {
344 return shader_library_;
348std::shared_ptr<PipelineLibrary> ContextMTL::GetPipelineLibrary()
const {
349 return pipeline_library_;
353std::shared_ptr<SamplerLibrary> ContextMTL::GetSamplerLibrary()
const {
354 return sampler_library_;
358std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBuffer()
const {
359 return CreateCommandBufferInQueue(command_queue_);
363void ContextMTL::Shutdown() {}
366std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer()
const {
371std::shared_ptr<const fml::SyncSwitch> ContextMTL::GetIsGpuDisabledSyncSwitch()
373 return is_gpu_disabled_sync_switch_;
376std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
377 id<MTLCommandQueue>
queue)
const {
382 auto buffer = std::shared_ptr<CommandBufferMTL>(
383 new CommandBufferMTL(weak_from_this(), device_,
queue));
384 if (!buffer->IsValid()) {
390std::shared_ptr<Allocator> ContextMTL::GetResourceAllocator()
const {
391 return resource_allocator_;
394id<MTLDevice> ContextMTL::GetMTLDevice()
const {
398const std::shared_ptr<const Capabilities>& ContextMTL::GetCapabilities()
const {
399 return device_capabilities_;
402void ContextMTL::SetCapabilities(
403 const std::shared_ptr<const Capabilities>& capabilities) {
404 device_capabilities_ = capabilities;
408bool ContextMTL::UpdateOffscreenLayerPixelFormat(
PixelFormat format) {
413id<MTLCommandBuffer> ContextMTL::CreateMTLCommandBuffer(
414 const std::string& label)
const {
415 auto buffer = [command_queue_ commandBuffer];
416 if (!label.empty()) {
417 [buffer setLabel:@(label.data())];
424 std::vector<PendingTasks> failed_tasks;
426 Lock lock(tasks_awaiting_gpu_mutex_);
427 tasks_awaiting_gpu_.push_back(PendingTasks{task, failure});
428 int32_t failed_task_count =
429 tasks_awaiting_gpu_.size() - kMaxTasksAwaitingGPU;
430 if (failed_task_count > 0) {
431 failed_tasks.reserve(failed_task_count);
432 failed_tasks.insert(failed_tasks.end(),
433 std::make_move_iterator(tasks_awaiting_gpu_.begin()),
434 std::make_move_iterator(tasks_awaiting_gpu_.begin() +
436 tasks_awaiting_gpu_.erase(
437 tasks_awaiting_gpu_.begin(),
438 tasks_awaiting_gpu_.begin() + failed_task_count);
441 for (
const PendingTasks& task : failed_tasks) {
448void ContextMTL::FlushTasksAwaitingGPU() {
449 std::deque<PendingTasks> tasks_awaiting_gpu;
451 Lock lock(tasks_awaiting_gpu_mutex_);
452 std::swap(tasks_awaiting_gpu, tasks_awaiting_gpu_);
454 std::vector<PendingTasks> tasks_to_queue;
455 for (
const auto& task : tasks_awaiting_gpu) {
467 tasks_to_queue.push_back(task);
470 if (!tasks_to_queue.empty()) {
471 Lock lock(tasks_awaiting_gpu_mutex_);
472 tasks_awaiting_gpu_.insert(tasks_awaiting_gpu_.end(),
473 tasks_to_queue.begin(), tasks_to_queue.end());
477bool ContextMTL::FinishQueue() {
479 ContextMTL::Cast(
this)->CreateMTLCommandBuffer(
"Finish Queue Waiter");
491ContextMTL::SyncSwitchObserver::SyncSwitchObserver(
ContextMTL& parent)
494void ContextMTL::SyncSwitchObserver::OnSyncSwitchUpdate(
bool new_is_disabled) {
495 if (!new_is_disabled) {
496 parent_.FlushTasksAwaitingGPU();
502 return command_queue_ip_;
511const std::shared_ptr<ImpellerMetalCaptureManager>
512ContextMTL::GetCaptureManager()
const {
513 return capture_manager_;
518 current_capture_scope_ = [[MTLCaptureManager sharedCaptureManager]
519 newCaptureScopeWithDevice:
device];
520 [current_capture_scope_ setLabel:
@"Impeller Frame"];
521 [[MTLCaptureManager sharedCaptureManager]
522 setDefaultCaptureScope:current_capture_scope_];
526 return scope_active_;
533 scope_active_ =
true;
534 [current_capture_scope_ beginScope];
539 [current_capture_scope_ endScope];
540 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 & 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.