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;
74ContextMTL::ContextMTL(
76 id<MTLCommandQueue> command_queue,
77 NSArray<id<MTLLibrary>>* shader_libraries,
78 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
79 std::optional<PixelFormat> pixel_format_override)
81 command_queue_(command_queue),
82 is_gpu_disabled_sync_switch_(
std::move(is_gpu_disabled_sync_switch)) {
89 sync_switch_observer_.reset(
new SyncSwitchObserver(*
this));
90 is_gpu_disabled_sync_switch_->AddObserver(sync_switch_observer_.get());
94 if (shader_libraries == nil) {
100 auto library = std::shared_ptr<ShaderLibraryMTL>(
101 new ShaderLibraryMTL(shader_libraries));
102 if (!library->IsValid()) {
106 shader_library_ = std::move(library);
112 std::shared_ptr<PipelineLibraryMTL>(
new PipelineLibraryMTL(device_));
118 std::shared_ptr<SamplerLibraryMTL>(
new SamplerLibraryMTL(device_));
123 resource_allocator_ = std::shared_ptr<AllocatorMTL>(
124 new AllocatorMTL(device_,
"Impeller Permanents Allocator"));
125 if (!resource_allocator_) {
131 device_capabilities_ =
133 ? pixel_format_override.value()
135 command_queue_ip_ = std::make_shared<CommandQueue>();
137 gpu_tracer_ = std::make_shared<GPUTracerMTL>();
144 const std::vector<std::string>& libraries_paths) {
145 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
146 for (
const auto& library_path : libraries_paths) {
149 << library_path <<
"'";
152 NSError* shader_library_error = nil;
153 auto library = [
device newLibraryWithFile:@(library_path.c_str())
154 error:&shader_library_error];
157 << shader_library_error.localizedDescription.UTF8String;
160 [found_libraries addObject:library];
162 return found_libraries;
167 const std::vector<std::shared_ptr<fml::Mapping>>& libraries_data,
168 const std::string& label) {
169 NSMutableArray<id<MTLLibrary>>* found_libraries = [NSMutableArray array];
170 for (
const auto& library_data : libraries_data) {
171 if (library_data ==
nullptr) {
176 __block
auto data = library_data;
179 ::dispatch_data_create(library_data->GetMapping(),
180 library_data->GetSize(),
181 dispatch_get_main_queue(),
187 if (!dispatch_data) {
188 FML_LOG(
ERROR) <<
"Could not wrap shader data in dispatch data.";
192 NSError* shader_library_error = nil;
193 auto library = [
device newLibraryWithData:dispatch_data
194 error:&shader_library_error];
197 << shader_library_error.localizedDescription.UTF8String;
200 if (!label.empty()) {
201 library.label = @(label.c_str());
203 [found_libraries addObject:library];
205 return found_libraries;
209 return ::MTLCreateSystemDefaultDevice();
213 auto command_queue =
device.newCommandQueue;
214 if (!command_queue) {
218 command_queue.label =
@"Impeller Command Queue";
219 return command_queue;
222std::shared_ptr<ContextMTL> ContextMTL::Create(
223 const std::vector<std::string>& shader_library_paths,
224 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
227 if (!command_queue) {
230 auto context = std::shared_ptr<ContextMTL>(
new ContextMTL(
233 std::move(is_gpu_disabled_sync_switch)));
234 if (!context->IsValid()) {
241std::shared_ptr<ContextMTL> ContextMTL::Create(
242 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
243 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
244 const std::string& library_label,
245 std::optional<PixelFormat> pixel_format_override) {
248 if (!command_queue) {
251 auto context = std::shared_ptr<ContextMTL>(
new ContextMTL(
255 std::move(is_gpu_disabled_sync_switch), pixel_format_override));
256 if (!context->IsValid()) {
263std::shared_ptr<ContextMTL> ContextMTL::Create(
265 id<MTLCommandQueue> command_queue,
266 const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
267 std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
268 const std::string& library_label) {
269 auto context = std::shared_ptr<ContextMTL>(
273 std::move(is_gpu_disabled_sync_switch)));
274 if (!context->IsValid()) {
281ContextMTL::~ContextMTL() {
282 is_gpu_disabled_sync_switch_->RemoveObserver(sync_switch_observer_.get());
286 return Context::BackendType::kMetal;
290std::string ContextMTL::DescribeGpuModel()
const {
291 return std::string([[device_
name] UTF8String]);
295bool ContextMTL::IsValid()
const {
300std::shared_ptr<ShaderLibrary> ContextMTL::GetShaderLibrary()
const {
301 return shader_library_;
305std::shared_ptr<PipelineLibrary> ContextMTL::GetPipelineLibrary()
const {
306 return pipeline_library_;
310std::shared_ptr<SamplerLibrary> ContextMTL::GetSamplerLibrary()
const {
311 return sampler_library_;
315std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBuffer()
const {
316 return CreateCommandBufferInQueue(command_queue_);
320void ContextMTL::Shutdown() {}
323std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer()
const {
328std::shared_ptr<const fml::SyncSwitch> ContextMTL::GetIsGpuDisabledSyncSwitch()
330 return is_gpu_disabled_sync_switch_;
333std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
334 id<MTLCommandQueue> queue)
const {
339 auto buffer = std::shared_ptr<CommandBufferMTL>(
340 new CommandBufferMTL(weak_from_this(), queue));
347std::shared_ptr<Allocator> ContextMTL::GetResourceAllocator()
const {
348 return resource_allocator_;
351id<MTLDevice> ContextMTL::GetMTLDevice()
const {
355const std::shared_ptr<const Capabilities>& ContextMTL::GetCapabilities()
const {
356 return device_capabilities_;
359void ContextMTL::SetCapabilities(
360 const std::shared_ptr<const Capabilities>& capabilities) {
361 device_capabilities_ = capabilities;
370id<MTLCommandBuffer> ContextMTL::CreateMTLCommandBuffer(
371 const std::string& label)
const {
372 auto buffer = [command_queue_ commandBuffer];
373 if (!label.empty()) {
374 [
buffer setLabel:@(label.data())];
379void ContextMTL::StoreTaskForGPU(
const std::function<
void()>& task) {
380 tasks_awaiting_gpu_.emplace_back(task);
381 while (tasks_awaiting_gpu_.size() > kMaxTasksAwaitingGPU) {
382 tasks_awaiting_gpu_.front()();
383 tasks_awaiting_gpu_.pop_front();
387void ContextMTL::FlushTasksAwaitingGPU() {
388 for (
const auto& task : tasks_awaiting_gpu_) {
391 tasks_awaiting_gpu_.clear();
394ContextMTL::SyncSwitchObserver::SyncSwitchObserver(ContextMTL& parent)
397void ContextMTL::SyncSwitchObserver::OnSyncSwitchUpdate(
bool new_is_disabled) {
398 if (!new_is_disabled) {
399 parent_.FlushTasksAwaitingGPU();
405 return command_queue_ip_;
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 & SetSupportsBufferToTextureBlits(bool 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.
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
#define FML_LOG(severity)
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 bool DeviceSupportsFramebufferFetch(id< MTLDevice > device)
static std::unique_ptr< Capabilities > InferMetalCapabilities(id< MTLDevice > device, PixelFormat color_format)