9#include "flutter/fml/concurrent_message_loop.h"
10#include "flutter/fml/file.h"
11#include "flutter/fml/logging.h"
12#include "flutter/fml/paths.h"
13#include "flutter/fml/synchronization/sync_switch.h"
24#if FML_OS_IOS_SIMULATOR
28 if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
29 return [
device supportsFamily:MTLGPUFamilyApple2];
35 return [
device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1];
43 bool supports_subgroups =
false;
46 if (@available(
ios 13.0,
tvos 13.0, macos 10.15, *)) {
47 supports_subgroups = [
device supportsFamily:MTLGPUFamilyApple7] ||
48 [
device supportsFamily:MTLGPUFamilyMac2];
50 return supports_subgroups;
73ContextMTL::ContextMTL(
75 id<MTLCommandQueue> command_queue,
76 NSArray<id<MTLLibrary>>* shader_libraries,
77 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
78 std::optional<PixelFormat> pixel_format_override)
80 command_queue_(command_queue),
81 is_gpu_disabled_sync_switch_(
std::move(is_gpu_disabled_sync_switch)) {
88 sync_switch_observer_.reset(
new SyncSwitchObserver(*
this));
89 is_gpu_disabled_sync_switch_->AddObserver(sync_switch_observer_.get());
93 if (shader_libraries == nil) {
99 auto library = std::shared_ptr<ShaderLibraryMTL>(
100 new ShaderLibraryMTL(shader_libraries));
101 if (!library->IsValid()) {
105 shader_library_ = std::move(library);
111 std::shared_ptr<PipelineLibraryMTL>(
new PipelineLibraryMTL(device_));
117 std::shared_ptr<SamplerLibraryMTL>(
new SamplerLibraryMTL(device_));
122 resource_allocator_ = std::shared_ptr<AllocatorMTL>(
123 new AllocatorMTL(device_,
"Impeller Permanents Allocator"));
124 if (!resource_allocator_) {
130 device_capabilities_ =
132 ? pixel_format_override.value()
134 command_queue_ip_ = std::make_shared<CommandQueue>();
136 gpu_tracer_ = std::make_shared<GPUTracerMTL>();
143 const std::vector<std::string>& libraries_paths) {
144 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
145 for (
const auto& library_path : libraries_paths) {
148 << library_path <<
"'";
151 NSError* shader_library_error = nil;
152 auto library = [
device newLibraryWithFile:@(library_path.c_str())
153 error:&shader_library_error];
156 << shader_library_error.localizedDescription.UTF8String;
159 [found_libraries addObject:library];
161 return found_libraries;
166 const std::vector<std::shared_ptr<fml::Mapping>>& libraries_data,
167 const std::string& label) {
168 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
169 for (
const auto& library_data : libraries_data) {
170 if (library_data ==
nullptr) {
175 __block
auto data = library_data;
178 ::dispatch_data_create(library_data->GetMapping(),
179 library_data->GetSize(),
180 dispatch_get_main_queue(),
186 if (!dispatch_data) {
187 FML_LOG(
ERROR) <<
"Could not wrap shader data in dispatch data.";
191 NSError* shader_library_error = nil;
192 auto library = [
device newLibraryWithData:dispatch_data
193 error:&shader_library_error];
196 << shader_library_error.localizedDescription.UTF8String;
199 if (!label.empty()) {
200 library.label = @(label.c_str());
202 [found_libraries addObject:library];
204 return found_libraries;
208 return ::MTLCreateSystemDefaultDevice();
212 auto command_queue =
device.newCommandQueue;
213 if (!command_queue) {
217 command_queue.label =
@"Impeller Command Queue";
218 return command_queue;
222 const std::vector<std::string>& shader_library_paths,
223 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
226 if (!command_queue) {
229 auto context = std::shared_ptr<ContextMTL>(
new ContextMTL(
232 std::move(is_gpu_disabled_sync_switch)));
233 if (!context->IsValid()) {
241 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
242 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
243 const std::string& library_label,
244 std::optional<PixelFormat> pixel_format_override) {
247 if (!command_queue) {
250 auto context = std::shared_ptr<ContextMTL>(
new ContextMTL(
254 std::move(is_gpu_disabled_sync_switch), pixel_format_override));
255 if (!context->IsValid()) {
264 id<MTLCommandQueue> command_queue,
265 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
266 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
267 const std::string& library_label) {
268 auto context = std::shared_ptr<ContextMTL>(
272 std::move(is_gpu_disabled_sync_switch)));
273 if (!context->IsValid()) {
280ContextMTL::~ContextMTL() {
281 is_gpu_disabled_sync_switch_->RemoveObserver(sync_switch_observer_.get());
289std::string ContextMTL::DescribeGpuModel()
const {
290 return std::string([[device_
name] UTF8String]);
294bool ContextMTL::IsValid()
const {
299std::shared_ptr<ShaderLibrary> ContextMTL::GetShaderLibrary()
const {
300 return shader_library_;
304std::shared_ptr<PipelineLibrary> ContextMTL::GetPipelineLibrary()
const {
305 return pipeline_library_;
309std::shared_ptr<SamplerLibrary> ContextMTL::GetSamplerLibrary()
const {
310 return sampler_library_;
315 return CreateCommandBufferInQueue(command_queue_);
322std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer()
const {
327std::shared_ptr<const fml::SyncSwitch> ContextMTL::GetIsGpuDisabledSyncSwitch()
329 return is_gpu_disabled_sync_switch_;
332std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
333 id<MTLCommandQueue>
queue)
const {
338 auto buffer = std::shared_ptr<CommandBufferMTL>(
339 new CommandBufferMTL(weak_from_this(),
queue));
346std::shared_ptr<Allocator> ContextMTL::GetResourceAllocator()
const {
347 return resource_allocator_;
350id<MTLDevice> ContextMTL::GetMTLDevice()
const {
354const std::shared_ptr<const Capabilities>& ContextMTL::GetCapabilities()
const {
355 return device_capabilities_;
358void ContextMTL::SetCapabilities(
359 const std::shared_ptr<const Capabilities>& capabilities) {
360 device_capabilities_ = capabilities;
369id<MTLCommandBuffer> ContextMTL::CreateMTLCommandBuffer(
370 const std::string& label)
const {
371 auto buffer = [command_queue_ commandBuffer];
372 if (!label.empty()) {
373 [
buffer setLabel:@(label.data())];
379 tasks_awaiting_gpu_.emplace_back(task);
380 while (tasks_awaiting_gpu_.size() > kMaxTasksAwaitingGPU) {
381 tasks_awaiting_gpu_.front()();
382 tasks_awaiting_gpu_.pop_front();
386void ContextMTL::FlushTasksAwaitingGPU() {
387 for (
const auto& task : tasks_awaiting_gpu_) {
390 tasks_awaiting_gpu_.clear();
393ContextMTL::SyncSwitchObserver::SyncSwitchObserver(ContextMTL& parent)
396void ContextMTL::SyncSwitchObserver::OnSyncSwitchUpdate(
bool new_is_disabled) {
397 if (!new_is_disabled) {
398 parent_.FlushTasksAwaitingGPU();
404 return command_queue_ip_;
static sk_sp< Effect > Create()
CapabilitiesBuilder & SetDefaultColorFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsComputeSubgroups(bool value)
CapabilitiesBuilder & SetSupportsTextureToTextureBlits(bool value)
CapabilitiesBuilder & SetDefaultStencilFormat(PixelFormat value)
CapabilitiesBuilder & SetSupportsDeviceTransientTextures(bool value)
CapabilitiesBuilder & SetSupportsFramebufferFetch(bool value)
CapabilitiesBuilder & SetSupportsDecalSamplerAddressMode(bool value)
CapabilitiesBuilder & SetSupportsOffscreenMSAA(bool value)
CapabilitiesBuilder & SetSupportsSSBO(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.
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
#define FML_LOG(severity)
Dart_NativeFunction function
SK_API sk_sp< SkSurface > ios(9.0)
SK_API sk_sp< SkSurface > tvos(9.0))
static void Shutdown(Dart_NativeArguments args)
DEF_SWITCHES_START aot vmservice shared library name
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 vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
bool IsFile(const std::string &path)
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)
static bool DeviceSupportsComputeSubgroups(id< MTLDevice > device)
static id< MTLCommandBuffer > CreateCommandBuffer(id< MTLCommandQueue > queue)
static bool DeviceSupportsFramebufferFetch(id< MTLDevice > device)
static std::unique_ptr< Capabilities > InferMetalCapabilities(id< MTLDevice > device, PixelFormat color_format)
std::shared_ptr< const fml::Mapping > data