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.03k stars 559 forks source link

HLSL: binding start offset feature #2340

Open TheArheus opened 3 months ago

TheArheus commented 3 months ago

Hi, I have small user experience issue, not really bug or anything. I am interested if spirv-cross have a feature so that when it cross compile from spv to hlsl, it would start, for example, CBVs not from 0, but from another user specified value. For example, right now, I have this cbuffer, generated from spirv:

cbuffer pushConstant
{
    row_major float4x4 _75_ShadowMatrix : packoffset(c0);
};

And I want to know if it spirv-cross could generate the bindings for specific resource type to be started from another value(for example, starting from 1) and not from zero

HansKristian-Work commented 3 months ago

What do you mean here, do you want to offset packoffset() (c0), or register(b#)? Of the latter, you can use the resource binding APIs to achieve that. Random resource shifts is jarring and not supported. You can override the bindings in many different ways.

TheArheus commented 3 months ago

Yeah, I was about packoffset(c#) starts from some arbitrary value and register(b#, space#) to start from some value and was thinking about this feature or how to do this if already implemed features

HansKristian-Work commented 3 months ago

You want to look at CompilerHLSL::add_hlsl_resource_binding. It can override register/space as needed. packoffset is really something you don't want to mess with. If you really want to do you overwrite the decorations with set_member_decoration(type.self, DecorationOffset, offset) on the type.

TheArheus commented 3 months ago

@HansKristian-Work there is another thing with generating actual hlsl code. It is similar to my initial issue, but different, and I think this should be a bug. For example, I have this piece of glsl shader bindings defines:

layout(set = 0, binding = 8)  uniform sampler2D GBuffer[GBUFFER_COUNT]; // << Based on error, this one is the issue, GBUFFER_COUNT is equal to 5
layout(set = 0, binding = 9)  uniform writeonly image2D ColorTarget;
layout(set = 0, binding = 10) uniform writeonly image2D BrightTarget;
layout(set = 0, binding = 11) uniform sampler2D AmbientOcclusionBuffer;
layout(set = 0, binding = 12) uniform sampler2D ShadowMap[DEPTH_CASCADES_COUNT];

And the issue is that it will translate to something like this:

Texture2D<float4> GBuffer[GBUFFER_COUNT] : register(t8, space0); // <-- The issue will be after this
SamplerState _GBuffer_sampler[GBUFFER_COUNT] : register(s8, space0); // <-- The issue will be after this
RWTexture2D<float4> ColorTarget : register(u9, space0);
RWTexture2D<float4> BrightTarget : register(u10, space0);
Texture2D<float4> AmbientOcclusionBuffer : register(t11, space0);
SamplerState _AmbientOcclusionBuffer_sampler : register(s11, space0);
Texture2D<float4> ShadowMap[DEPTH_CASCADES_COUNT] : register(t12, space0);
SamplerState _ShadowMap_sampler[DEPTH_CASCADES_COUNT] : register(s12, space0);

The issue is that after translating glsl to hlsl, there will be overlapping registers and I wont be able to create a pipeline state. If I have a register, which is actually an array of samplers (like GBuffer in my code), then, the bindings after that should come like this:

Texture2D<float4> GBuffer[GBUFFER_COUNT] : register(t8, space0); // <-- Now there shouldn't be an issue after that
SamplerState _GBuffer_sampler[GBUFFER_COUNT] : register(s8, space0); // <-- Now there shouldn't be an issue after that
RWTexture2D<float4> ColorTarget : register(u13, space0);
RWTexture2D<float4> BrightTarget : register(u14, space0);
Texture2D<float4> AmbientOcclusionBuffer : register(t15, space0);
SamplerState _AmbientOcclusionBuffer_sampler : register(s15, space0);
Texture2D<float4> ShadowMap[DEPTH_CASCADES_COUNT] : register(t16, space0);
SamplerState _ShadowMap_sampler[DEPTH_CASCADES_COUNT] : register(s16, space0);

Or it shpuld just generate Texture2DArray, but then without binding offset