KhronosGroup / SPIRV-Cross

SPIRV-Cross is a practical tool and library for performing reflection on SPIR-V and disassembling SPIR-V back to high level languages.
Apache License 2.0
2.02k stars 557 forks source link

MSL: All textures and samplers get set to the same index #2111

Closed Ravbug closed 1 year ago

Ravbug commented 1 year ago

I am trying to transpile this GLSL shader to MSL:

#version 450

uniform sampler2D colorSampler;
uniform sampler2D normalSampler;
uniform sampler2D positionSampler;

layout(location = 0) out vec4 outColor;

void main() {
    // sample textures, cut for brevity ...
}

I am using the following code to do it:

spirv_cross::CompilerMSL::Options options;
uint32_t major = 3;
uint32_t minor = 0;
options.set_msl_version(major,minor);
options.platform = spirv_cross::CompilerMSL::Options::Platform::macOS;
options.enable_decoration_binding = true;
msl.set_msl_options(options);

{
    int currentIndex = 0;
    for(auto& resource : refldata.sampled_images){
        spirv_cross::MSLResourceBinding newBinding;
        newBinding.stage = model;
        newBinding.desc_set = msl.get_decoration(resource.id, spv::Decoration::DecorationDescriptorSet);
        newBinding.msl_texture = currentIndex;
        newBinding.msl_sampler = currentIndex;
        msl.add_msl_resource_binding( newBinding );
        currentIndex++;
    }
}
return msl.compile();

However, this results in all textures and samplers being set to the same [[texture(n)]] and [[sampler(n)]] (2):

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

struct dirlight_frag_out
{
    float4 outColor [[color(0)]];
};

fragment dirlight_frag_out dirlight_frag(texture2d<float> colorSampler [[texture(2)]], texture2d<float> normalSampler [[texture(2)]], texture2d<float> positionSampler [[texture(2)]], sampler colorSamplerSmplr [[sampler(2)]], sampler normalSamplerSmplr [[sampler(2)]], sampler positionSamplerSmplr [[sampler(2)]])
{
   // cut for brevity ...
}

I noticed when stepping into add_msl_resource_binding that tuple is always set to the same value, which results in only one entry total added to resource_bindings. However, when I tried to set newBinding.binding or newBinding.desc_set to an increasing number, all texture indices got set to 0.

image

How can I set spirv-cross to give each texture-sampler pair an increasing index?

HansKristian-Work commented 1 year ago
    newBinding.desc_set = msl.get_decoration(resource.id, spv::Decoration::DecorationDescriptorSet);

You're not using newBinding.binding.

options.enable_decoration_binding = true;

Is not supposed to be used when you use explicit binding API.

Ravbug commented 1 year ago

The issue I'm running into is if I don't have options.enable_decoration_binding = true, the texture indices are ordered by first use rather than by the order they are declared in the shader. Is there a way to ensure that the indices match the order the uniforms are listed in the GLSL? For example, if I have:

uniform sampler2D colorSampler;
uniform sampler2D normalSampler;
uniform sampler2D positionSampler;

I want the resulting Metal shader to have

fragment dirlight_frag_out dirlight_frag(texture2d<float> colorSampler [[texture(0)]], texture2d<float> normalSampler [[texture(1)]], texture2d<float> positionSampler [[texture(2)]], sampler colorSamplerSmplr [[sampler(0)]], sampler normalSamplerSmplr [[sampler(1)]], sampler positionSamplerSmplr [[sampler(2)]])
Ravbug commented 1 year ago

Resolved by setting explicit binding positions (binding = n) in the input shader.