diff --git a/projects/apis/metal/loader/metal_device_loader.m b/projects/apis/metal/loader/metal_device_loader.m index bea199f..fedc1c7 100644 --- a/projects/apis/metal/loader/metal_device_loader.m +++ b/projects/apis/metal/loader/metal_device_loader.m @@ -48,6 +48,7 @@ gnDeviceFunctions loadMetalDeviceFunctions() { ._gnDestroyUniformPool = destroyMetalUniformPool, ._gnUpdateBufferUniform = updateMetalBufferUniform, + ._gnUpdateStorageUniform = updateMetalStorageUniform, ._gnUpdateImageUniform = updateMetalImageUniform, ._gnCreateTexture = createMetalTexture, diff --git a/projects/apis/metal/src/commands/commands/metal_commands.m b/projects/apis/metal/src/commands/commands/metal_commands.m index 9d92af0..be3e39e 100644 --- a/projects/apis/metal/src/commands/commands/metal_commands.m +++ b/projects/apis/metal/src/commands/commands/metal_commands.m @@ -115,31 +115,25 @@ void metalBindUniform(gnCommandBufferHandle buffer, gnUniform uniform, uint32_t for (int i = 0; i < uniform->uniform->bindingCount; i++) { if (uniform->uniform->bindings[i].type == GN_UNIFORM_BUFFER_DESCRIPTOR) { gnBufferUniformInfo info = *(gnBufferUniformInfo*)uniform->uniform->bindings[i].data; - - for (int c = 0; c < buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->vertexShaderMaps.uniformBufferMaps.count; c++) { - metalBindingMap map = buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->vertexShaderMaps.uniformBufferMaps.data[c]; - if (map.set == set && map.binding == uniform->uniform->bindings[i].binding) { - [encoder setVertexBuffer:info.buffer->buffer->buffer - offset:info.offset - atIndex:map.metalBindingIndex - ]; - break; - } - } + [encoder setVertexBuffer:info.buffer->buffer->buffer + offset:info.offset + atIndex:buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->vertexShaderMaps.sets[set].bindings[info.binding] + ]; + } else if (uniform->uniform->bindings[i].type == GN_SHADER_STORE_BUFFER_DESCRIPTOR) { + gnStorageUniformInfo info = *(gnStorageUniformInfo*)uniform->uniform->bindings[i].data; + [encoder setVertexBuffer:info.buffer->buffer->buffer + offset:info.offset + atIndex:buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->vertexShaderMaps.sets[set].bindings[info.binding] + ]; } else if (uniform->uniform->bindings[i].type == GN_IMAGE_DESCRIPTOR) { - for (int c = 0; c < buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.textureMaps.count; c++) { - metalBindingMap map = buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.textureMaps.data[c]; - if (map.set == set && map.binding == uniform->uniform->bindings[i].binding) { - gnImageUniformInfo info = *(gnImageUniformInfo*)uniform->uniform->bindings[i].data; - [encoder setFragmentTexture:info.texture->texture->texture atIndex:map.metalBindingIndex]; - break; - } - } + gnImageUniformInfo info = *(gnImageUniformInfo*)uniform->uniform->bindings[i].data; + [encoder setFragmentTexture:info.texture->texture->texture atIndex: + buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.sets[set].bindings[info.binding]]; } } } void metalBindVertexBytes(gnCommandBufferHandle buffer, gnPushConstantLayout layout, void* data) { id encoder = (id)buffer->commandBuffer->encoder; - [encoder setVertexBytes:data length:layout.size atIndex:buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->vertexShaderMaps.pushConstantIndex]; // TODO: fix this + [encoder setVertexBytes:data length:layout.size atIndex:1]; // TODO: fix this } diff --git a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.h b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.h index 06d1db2..8cdc9aa 100644 --- a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.h +++ b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.h @@ -6,7 +6,7 @@ typedef struct gnPlatformGraphicsPipeline_t { id graphicsPipeline; id depthState; - metalBindingMaps vertexShaderMaps, fragmentShaderMaps; + metalShaderMap vertexShaderMaps, fragmentShaderMaps; } gnPlatformGraphicsPipeline; gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gnOutputDevice device, gnGraphicsPipelineInfo info); diff --git a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m index 4abf056..bbe27e3 100644 --- a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m +++ b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m @@ -75,10 +75,10 @@ gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gn for (int i = 0; i < info.shaderModuleCount; i++) { if (info.shaderModules[i]->info.stage == GN_VERTEX_SHADER_MODULE) { [descriptor setVertexFunction:info.shaderModules[i]->shaderModule->function]; - graphicsPipeline->graphicsPipeline->vertexShaderMaps = info.shaderModules[i]->shaderModule->maps; + graphicsPipeline->graphicsPipeline->vertexShaderMaps = info.shaderModules[i]->shaderModule->map; } else if (info.shaderModules[i]->info.stage == GN_FRAGMENT_SHADER_MODULE) { [descriptor setFragmentFunction:info.shaderModules[i]->shaderModule->function]; - graphicsPipeline->graphicsPipeline->fragmentShaderMaps = info.shaderModules[i]->shaderModule->maps; + graphicsPipeline->graphicsPipeline->fragmentShaderMaps = info.shaderModules[i]->shaderModule->map; } else { return GN_UNSUPPORTED_SHADER_MODULE; } diff --git a/projects/apis/metal/src/shader_module/metal_shader_module.h b/projects/apis/metal/src/shader_module/metal_shader_module.h index 727abf6..22a6a46 100644 --- a/projects/apis/metal/src/shader_module/metal_shader_module.h +++ b/projects/apis/metal/src/shader_module/metal_shader_module.h @@ -3,23 +3,21 @@ #include "utils/lists/gryphn_array_list.h" #import -typedef struct metalBindingMap { - uint32_t set; - uint32_t binding; - uint32_t metalBindingIndex; -} metalBindingMap; -GN_ARRAY_LIST(metalBindingMap); +#define METAL_MAX_SET_COUNT 16 +#define METAL_MAX_BINDING_COUNT 16 -typedef struct metalBindingMaps { - metalBindingMapArrayList uniformBufferMaps; - uint32_t pushConstantIndex; - metalBindingMapArrayList textureMaps; -} metalBindingMaps; +typedef struct metalSetMap { + uint32_t bindings[METAL_MAX_BINDING_COUNT]; +} metalSetMap; + +typedef struct metalShaderMap { + metalSetMap sets[METAL_MAX_SET_COUNT]; + uint32_t pushConstantBufferIndex; +} metalShaderMap; typedef struct gnPlatformShaderModule_t { id function; - uint32_t pushConstantIndex; - metalBindingMaps maps; + metalShaderMap map; } gnPlatformShaderModule; gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo); diff --git a/projects/apis/metal/src/shader_module/metal_shader_module.m b/projects/apis/metal/src/shader_module/metal_shader_module.m index 6756043..f6d8c2c 100644 --- a/projects/apis/metal/src/shader_module/metal_shader_module.m +++ b/projects/apis/metal/src/shader_module/metal_shader_module.m @@ -8,62 +8,10 @@ void mtlSpirVErrorCallback(void *userdata, const char *error) { gnDebugger debugger = (gnDebugger)userdata; gnDebuggerSetErrorMessage(debugger, (gnMessageData){ - .message = gnCreateString(error) + .message = gnCombineStrings(gnCreateString("shader compilation error MSL "), gnCreateString(error)) }); } -metalBindingMapArrayList loadTextureBindingInformation(spvc_resources resources, spvc_compiler compiler) { - metalBindingMapArrayList bindings = metalBindingMapArrayListCreate(); - - const spvc_reflected_resource *list = NULL; - size_t count; - - 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); - - metalBindingMap map = { - .set = set, .binding = binding, - .metalBindingIndex = i - }; - metalBindingMapArrayListAdd(&bindings, map); - } - - return bindings; -} - -metalBindingMapArrayList loadUniformBufferInformation(spvc_resources resources, spvc_compiler compiler, gnShaderModuleStage stage) { - metalBindingMapArrayList bindings = metalBindingMapArrayListCreate(); - - const spvc_reflected_resource *list = NULL; - size_t count; - - spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_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); - - uint32_t realBinding = binding; - - // if ((stage & GN_VERTEX_SHADER_MODULE) == GN_VERTEX_SHADER_MODULE) - realBinding += 1; - - metalBindingMap map = { - .set = set, .binding = binding, - .metalBindingIndex = realBinding - }; - metalBindingMapArrayListAdd(&bindings, map); - - spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding); - spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, realBinding); - } - return bindings; -} - gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnShaderModuleInfo shaderModuleInfo) { module->shaderModule = malloc(sizeof(struct gnPlatformShaderModule_t)); @@ -83,14 +31,50 @@ gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnS spvc_compiler_create_shader_resources(compiler, &resources); - module->shaderModule->maps.uniformBufferMaps = loadUniformBufferInformation(resources, compiler, shaderModuleInfo.stage); - module->shaderModule->maps.textureMaps = loadTextureBindingInformation(resources, compiler); + spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SHADER_RECORD_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), + mslBinding = spvc_compiler_msl_get_automatic_resource_binding(compiler, list[i].id); + printf("%s: set %ui, binding %ui, mslBinding %ui\n", list[i].name, set, binding, mslBinding); + } + + 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); - module->shaderModule->maps.pushConstantIndex = module->shaderModule->maps.uniformBufferMaps.data[module->shaderModule->maps.uniformBufferMaps.count - 1].metalBindingIndex + 1; - spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, module->shaderModule->maps.pushConstantIndex); + spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, 1); } spvc_compiler_create_compiler_options(compiler, &options); @@ -143,6 +127,8 @@ gnReturnCode createMetalShaderModule(gnShaderModule module, gnDevice device, gnS [shaderLib release]; + printf("%s\n", result); + spvc_context_destroy(context); return GN_SUCCESS; } diff --git a/projects/apis/metal/src/uniforms/metal_uniform.h b/projects/apis/metal/src/uniforms/metal_uniform.h index 7288025..4455a41 100644 --- a/projects/apis/metal/src/uniforms/metal_uniform.h +++ b/projects/apis/metal/src/uniforms/metal_uniform.h @@ -14,4 +14,5 @@ typedef struct gnPlatformUniform_t { } gnPlatformUniform; void updateMetalBufferUniform(gnUniform uniform, gnBufferUniformInfo* info); +void updateMetalStorageUniform(gnUniform uniform, gnStorageUniformInfo* info); void updateMetalImageUniform(gnUniform uniform, gnImageUniformInfo* info); diff --git a/projects/apis/metal/src/uniforms/metal_uniform.m b/projects/apis/metal/src/uniforms/metal_uniform.m index 14b5aaa..9beebd3 100644 --- a/projects/apis/metal/src/uniforms/metal_uniform.m +++ b/projects/apis/metal/src/uniforms/metal_uniform.m @@ -11,6 +11,16 @@ void updateMetalBufferUniform(gnUniform uniform, gnBufferUniformInfo* info) { } } +void updateMetalStorageUniform(gnUniform uniform, gnStorageUniformInfo* info) { + for (int i = 0; i < uniform->uniform->bindingCount; i++) { + if (uniform->uniform->bindings[i].binding == info->binding) { + uniform->uniform->bindings[i].data = malloc(sizeof(gnStorageUniformInfo)); + memcpy(uniform->uniform->bindings[i].data, info, sizeof(gnStorageUniformInfo)); + break; + } + } +} + void updateMetalImageUniform(gnUniform uniform, gnImageUniformInfo* info) { for (int i = 0; i < uniform->uniform->bindingCount; i++) { if (uniform->uniform->bindings[i].binding == info->binding) {