summaryrefslogtreecommitdiffstats
path: root/drivers/metal/metal_objects.mm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/metal/metal_objects.mm')
-rw-r--r--drivers/metal/metal_objects.mm208
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