SDL_shadercross: MSL: fix buffer ordering when transpiling compute from SPIRV (#77)

https://github.com/libsdl-org/SDL_shadercross/commit/efa0d1531bf3cccfc5ecf3076716f14684f29965

From efa0d1531bf3cccfc5ecf3076716f14684f29965 Mon Sep 17 00:00:00 2001
From: Mirko Covizzi <[EMAIL REDACTED]>
Date: Sun, 12 Jan 2025 02:40:55 +0100
Subject: [PATCH] MSL: fix buffer ordering when transpiling compute from SPIRV
 (#77)

Fixes the buffer ordering when transpiling compute shaders
from SPIRV.
The SPV kernel execution model produces a different
layout for HLSL and GLSL. When used with GLSL, the bindings
set are ignored by SPIRV-cross. In this case, use GLCompute
model instead. This produces the expected result.
Also properly assigns the return values that are checked
for errors.

Signed-off-by: Mirko Covizzi <mrkcvzz@gmail.com>
---
 src/SDL_shadercross.c | 94 +++++++++++++++++++++++--------------------
 1 file changed, 50 insertions(+), 44 deletions(-)

diff --git a/src/SDL_shadercross.c b/src/SDL_shadercross.c
index 0e69c4e..efc15c4 100644
--- a/src/SDL_shadercross.c
+++ b/src/SDL_shadercross.c
@@ -948,7 +948,11 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
     } else if (shaderStage == SDL_SHADERCROSS_SHADERSTAGE_FRAGMENT) {
         executionModel = SpvExecutionModelFragment;
     } else { // compute
-        executionModel = SpvExecutionModelKernel;
+        if (backend == SPVC_BACKEND_HLSL) {
+            executionModel = SpvExecutionModelKernel;
+        } else {
+            executionModel = SpvExecutionModelGLCompute;
+        }
     }
 
     // MSL doesn't have descriptor sets, so we have to set up index remapping
@@ -1433,20 +1437,19 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
             num_textures += 1;
         }
 
-        // Storage buffers
+        // Uniform buffers
         result = spvc_resources_get_resource_list_for_type(
             resources,
-            SPVC_RESOURCE_TYPE_STORAGE_BUFFER,
+            SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
             (const spvc_reflected_resource **)&reflected_resources,
-            &num_storage_buffers);
+            &num_uniform_buffers);
         if (result < 0) {
             SPVC_ERROR(spvc_resources_get_resource_list_for_type);
             spvc_context_destroy(context);
             return NULL;
         }
 
-        // Readonly storage buffers
-        for (size_t i = 0; i < num_storage_buffers; i += 1) {
+        for (size_t i = 0; i < num_uniform_buffers; i += 1) {
             if (!spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet) || !spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding)) {
                 SDL_SetError("%s", "Shader resources must have descriptor set and binding index!");
                 spvc_context_destroy(context);
@@ -1454,38 +1457,57 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
             }
 
             unsigned int descriptor_set_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet);
-            if (!(descriptor_set_index == 0 || descriptor_set_index == 1)) {
-                SDL_SetError("%s", "Descriptor set index for compute storage buffer must be 0 or 1!");
+            if (descriptor_set_index != 2) {
+                SDL_SetError("%s", "Descriptor set index for compute uniform buffer must be 2!");
                 spvc_context_destroy(context);
                 return NULL;
             }
 
-            // Skip readwrite buffers
-            if (descriptor_set_index != 0) { continue; }
-
             unsigned int binding_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding);
 
             binding.stage = executionModel;
             binding.desc_set = descriptor_set_index;
             binding.binding = binding_index;
             binding.msl_buffer = binding_index;
-            spvc_compiler_msl_add_resource_binding(compiler, &binding);
+            result = spvc_compiler_msl_add_resource_binding(compiler, &binding);
             if (result < 0) {
                 SPVC_ERROR(spvc_compiler_msl_add_resource_binding);
                 spvc_context_destroy(context);
                 return NULL;
             }
+        }
+        num_buffers += num_uniform_buffers;
 
-            num_buffers += 1;
+        // Storage buffers
+        result = spvc_resources_get_resource_list_for_type(
+            resources,
+            SPVC_RESOURCE_TYPE_STORAGE_BUFFER,
+            (const spvc_reflected_resource **)&reflected_resources,
+            &num_storage_buffers);
+        if (result < 0) {
+            SPVC_ERROR(spvc_resources_get_resource_list_for_type);
+            spvc_context_destroy(context);
+            return NULL;
         }
 
-        // Readwrite storage buffers
+        // Readonly storage buffers
         size_t current_num_buffers = num_buffers;
         for (size_t i = 0; i < num_storage_buffers; i += 1) {
+            if (!spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet) || !spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding)) {
+                SDL_SetError("%s", "Shader resources must have descriptor set and binding index!");
+                spvc_context_destroy(context);
+                return NULL;
+            }
+
             unsigned int descriptor_set_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet);
+            if (!(descriptor_set_index == 0|| descriptor_set_index == 1)) {
+                SDL_SetError("%s", "Descriptor set index for compute storage buffer must be 0 or 1!");
+                spvc_context_destroy(context);
+                return NULL;
+            }
 
-            // Skip readonly buffers
-            if (descriptor_set_index != 1) { continue; }
+            // Skip readwrite buffers
+            if (descriptor_set_index != 0) { continue; }
 
             unsigned int binding_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding);
 
@@ -1493,7 +1515,7 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
             binding.desc_set = descriptor_set_index;
             binding.binding = binding_index;
             binding.msl_buffer = current_num_buffers + binding_index;
-            spvc_compiler_msl_add_resource_binding(compiler, &binding);
+            result = spvc_compiler_msl_add_resource_binding(compiler, &binding);
             if (result < 0) {
                 SPVC_ERROR(spvc_compiler_msl_add_resource_binding);
                 spvc_context_destroy(context);
@@ -1503,46 +1525,30 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
             num_buffers += 1;
         }
 
-        // Uniform buffers
-        result = spvc_resources_get_resource_list_for_type(
-            resources,
-            SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
-            (const spvc_reflected_resource **)&reflected_resources,
-            &num_uniform_buffers);
-        if (result < 0) {
-            SPVC_ERROR(spvc_resources_get_resource_list_for_type);
-            spvc_context_destroy(context);
-            return NULL;
-        }
-
-        for (size_t i = 0; i < num_uniform_buffers; i += 1) {
-            if (!spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet) || !spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding)) {
-                SDL_SetError("%s", "Shader resources must have descriptor set and binding index!");
-                spvc_context_destroy(context);
-                return NULL;
-            }
-
+        // Readwrite storage buffers
+        current_num_buffers = num_buffers;
+        for (size_t i = 0; i < num_storage_buffers; i += 1) {
             unsigned int descriptor_set_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet);
-            if (descriptor_set_index != 2) {
-                SDL_SetError("%s", "Descriptor set index for compute uniform buffer must be 2!");
-                spvc_context_destroy(context);
-                return NULL;
-            }
+
+            // Skip readonly buffers
+            if (descriptor_set_index != 1) { continue; }
 
             unsigned int binding_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding);
 
             binding.stage = executionModel;
             binding.desc_set = descriptor_set_index;
             binding.binding = binding_index;
-            binding.msl_buffer = num_buffers + binding_index;
-            spvc_compiler_msl_add_resource_binding(compiler, &binding);
+            binding.msl_buffer = current_num_buffers + binding_index;
+            result = spvc_compiler_msl_add_resource_binding(compiler, &binding);
             if (result < 0) {
                 SPVC_ERROR(spvc_compiler_msl_add_resource_binding);
                 spvc_context_destroy(context);
                 return NULL;
             }
+
+            num_buffers += 1;
         }
-        num_buffers += num_uniform_buffers;
+
     }
 
     result = spvc_compiler_install_compiler_options(compiler, options);