diff options
Diffstat (limited to 'drivers/metal/metal_objects.mm')
-rw-r--r-- | drivers/metal/metal_objects.mm | 208 |
1 files changed, 206 insertions, 2 deletions
diff --git a/drivers/metal/metal_objects.mm b/drivers/metal/metal_objects.mm index 3ce00f74a3..5c7036f11e 100644 --- a/drivers/metal/metal_objects.mm +++ b/drivers/metal/metal_objects.mm @@ -50,9 +50,12 @@ #import "metal_objects.h" +#import "metal_utils.h" #import "pixel_formats.h" #import "rendering_device_driver_metal.h" +#import <os/signpost.h> + void MDCommandBuffer::begin() { DEV_ASSERT(commandBuffer == nil); commandBuffer = queue.commandBuffer; @@ -850,7 +853,7 @@ void MDCommandBuffer::_end_blit() { type = MDCommandBufferStateType::None; } -MDComputeShader::MDComputeShader(CharString p_name, Vector<UniformSet> p_sets, id<MTLLibrary> p_kernel) : +MDComputeShader::MDComputeShader(CharString p_name, Vector<UniformSet> p_sets, MDLibrary *p_kernel) : MDShader(p_name, p_sets), kernel(p_kernel) { } @@ -868,7 +871,7 @@ void MDComputeShader::encode_push_constant_data(VectorView<uint32_t> p_data, MDC [enc setBytes:ptr length:length atIndex:push_constants.binding]; } -MDRenderShader::MDRenderShader(CharString p_name, Vector<UniformSet> p_sets, id<MTLLibrary> _Nonnull p_vert, id<MTLLibrary> _Nonnull p_frag) : +MDRenderShader::MDRenderShader(CharString p_name, Vector<UniformSet> p_sets, MDLibrary *_Nonnull p_vert, MDLibrary *_Nonnull p_frag) : MDShader(p_name, p_sets), vert(p_vert), frag(p_frag) { } @@ -1378,3 +1381,204 @@ id<MTLDepthStencilState> MDResourceCache::get_depth_stencil_state(bool p_use_dep } return *val; } + +static const char *SHADER_STAGE_NAMES[] = { + [RD::SHADER_STAGE_VERTEX] = "vert", + [RD::SHADER_STAGE_FRAGMENT] = "frag", + [RD::SHADER_STAGE_TESSELATION_CONTROL] = "tess_ctrl", + [RD::SHADER_STAGE_TESSELATION_EVALUATION] = "tess_eval", + [RD::SHADER_STAGE_COMPUTE] = "comp", +}; + +void ShaderCacheEntry::notify_free() const { + owner.shader_cache_free_entry(key); +} + +@interface MDLibrary () +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry; +- (ShaderCacheEntry *)entry; +@end + +@interface MDLazyLibrary : MDLibrary { + id<MTLLibrary> _library; + NSError *_error; + std::shared_mutex _mu; + bool _loaded; + id<MTLDevice> _device; + NSString *_source; + MTLCompileOptions *_options; +} +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry + device:(id<MTLDevice>)device + source:(NSString *)source + options:(MTLCompileOptions *)options; +@end + +@interface MDImmediateLibrary : MDLibrary { + id<MTLLibrary> _library; + NSError *_error; + std::mutex _cv_mutex; + std::condition_variable _cv; + std::atomic<bool> _complete; + bool _ready; +} +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry + device:(id<MTLDevice>)device + source:(NSString *)source + options:(MTLCompileOptions *)options; +@end + +@implementation MDLibrary { + ShaderCacheEntry *_entry; +} + ++ (instancetype)newLibraryWithCacheEntry:(ShaderCacheEntry *)entry + device:(id<MTLDevice>)device + source:(NSString *)source + options:(MTLCompileOptions *)options + strategy:(ShaderLoadStrategy)strategy { + switch (strategy) { + case ShaderLoadStrategy::DEFAULT: + [[fallthrough]]; + default: + return [[MDImmediateLibrary alloc] initWithCacheEntry:entry device:device source:source options:options]; + case ShaderLoadStrategy::LAZY: + return [[MDLazyLibrary alloc] initWithCacheEntry:entry device:device source:source options:options]; + } +} + +- (ShaderCacheEntry *)entry { + return _entry; +} + +- (id<MTLLibrary>)library { + CRASH_NOW_MSG("Not implemented"); + return nil; +} + +- (NSError *)error { + CRASH_NOW_MSG("Not implemented"); + return nil; +} + +- (void)setLabel:(NSString *)label { +} + +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry { + self = [super init]; + _entry = entry; + _entry->library = self; + return self; +} + +- (void)dealloc { + _entry->notify_free(); +} + +@end + +@implementation MDImmediateLibrary + +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry + device:(id<MTLDevice>)device + source:(NSString *)source + options:(MTLCompileOptions *)options { + self = [super initWithCacheEntry:entry]; + _complete = false; + _ready = false; + + __block os_signpost_id_t compile_id = (os_signpost_id_t)(uintptr_t)self; + os_signpost_interval_begin(LOG_INTERVALS, compile_id, "shader_compile", + "shader_name=%{public}s stage=%{public}s hash=%{public}s", + entry->name.get_data(), SHADER_STAGE_NAMES[entry->stage], entry->short_sha.get_data()); + + [device newLibraryWithSource:source + options:options + completionHandler:^(id<MTLLibrary> library, NSError *error) { + os_signpost_interval_end(LOG_INTERVALS, compile_id, "shader_compile"); + self->_library = library; + self->_error = error; + if (error) { + ERR_PRINT(String(U"Error compiling shader %s: %s").format(entry->name.get_data(), error.localizedDescription.UTF8String)); + } + + { + std::lock_guard<std::mutex> lock(self->_cv_mutex); + _ready = true; + } + _cv.notify_all(); + _complete = true; + }]; + return self; +} + +- (id<MTLLibrary>)library { + if (!_complete) { + std::unique_lock<std::mutex> lock(_cv_mutex); + _cv.wait(lock, [&] { return _ready; }); + } + return _library; +} + +- (NSError *)error { + if (!_complete) { + std::unique_lock<std::mutex> lock(_cv_mutex); + _cv.wait(lock, [&] { return _ready; }); + } + return _error; +} + +@end + +@implementation MDLazyLibrary +- (instancetype)initWithCacheEntry:(ShaderCacheEntry *)entry + device:(id<MTLDevice>)device + source:(NSString *)source + options:(MTLCompileOptions *)options { + self = [super initWithCacheEntry:entry]; + _device = device; + _source = source; + _options = options; + + return self; +} + +- (void)load { + { + std::shared_lock<std::shared_mutex> lock(_mu); + if (_loaded) { + return; + } + } + + std::unique_lock<std::shared_mutex> lock(_mu); + if (_loaded) { + return; + } + + ShaderCacheEntry *entry = [self entry]; + + __block os_signpost_id_t compile_id = (os_signpost_id_t)(uintptr_t)self; + os_signpost_interval_begin(LOG_INTERVALS, compile_id, "shader_compile", + "shader_name=%{public}s stage=%{public}s hash=%{public}s", + entry->name.get_data(), SHADER_STAGE_NAMES[entry->stage], entry->short_sha.get_data()); + NSError *error; + _library = [_device newLibraryWithSource:_source options:_options error:&error]; + os_signpost_interval_end(LOG_INTERVALS, compile_id, "shader_compile"); + _device = nil; + _source = nil; + _options = nil; + _loaded = true; +} + +- (id<MTLLibrary>)library { + [self load]; + return _library; +} + +- (NSError *)error { + [self load]; + return _error; +} + +@end |