finish redoing metal shader workflow
This commit is contained in:
@@ -2,40 +2,62 @@
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "utils/gryphn_bool.h"
|
||||
#include <core/src/uniforms/gryphn_uniform_layout.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define GN_CPP_FUNCTION extern "C"
|
||||
#else
|
||||
#define GN_CPP_FUNCTION
|
||||
#endif
|
||||
|
||||
#define MAX_METAL_SETS 32
|
||||
#define MAX_METAL_BINDINGS 16
|
||||
|
||||
typedef struct mtlCompiler_t* mtlCompiler;
|
||||
|
||||
typedef enum mtlShaderModuleStage {
|
||||
vertex, fragment
|
||||
mtlVertex, mtlFragment, mtlMaxStage
|
||||
} mtlShaderModuleStage;
|
||||
|
||||
typedef struct mtlShaderOptions {
|
||||
gnBool useArgumentBuffers;
|
||||
mtlShaderModuleStage stage;
|
||||
typedef struct mtlCompilerInfo {
|
||||
uint32_t* code;
|
||||
int wordCount;
|
||||
const char* entryPoint;
|
||||
} mtlShaderOptions;
|
||||
mtlShaderModuleStage stage;
|
||||
|
||||
typedef struct mtlBinding {
|
||||
uint32_t spvBinding;
|
||||
uint32_t metalID;
|
||||
} mtlBinding;
|
||||
int mslMajorVersion, minorVersion;
|
||||
gnBool useArgumentBuffers;
|
||||
} mtlCompilerInfo;
|
||||
|
||||
typedef struct mtlSetMap {
|
||||
uint32_t setIndex, mtlSetIndex;
|
||||
mtlBinding bindings[MAX_METAL_BINDINGS];
|
||||
} mtlSetMap;
|
||||
GN_CPP_FUNCTION mtlCompiler mtlCreateCompiler(mtlCompilerInfo* info);
|
||||
GN_CPP_FUNCTION const char* mtlCompilerShader(mtlCompiler compiler, gnUniformLayout* uniformLayout);
|
||||
|
||||
typedef struct mtlShaderMap {
|
||||
mtlSetMap sets[MAX_METAL_SETS];
|
||||
} mtlShaderMap;
|
||||
// typedef struct mtlShaderOptions {
|
||||
// gnBool useArgumentBuffers;
|
||||
// mtlShaderModuleStage stage;
|
||||
// const char* entryPoint;
|
||||
// } mtlShaderOptions;
|
||||
|
||||
typedef struct mtlShader {
|
||||
const char* code;
|
||||
mtlShaderMap map;
|
||||
} mtlShader;
|
||||
// typedef struct mtlBinding {
|
||||
// uint32_t spvBinding;
|
||||
// uint32_t metalID;
|
||||
// } mtlBinding;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
mtlShader mtlCompileShader(uint32_t* code, size_t wordCount, mtlShaderOptions* options);
|
||||
// typedef struct mtlSetMap {
|
||||
// uint32_t setIndex, mtlSetIndex;
|
||||
// mtlBinding bindings[MAX_METAL_BINDINGS];
|
||||
// } mtlSetMap;
|
||||
|
||||
// typedef struct mtlShaderMap {
|
||||
// mtlSetMap sets[MAX_METAL_SETS];
|
||||
// } mtlShaderMap;
|
||||
|
||||
// typedef struct mtlShader {
|
||||
// const char* code;
|
||||
// mtlShaderMap map;
|
||||
// } mtlShader;
|
||||
|
||||
// #ifdef __cplusplus
|
||||
// extern "C"
|
||||
// #endif
|
||||
// mtlShader mtlCompileShader(uint32_t* code, size_t wordCount, mtlShaderOptions* options);
|
||||
|
||||
@@ -1,71 +1,77 @@
|
||||
#include "metal_shader_compiler.h"
|
||||
#include "spirv_msl.hpp"
|
||||
#include "iostream"
|
||||
// #include "iostream"
|
||||
|
||||
void handle_resources(spirv_cross::CompilerMSL& compiler, spirv_cross::SmallVector<spirv_cross::Resource>& resources, mtlShaderMap* map) {
|
||||
typedef struct mtlCompiler_t {
|
||||
spirv_cross::CompilerMSL* mslCompiler;
|
||||
bool usingArgumentBuffers = false;
|
||||
mtlShaderModuleStage stage;
|
||||
} mtlInternalCompiler;
|
||||
|
||||
void handle_resources(spirv_cross::CompilerMSL& compiler, spirv_cross::SmallVector<spirv_cross::Resource>& resources) {
|
||||
for (int i = 0; i < resources.size(); i++) {
|
||||
uint32_t set = compiler.get_decoration(resources[i].id, spv::DecorationDescriptorSet);
|
||||
compiler.unset_decoration(resources[i].id, spv::DecorationDescriptorSet);
|
||||
compiler.set_decoration(resources[i].id, spv::DecorationDescriptorSet, set + 1);
|
||||
map->sets[set].setIndex = set;
|
||||
map->sets[set].mtlSetIndex = set + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void improve_map(spirv_cross::CompilerMSL& compiler, spirv_cross::SmallVector<spirv_cross::Resource>& resources, mtlShaderMap* map) {
|
||||
for (int i = 0; i < resources.size(); i++) {
|
||||
uint32_t set = compiler.get_decoration(resources[i].id, spv::DecorationDescriptorSet);
|
||||
uint32_t binding = compiler.get_decoration(resources[i].id, spv::DecorationBinding);
|
||||
map->sets[(set - 1)].bindings[binding].spvBinding = binding;
|
||||
map->sets[(set - 1)].bindings[binding].metalID = compiler.get_automatic_msl_resource_binding(resources[i].id);
|
||||
}
|
||||
GN_CPP_FUNCTION mtlCompiler mtlCreateCompiler(mtlCompilerInfo* info) {
|
||||
mtlInternalCompiler* compiler = (mtlInternalCompiler*)malloc(sizeof(mtlInternalCompiler));
|
||||
compiler->mslCompiler = new spirv_cross::CompilerMSL(info->code, info->wordCount);
|
||||
|
||||
spirv_cross::CompilerMSL::Options options = compiler->mslCompiler->get_msl_options();
|
||||
options.argument_buffers = (bool)info->useArgumentBuffers;
|
||||
options.set_msl_version(info->mslMajorVersion, info->minorVersion);
|
||||
compiler->mslCompiler->set_msl_options(options);
|
||||
|
||||
compiler->usingArgumentBuffers = (info->mslMajorVersion >= 2 && info->useArgumentBuffers);
|
||||
compiler->stage = info->stage;
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
extern "C" mtlShader mtlCompileShader(uint32_t* code, size_t wordCount, mtlShaderOptions* inOptions) {
|
||||
spirv_cross::CompilerMSL compiler(code, wordCount);
|
||||
GN_CPP_FUNCTION const char* mtlCompilerShader(mtlCompiler compiler, gnUniformLayout* uniformLayout) {
|
||||
if (uniformLayout->setCount == 0) goto compile;
|
||||
|
||||
spirv_cross::CompilerMSL::Options options;
|
||||
options.enable_base_index_zero = false;
|
||||
if (inOptions->useArgumentBuffers) {
|
||||
options.set_msl_version(3);
|
||||
options.argument_buffers = true;
|
||||
} else {
|
||||
options.set_msl_version(1);
|
||||
return {};
|
||||
}
|
||||
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 {};
|
||||
}
|
||||
|
||||
mtlShaderMap map;
|
||||
for (int i = 0; i < MAX_METAL_SETS; i++) {
|
||||
map.sets[i].mtlSetIndex = -1;
|
||||
map.sets[i].setIndex = -1;
|
||||
for (int c = 0; c < MAX_METAL_BINDINGS; c++) {
|
||||
map.sets[i].bindings[c].spvBinding = -1;
|
||||
map.sets[i].bindings[c].metalID = -1;
|
||||
if (compiler->usingArgumentBuffers) {
|
||||
// std::vector<spirv_cross::MSLResourceBinding> bindings;
|
||||
for (int i = 0; i < uniformLayout->setCount; i++) {
|
||||
uint32_t currentBinding = 0;
|
||||
for (int c = 0; c < uniformLayout->sets[i].uniformBindingCount; c++) {
|
||||
gnUniformBinding gryphnBinding = uniformLayout->sets[i].uniformBindings[c];
|
||||
spirv_cross::MSLResourceBinding binding = {
|
||||
.binding = gryphnBinding.binding,
|
||||
.count = 1,
|
||||
.desc_set = ((uint32_t)i + 1),
|
||||
.stage = (compiler->stage == mtlVertex) ? spv::ExecutionModelVertex : spv::ExecutionModelFragment,
|
||||
};
|
||||
if (gryphnBinding.type == GN_COMBINED_IMAGE_SAMPLER_DESCRIPTOR) {
|
||||
binding.msl_texture = currentBinding;
|
||||
binding.msl_sampler = currentBinding + 1;
|
||||
currentBinding += 2;
|
||||
} else if (gryphnBinding.type == GN_SHADER_STORE_BUFFER_DESCRIPTOR || gryphnBinding.type == GN_UNIFORM_BUFFER_DESCRIPTOR) {
|
||||
binding.msl_buffer = currentBinding;
|
||||
currentBinding++;
|
||||
}
|
||||
// bindings.push_back(binding);
|
||||
compiler->mslCompiler->add_msl_resource_binding(binding);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("please add support for not using argument buffers on metal\n");
|
||||
goto compile;
|
||||
}
|
||||
auto arg_buffers = compiler.get_shader_resources();
|
||||
handle_resources(compiler, arg_buffers.uniform_buffers, &map);
|
||||
handle_resources(compiler, arg_buffers.storage_buffers, &map);
|
||||
handle_resources(compiler, arg_buffers.sampled_images, &map);
|
||||
|
||||
std::string returnedCode = compiler.compile();
|
||||
compile:
|
||||
auto arg_buffers = compiler->mslCompiler->get_shader_resources();
|
||||
handle_resources(*compiler->mslCompiler, arg_buffers.uniform_buffers);
|
||||
handle_resources(*compiler->mslCompiler, arg_buffers.storage_buffers);
|
||||
handle_resources(*compiler->mslCompiler, arg_buffers.sampled_images);
|
||||
|
||||
improve_map(compiler, arg_buffers.uniform_buffers, &map);
|
||||
improve_map(compiler, arg_buffers.storage_buffers, &map);
|
||||
improve_map(compiler, arg_buffers.sampled_images, &map);
|
||||
|
||||
char* returnString = (char*)malloc(sizeof(char) * (returnedCode.size() + 1));
|
||||
strcpy(returnString, returnedCode.c_str());
|
||||
return {
|
||||
.code = returnString,
|
||||
.map = map
|
||||
};
|
||||
std::string output = compiler->mslCompiler->compile();
|
||||
char* copied_output = (char*)malloc(sizeof(char*) * (output.size() + 1));
|
||||
strcpy(copied_output, output.c_str());
|
||||
copied_output[output.size()] = '\0';
|
||||
return copied_output;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,8 @@
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
typedef struct gnPlatformShaderModule_t {
|
||||
id<MTLFunction> function;
|
||||
mtlShaderMap shaderMap;
|
||||
mtlCompiler compiler;
|
||||
} gnPlatformShaderModule;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo);
|
||||
void destroyMetalShaderModule(gnShaderModule module);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo);
|
||||
void destroyMetalShaderModule(gnShaderModule module);
|
||||
|
||||
@@ -9,50 +9,22 @@
|
||||
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
|
||||
mtlCompilerInfo info = {
|
||||
.code = shaderModuleInfo.code,
|
||||
.wordCount = shaderModuleInfo.size / 4,
|
||||
.entryPoint = shaderModuleInfo.entryPoint.value,
|
||||
.stage = (shaderModuleInfo.stage == GN_FRAGMENT_SHADER_MODULE) ? mtlFragment : mtlVertex
|
||||
};
|
||||
if (shaderModuleInfo.stage == GN_FRAGMENT_SHADER_MODULE) options.stage = fragment;
|
||||
|
||||
mtlShader shader = mtlCompileShader(shaderModuleInfo.code, shaderModuleInfo.size / 4, &options);
|
||||
const char* res = shader.code;
|
||||
if (res == NULL) return GN_FAILED_TO_CONVERT_SHADER_CODE;
|
||||
printf("res: %s\n", res);
|
||||
|
||||
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)
|
||||
});
|
||||
[shaderLib release];
|
||||
free((void*)res);
|
||||
return GN_FAILED_TO_CREATE_SHADER_MODULE;
|
||||
if ((device->outputDevice->device.argumentBuffersSupport == MTLArgumentBuffersTier2)) {
|
||||
info.mslMajorVersion = 3;
|
||||
info.minorVersion = 0;
|
||||
info.useArgumentBuffers = true;
|
||||
} else {
|
||||
info.mslMajorVersion = 1;
|
||||
info.minorVersion = 0;
|
||||
info.useArgumentBuffers = false;
|
||||
}
|
||||
|
||||
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];
|
||||
if (options.stage == vertex) free((void*)res);
|
||||
module->shaderModule->shaderMap = shader.map;
|
||||
module->shaderModule->compiler = mtlCreateCompiler(&info);
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user