Skip to content

Commit 0d29bfa

Browse files
committed
Resolve Metal shader beside executable
1 parent 8974cc0 commit 0d29bfa

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ mkdir -p outputs
2626
mapping all weights or generating media. Run `./h3 --help` for the complete CLI
2727
reference.
2828

29+
The Metal shader source is compiled at runtime. To run `h3` outside the source
30+
directory, install `h3_shaders.metal` beside the executable:
31+
32+
```sh
33+
mkdir -p "$HOME/bin"
34+
install -m 755 h3 "$HOME/bin/h3"
35+
install -m 644 h3_shaders.metal "$HOME/bin/h3_shaders.metal"
36+
```
37+
38+
Relative shader paths are checked in the current directory first and then next
39+
to the executable, so source-tree workflows remain unchanged.
40+
2941
Without `-p`, the same binary starts an Iris-style interactive session:
3042

3143
```sh

h3_gpu.m

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <errno.h>
99
#include <fcntl.h>
1010
#include <limits.h>
11+
#include <mach-o/dyld.h>
1112
#include <math.h>
1213
#include <stdarg.h>
1314
#include <stdio.h>
@@ -325,6 +326,25 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows,
325326
return 1;
326327
}
327328

329+
static NSString *h3_gpu_executable_relative_path(NSString *relative_path) {
330+
if (!relative_path || relative_path.isAbsolutePath) return nil;
331+
332+
uint32_t size = 0;
333+
if (_NSGetExecutablePath(NULL, &size) != -1 || !size) return nil;
334+
char *buffer = malloc(size);
335+
if (!buffer) return nil;
336+
if (_NSGetExecutablePath(buffer, &size) != 0) {
337+
free(buffer);
338+
return nil;
339+
}
340+
341+
NSString *executable = [NSString stringWithUTF8String:buffer];
342+
free(buffer);
343+
if (!executable) return nil;
344+
return [[executable stringByDeletingLastPathComponent]
345+
stringByAppendingPathComponent:relative_path];
346+
}
347+
328348
h3_gpu *h3_gpu_create(const char *shader_source_path,
329349
char *error, size_t error_size) {
330350
@autoreleasepool {
@@ -352,11 +372,24 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows,
352372
}
353373
const char *source_path = shader_source_path ? shader_source_path :
354374
"h3_shaders.metal";
355-
NSString *path = [NSString stringWithUTF8String:source_path];
375+
NSString *requestedPath = [NSString stringWithUTF8String:source_path];
376+
NSString *path = requestedPath;
377+
NSString *executableRelativePath = nil;
356378
NSError *libraryError = nil;
357379
NSString *source = [NSString stringWithContentsOfFile:path
358380
encoding:NSUTF8StringEncoding
359381
error:&libraryError];
382+
if (!source) {
383+
executableRelativePath =
384+
h3_gpu_executable_relative_path(requestedPath);
385+
if (executableRelativePath) {
386+
libraryError = nil;
387+
source = [NSString stringWithContentsOfFile:executableRelativePath
388+
encoding:NSUTF8StringEncoding
389+
error:&libraryError];
390+
if (source) path = executableRelativePath;
391+
}
392+
}
360393
if (source) {
361394
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
362395
options.mathMode = MTLMathModeSafe;
@@ -396,8 +429,16 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows,
396429
if (!gpu.library) {
397430
if (error && error_size) {
398431
const char *description = libraryError.localizedDescription.UTF8String;
399-
snprintf(error, error_size, "cannot compile %s: %s",
400-
source_path, description ? description : "unknown error");
432+
if (!source && executableRelativePath) {
433+
snprintf(error, error_size, "cannot read %s or %s: %s",
434+
requestedPath.UTF8String,
435+
executableRelativePath.UTF8String,
436+
description ? description : "unknown error");
437+
} else {
438+
snprintf(error, error_size, "cannot compile %s: %s",
439+
path.UTF8String,
440+
description ? description : "unknown error");
441+
}
401442
}
402443
return NULL;
403444
}

0 commit comments

Comments
 (0)