redo metal shader compilation with argument buffers

This commit is contained in:
Greg Wells
2025-07-18 21:29:24 -04:00
parent 431436b945
commit b8f431a5e0
4 changed files with 113 additions and 159 deletions

View File

@@ -1,9 +1,19 @@
#pragma once
#include "stdint.h"
#include "stdlib.h"
#include "utils/gryphn_bool.h"
typedef enum mtlShaderModuleStage {
vertex, fragment
} mtlShaderModuleStage;
typedef struct mtlShaderOptions {
gnBool useArgumentBuffers;
mtlShaderModuleStage stage;
const char* entryPoint;
} mtlShaderOptions;
const char* mtlCompileShader(uint32_t* code, size_t size, mtlShaderOptions* options);
#ifdef __cplusplus
extern "C"
#endif
const char* mtlCompileShader(uint32_t* code, size_t wordCount, mtlShaderOptions* options);

View File

@@ -1,5 +1,66 @@
#include "metal_shader_compiler.h"
#include "spirv_msl.hpp"
extern "C" const char* mtlCompileShader(const char* src, mtlShaderOptions options) {
return "i hate this BS";
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
// // [[buffer(0)]] is reserved for stage_in, [[buffer(1)]] is reserved for push_constant
// uint32_t currentBufferBinding = 2, currentTextureBinding = 0;
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentBufferBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentBufferBinding;
// currentBufferBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count);
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentTextureBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentTextureBinding;
// currentTextureBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STORAGE_BUFFER, &list, &count);
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentBufferBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentBufferBinding;
// currentBufferBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_PUSH_CONSTANT, &list, &count);
// for (int i = 0; i < count; i++) {
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, 1);
// }
extern "C" const char* mtlCompileShader(uint32_t* code, size_t wordCount, mtlShaderOptions* inOptions) {
spirv_cross::CompilerMSL compiler(code, wordCount);
spirv_cross::CompilerMSL::Options options;
if (inOptions->useArgumentBuffers) {
options.set_msl_version(3);
options.argument_buffers = true;
} else {
options.set_msl_version(1);
return NULL;
}
compiler.set_msl_options(options);
if (inOptions->stage == vertex)
compiler.set_entry_point(inOptions->entryPoint, spv::ExecutionModelVertex);
else if (inOptions->stage == fragment)
compiler.set_entry_point(inOptions->entryPoint, spv::ExecutionModelFragment);
else {
return NULL;
}
std::string returnedCode = compiler.compile();
char* returnString = (char*)malloc(sizeof(char) * returnedCode.size());
strcpy(returnString, returnedCode.c_str());
return returnString;
}

View File

@@ -7,166 +7,49 @@
#import <Metal/Metal.h>
gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo) {
module->shaderModule = malloc(sizeof(gnPlatformShaderModule));
mtlShaderOptions options = {
.useArgumentBuffers = (device->outputDevice->device.argumentBuffersSupport == MTLArgumentBuffersTier2),
.stage = vertex,
.entryPoint = shaderModuleInfo.entryPoint.value
};
if (shaderModuleInfo.stage == GN_FRAGMENT_SHADER_MODULE) options.stage = fragment;
const char* res = mtlCompileShader(shaderModuleInfo.code, shaderModuleInfo.size, &options);
printf("compiled res: %s\n", res);
const char* res = mtlCompileShader(shaderModuleInfo.code, shaderModuleInfo.size / 4, &options);
if (res == NULL) return GN_FAILED_TO_CONVERT_SHADER_CODE;
NSError* error = nil;
MTLCompileOptions* mtloptions = nil;
NSString* sourceCode = [NSString stringWithCString:res encoding:NSUTF8StringEncoding];
id<MTLLibrary> shaderLib = [device->outputDevice->device newLibraryWithSource:sourceCode options:mtloptions error:&error];
if (!shaderLib) {
const char* errorString = error.localizedDescription.UTF8String;
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
.message = gnCombineStrings(gnCreateString("Failed to compile metal library "), errorString)
});
return GN_FAILED_TO_CREATE_SHADER_MODULE;
}
const char* name = shaderModuleInfo.entryPoint.value;
if (strcmp(name, "main") == 0) name = "main0";
gnBool foundFunction = false;
for (int i = 0; i < shaderLib.functionNames.count; i++) {
if (strcmp([shaderLib.functionNames objectAtIndex:0].UTF8String, name) == 0) {
foundFunction = true;
break;
}
}
if (!foundFunction) return GN_FAILED_TO_FIND_ENTRY_POINT;
NSString* functionName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
module->shaderModule->function = [shaderLib newFunctionWithName:functionName];
[shaderLib release];
free((void*)res);
return GN_SUCCESS;
}
// void mtlSpirVErrorCallback(void *userdata, const char *error) {
// gnDebuggerInfo debugger = *((gnDebuggerInfo*)userdata);
// gnDebuggerSetErrorMessage(debugger, (gnMessageData){
// .message = gnCombineStrings(gnCreateString("shader compilation error MSL "), gnCreateString(error))
// });
// }
// extern "C" gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo) {
// module->shaderModule = (gnPlatformShaderModule_t*)malloc(sizeof(gnPlatformShaderModule_t));
// MTLArgumentBuffersTier supportsArgumentBuffers = device->outputDevice->device.argumentBuffersSupport;
// module->shaderModule->useShaderMap = !(supportsArgumentBuffers == MTLArgumentBuffersTier2);
// spvc_context context = NULL;
// spvc_parsed_ir ir = NULL;
// spvc_compiler compiler = NULL;
// const char *result = NULL;
// spvc_resources resources = NULL;
// const spvc_reflected_resource *list = NULL;
// spvc_compiler_options options = NULL;
// size_t count;
// spvc_context_create(&context);
// spvc_context_set_error_callback(context, mtlSpirVErrorCallback, &module->device->instance->debugger);
// spvc_context_parse_spirv(context, shaderModuleInfo.code, shaderModuleInfo.size / 4, &ir);
// spvc_context_create_compiler(context, SPVC_BACKEND_MSL, ir, SPVC_CAPTURE_MODE_COPY, &compiler);
// spvc_compiler_create_shader_resources(compiler, &resources);
// spvc_compiler_create_compiler_options(compiler, &options);
// if (module->shaderModule->useShaderMap) {
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
// // [[buffer(0)]] is reserved for stage_in, [[buffer(1)]] is reserved for push_constant
// uint32_t currentBufferBinding = 2, currentTextureBinding = 0;
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentBufferBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentBufferBinding;
// currentBufferBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count);
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentTextureBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentTextureBinding;
// currentTextureBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STORAGE_BUFFER, &list, &count);
// for (int i = 0; i < count; i++) {
// uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentBufferBinding);
// module->shaderModule->map.sets[set].bindings[binding] = currentBufferBinding;
// currentBufferBinding++;
// }
// spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_PUSH_CONSTANT, &list, &count);
// for (int i = 0; i < count; i++) {
// spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, 1);
// }
// spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_VERSION, SPVC_MAKE_MSL_VERSION(1, 0, 0));
// } else {
// spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_VERSION, SPVC_MAKE_MSL_VERSION(3, 0, 0));
// spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS, true);
// spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES, true);
// spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS_TIER, 2);
// const spvc_combined_image_sampler* samplers;
// size_t sampler_count;
// spvc_compiler_build_combined_image_samplers(compiler);
// spvc_compiler_get_combined_image_samplers(compiler, &samplers, &sampler_count);
// printf("sampler count: %zu\n", sampler_count);
// for (size_t i = 0; i < sampler_count; ++i) {
// printf("Combined: image ID %u + sampler ID %u = ID %u\n",
// samplers[i].image_id,
// samplers[i].sampler_id,
// samplers[i].combined_id);
// }
// // spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count);
// // for (int i = 0; i < count; i++) {
// // spvc_compiler
// // // uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
// // // binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
// // // spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
// // // spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, currentTextureBinding);
// // // module->shaderModule->map.sets[set].bindings[binding] = currentTextureBinding;
// // // currentTextureBinding++;
// // }
// }
// spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING, true);
// spvc_compiler_install_compiler_options(compiler, options);
// SpvExecutionModel executionModel = SpvExecutionModelVertex;
// if (shaderModuleInfo.stage == GN_FRAGMENT_SHADER_MODULE) executionModel = SpvExecutionModelFragment;
// spvc_compiler_set_entry_point(compiler, shaderModuleInfo.entryPoint.value, executionModel);
// spvc_result res = spvc_compiler_compile(compiler, &result);
// printf("res: %s\n", result);
// if (res != SPVC_SUCCESS)
// return GN_FAILED_TO_CONVERT_SHADER_CODE;
// NSError* error = nil;
// MTLCompileOptions* mtloptions = nil;
// NSString* sourceCode = [NSString stringWithCString:result encoding:NSUTF8StringEncoding];
// id<MTLLibrary> shaderLib = [device->outputDevice->device newLibraryWithSource:sourceCode options:mtloptions error:&error];
// if (!shaderLib) {
// const char* errorString = error.localizedDescription.UTF8String;
// gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
// .message = gnCombineStrings(gnCreateString("Failed to compile metal library "), errorString)
// });
// return GN_FAILED_TO_CREATE_SHADER_MODULE;
// }
// const char* name = shaderModuleInfo.entryPoint.value;
// if (strcmp(name, "main") == 0) {
// name = "main0";
// }
// gnBool foundFunction = false;
// for (int i = 0; i < shaderLib.functionNames.count; i++) {
// if (strcmp([shaderLib.functionNames objectAtIndex:0].UTF8String, name) == 0) {
// foundFunction = true;
// }
// }
// if (!foundFunction) {
// gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
// .message = gnCombineStrings(gnCreateString("Failed to find specified entry point "), name)
// });
// return GN_FAILED_TO_FIND_ENTRY_POINT;
// }
// NSString* functionName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
// module->shaderModule->function = [shaderLib newFunctionWithName:functionName];
// [shaderLib release];
// spvc_context_destroy(context);
// return GN_SUCCESS;
// }
void destroyMetalShaderModule(gnShaderModule module) {
free(module->shaderModule);