Skip to content

Commit 14f24d7

Browse files
Merge pull request #1308 from KhronosGroup/fix-1306
HLSL: Add support for treating NonWritable UAV texture as SRV instead.
2 parents cfcd843 + 28bf905 commit 14f24d7

10 files changed

+268
-7
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ if (SPIRV_CROSS_STATIC)
323323
endif()
324324

325325
set(spirv-cross-abi-major 0)
326-
set(spirv-cross-abi-minor 28)
326+
set(spirv-cross-abi-minor 29)
327327
set(spirv-cross-abi-patch 0)
328328

329329
if (SPIRV_CROSS_SHARED)

main.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ struct CLIArguments
560560
bool hlsl_compat = false;
561561
bool hlsl_support_nonzero_base = false;
562562
bool hlsl_force_storage_buffer_as_uav = false;
563+
bool hlsl_nonwritable_uav_texture_as_srv = false;
563564
HLSLBindingFlags hlsl_binding_flags = 0;
564565
bool vulkan_semantics = false;
565566
bool flatten_multidimensional_arrays = false;
@@ -632,6 +633,7 @@ static void print_help()
632633
"\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
633634
"\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
634635
"\t[--hlsl-force-storage-buffer-as-uav]\n"
636+
"\t[--hlsl-nonwritable-uav-texture-as-srv]\n"
635637
"\t[--separate-shader-objects]\n"
636638
"\t[--pls-in format input-name]\n"
637639
"\t[--pls-out format output-name]\n"
@@ -988,6 +990,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
988990

989991
hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
990992
hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav;
993+
hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv;
991994
hlsl->set_hlsl_options(hlsl_opts);
992995
hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
993996
}
@@ -1154,6 +1157,8 @@ static int main_inner(int argc, char *argv[])
11541157
});
11551158
cbs.add("--hlsl-force-storage-buffer-as-uav",
11561159
[&args](CLIParser &) { args.hlsl_force_storage_buffer_as_uav = true; });
1160+
cbs.add("--hlsl-nonwritable-uav-texture-as-srv",
1161+
[&args](CLIParser &) { args.hlsl_nonwritable_uav_texture_as_srv = true; });
11571162
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
11581163
cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
11591164
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u);
2+
3+
Texture2D<float4> uImageInF : register(t0);
4+
RWTexture2D<float> uImageOutF : register(u1);
5+
Texture2D<int4> uImageInI : register(t2);
6+
RWTexture2D<int> uImageOutI : register(u3);
7+
Texture2D<uint4> uImageInU : register(t4);
8+
RWTexture2D<uint> uImageOutU : register(u5);
9+
Buffer<float4> uImageInBuffer : register(t6);
10+
RWBuffer<float> uImageOutBuffer : register(u7);
11+
Texture2D<float4> uImageInF2 : register(t8);
12+
RWTexture2D<float2> uImageOutF2 : register(u9);
13+
Texture2D<int4> uImageInI2 : register(t10);
14+
RWTexture2D<int2> uImageOutI2 : register(u11);
15+
Texture2D<uint4> uImageInU2 : register(t12);
16+
RWTexture2D<uint2> uImageOutU2 : register(u13);
17+
Buffer<float4> uImageInBuffer2 : register(t14);
18+
RWBuffer<float2> uImageOutBuffer2 : register(u15);
19+
Texture2D<float4> uImageInF4 : register(t16);
20+
RWTexture2D<float4> uImageOutF4 : register(u17);
21+
Texture2D<int4> uImageInI4 : register(t18);
22+
RWTexture2D<int4> uImageOutI4 : register(u19);
23+
Texture2D<uint4> uImageInU4 : register(t20);
24+
RWTexture2D<uint4> uImageOutU4 : register(u21);
25+
Buffer<float4> uImageInBuffer4 : register(t22);
26+
RWBuffer<float4> uImageOutBuffer4 : register(u23);
27+
RWTexture2D<float4> uImageNoFmtF : register(u24);
28+
RWTexture2D<uint4> uImageNoFmtU : register(u25);
29+
RWTexture2D<int4> uImageNoFmtI : register(u26);
30+
31+
static uint3 gl_GlobalInvocationID;
32+
struct SPIRV_Cross_Input
33+
{
34+
uint3 gl_GlobalInvocationID : SV_DispatchThreadID;
35+
};
36+
37+
void comp_main()
38+
{
39+
int2 _23 = int2(gl_GlobalInvocationID.xy);
40+
uImageOutF[_23] = uImageInF[_23].x;
41+
uImageOutI[_23] = uImageInI[_23].x;
42+
uImageOutU[_23] = uImageInU[_23].x;
43+
int _74 = int(gl_GlobalInvocationID.x);
44+
uImageOutBuffer[_74] = uImageInBuffer[_74].x;
45+
uImageOutF2[_23] = uImageInF2[_23].xy;
46+
uImageOutI2[_23] = uImageInI2[_23].xy;
47+
uImageOutU2[_23] = uImageInU2[_23].xy;
48+
float4 _135 = uImageInBuffer2[_74];
49+
uImageOutBuffer2[_74] = _135.xy;
50+
uImageOutF4[_23] = uImageInF4[_23];
51+
int4 _165 = uImageInI4[_23];
52+
uImageOutI4[_23] = _165;
53+
uint4 _180 = uImageInU4[_23];
54+
uImageOutU4[_23] = _180;
55+
uImageOutBuffer4[_74] = uImageInBuffer4[_74];
56+
uImageNoFmtF[_23] = _135;
57+
uImageNoFmtU[_23] = _180;
58+
uImageNoFmtI[_23] = _165;
59+
}
60+
61+
[numthreads(1, 1, 1)]
62+
void main(SPIRV_Cross_Input stage_input)
63+
{
64+
gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID;
65+
comp_main();
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u);
2+
3+
Texture2D<float4> uImageInF : register(t0);
4+
RWTexture2D<float> uImageOutF : register(u1);
5+
Texture2D<int4> uImageInI : register(t2);
6+
RWTexture2D<int> uImageOutI : register(u3);
7+
Texture2D<uint4> uImageInU : register(t4);
8+
RWTexture2D<uint> uImageOutU : register(u5);
9+
Buffer<float4> uImageInBuffer : register(t6);
10+
RWBuffer<float> uImageOutBuffer : register(u7);
11+
Texture2D<float4> uImageInF2 : register(t8);
12+
RWTexture2D<float2> uImageOutF2 : register(u9);
13+
Texture2D<int4> uImageInI2 : register(t10);
14+
RWTexture2D<int2> uImageOutI2 : register(u11);
15+
Texture2D<uint4> uImageInU2 : register(t12);
16+
RWTexture2D<uint2> uImageOutU2 : register(u13);
17+
Buffer<float4> uImageInBuffer2 : register(t14);
18+
RWBuffer<float2> uImageOutBuffer2 : register(u15);
19+
Texture2D<float4> uImageInF4 : register(t16);
20+
RWTexture2D<float4> uImageOutF4 : register(u17);
21+
Texture2D<int4> uImageInI4 : register(t18);
22+
RWTexture2D<int4> uImageOutI4 : register(u19);
23+
Texture2D<uint4> uImageInU4 : register(t20);
24+
RWTexture2D<uint4> uImageOutU4 : register(u21);
25+
Buffer<float4> uImageInBuffer4 : register(t22);
26+
RWBuffer<float4> uImageOutBuffer4 : register(u23);
27+
RWTexture2D<float4> uImageNoFmtF : register(u24);
28+
RWTexture2D<uint4> uImageNoFmtU : register(u25);
29+
RWTexture2D<int4> uImageNoFmtI : register(u26);
30+
31+
static uint3 gl_GlobalInvocationID;
32+
struct SPIRV_Cross_Input
33+
{
34+
uint3 gl_GlobalInvocationID : SV_DispatchThreadID;
35+
};
36+
37+
void comp_main()
38+
{
39+
float4 f = uImageInF[int2(gl_GlobalInvocationID.xy)];
40+
uImageOutF[int2(gl_GlobalInvocationID.xy)] = f.x;
41+
int4 i = uImageInI[int2(gl_GlobalInvocationID.xy)];
42+
uImageOutI[int2(gl_GlobalInvocationID.xy)] = i.x;
43+
uint4 u = uImageInU[int2(gl_GlobalInvocationID.xy)];
44+
uImageOutU[int2(gl_GlobalInvocationID.xy)] = u.x;
45+
float4 b = uImageInBuffer[int(gl_GlobalInvocationID.x)];
46+
uImageOutBuffer[int(gl_GlobalInvocationID.x)] = b.x;
47+
float4 f2 = uImageInF2[int2(gl_GlobalInvocationID.xy)];
48+
uImageOutF2[int2(gl_GlobalInvocationID.xy)] = f2.xy;
49+
int4 i2 = uImageInI2[int2(gl_GlobalInvocationID.xy)];
50+
uImageOutI2[int2(gl_GlobalInvocationID.xy)] = i2.xy;
51+
uint4 u2 = uImageInU2[int2(gl_GlobalInvocationID.xy)];
52+
uImageOutU2[int2(gl_GlobalInvocationID.xy)] = u2.xy;
53+
float4 b2 = uImageInBuffer2[int(gl_GlobalInvocationID.x)];
54+
uImageOutBuffer2[int(gl_GlobalInvocationID.x)] = b2.xy;
55+
float4 f4 = uImageInF4[int2(gl_GlobalInvocationID.xy)];
56+
uImageOutF4[int2(gl_GlobalInvocationID.xy)] = f4;
57+
int4 i4 = uImageInI4[int2(gl_GlobalInvocationID.xy)];
58+
uImageOutI4[int2(gl_GlobalInvocationID.xy)] = i4;
59+
uint4 u4 = uImageInU4[int2(gl_GlobalInvocationID.xy)];
60+
uImageOutU4[int2(gl_GlobalInvocationID.xy)] = u4;
61+
float4 b4 = uImageInBuffer4[int(gl_GlobalInvocationID.x)];
62+
uImageOutBuffer4[int(gl_GlobalInvocationID.x)] = b4;
63+
uImageNoFmtF[int2(gl_GlobalInvocationID.xy)] = b2;
64+
uImageNoFmtU[int2(gl_GlobalInvocationID.xy)] = u4;
65+
uImageNoFmtI[int2(gl_GlobalInvocationID.xy)] = i4;
66+
}
67+
68+
[numthreads(1, 1, 1)]
69+
void main(SPIRV_Cross_Input stage_input)
70+
{
71+
gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID;
72+
comp_main();
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#version 450
2+
layout(local_size_x = 1) in;
3+
4+
layout(r32f, binding = 0) uniform readonly image2D uImageInF;
5+
layout(r32f, binding = 1) uniform writeonly image2D uImageOutF;
6+
layout(r32i, binding = 2) uniform readonly iimage2D uImageInI;
7+
layout(r32i, binding = 3) uniform writeonly iimage2D uImageOutI;
8+
layout(r32ui, binding = 4) uniform readonly uimage2D uImageInU;
9+
layout(r32ui, binding = 5) uniform writeonly uimage2D uImageOutU;
10+
layout(r32f, binding = 6) uniform readonly imageBuffer uImageInBuffer;
11+
layout(r32f, binding = 7) uniform writeonly imageBuffer uImageOutBuffer;
12+
13+
layout(rg32f, binding = 8) uniform readonly image2D uImageInF2;
14+
layout(rg32f, binding = 9) uniform writeonly image2D uImageOutF2;
15+
layout(rg32i, binding = 10) uniform readonly iimage2D uImageInI2;
16+
layout(rg32i, binding = 11) uniform writeonly iimage2D uImageOutI2;
17+
layout(rg32ui, binding = 12) uniform readonly uimage2D uImageInU2;
18+
layout(rg32ui, binding = 13) uniform writeonly uimage2D uImageOutU2;
19+
layout(rg32f, binding = 14) uniform readonly imageBuffer uImageInBuffer2;
20+
layout(rg32f, binding = 15) uniform writeonly imageBuffer uImageOutBuffer2;
21+
22+
layout(rgba32f, binding = 16) uniform readonly image2D uImageInF4;
23+
layout(rgba32f, binding = 17) uniform writeonly image2D uImageOutF4;
24+
layout(rgba32i, binding = 18) uniform readonly iimage2D uImageInI4;
25+
layout(rgba32i, binding = 19) uniform writeonly iimage2D uImageOutI4;
26+
layout(rgba32ui, binding = 20) uniform readonly uimage2D uImageInU4;
27+
layout(rgba32ui, binding = 21) uniform writeonly uimage2D uImageOutU4;
28+
layout(rgba32f, binding = 22) uniform readonly imageBuffer uImageInBuffer4;
29+
layout(rgba32f, binding = 23) uniform writeonly imageBuffer uImageOutBuffer4;
30+
31+
layout(binding = 24) uniform writeonly image2D uImageNoFmtF;
32+
layout(binding = 25) uniform writeonly uimage2D uImageNoFmtU;
33+
layout(binding = 26) uniform writeonly iimage2D uImageNoFmtI;
34+
35+
void main()
36+
{
37+
vec4 f = imageLoad(uImageInF, ivec2(gl_GlobalInvocationID.xy));
38+
imageStore(uImageOutF, ivec2(gl_GlobalInvocationID.xy), f);
39+
40+
ivec4 i = imageLoad(uImageInI, ivec2(gl_GlobalInvocationID.xy));
41+
imageStore(uImageOutI, ivec2(gl_GlobalInvocationID.xy), i);
42+
43+
uvec4 u = imageLoad(uImageInU, ivec2(gl_GlobalInvocationID.xy));
44+
imageStore(uImageOutU, ivec2(gl_GlobalInvocationID.xy), u);
45+
46+
vec4 b = imageLoad(uImageInBuffer, int(gl_GlobalInvocationID.x));
47+
imageStore(uImageOutBuffer, int(gl_GlobalInvocationID.x), b);
48+
49+
vec4 f2 = imageLoad(uImageInF2, ivec2(gl_GlobalInvocationID.xy));
50+
imageStore(uImageOutF2, ivec2(gl_GlobalInvocationID.xy), f2);
51+
52+
ivec4 i2 = imageLoad(uImageInI2, ivec2(gl_GlobalInvocationID.xy));
53+
imageStore(uImageOutI2, ivec2(gl_GlobalInvocationID.xy), i2);
54+
55+
uvec4 u2 = imageLoad(uImageInU2, ivec2(gl_GlobalInvocationID.xy));
56+
imageStore(uImageOutU2, ivec2(gl_GlobalInvocationID.xy), u2);
57+
58+
vec4 b2 = imageLoad(uImageInBuffer2, int(gl_GlobalInvocationID.x));
59+
imageStore(uImageOutBuffer2, int(gl_GlobalInvocationID.x), b2);
60+
61+
vec4 f4 = imageLoad(uImageInF4, ivec2(gl_GlobalInvocationID.xy));
62+
imageStore(uImageOutF4, ivec2(gl_GlobalInvocationID.xy), f4);
63+
64+
ivec4 i4 = imageLoad(uImageInI4, ivec2(gl_GlobalInvocationID.xy));
65+
imageStore(uImageOutI4, ivec2(gl_GlobalInvocationID.xy), i4);
66+
67+
uvec4 u4 = imageLoad(uImageInU4, ivec2(gl_GlobalInvocationID.xy));
68+
imageStore(uImageOutU4, ivec2(gl_GlobalInvocationID.xy), u4);
69+
70+
vec4 b4 = imageLoad(uImageInBuffer4, int(gl_GlobalInvocationID.x));
71+
imageStore(uImageOutBuffer4, int(gl_GlobalInvocationID.x), b4);
72+
73+
imageStore(uImageNoFmtF, ivec2(gl_GlobalInvocationID.xy), b2);
74+
imageStore(uImageNoFmtU, ivec2(gl_GlobalInvocationID.xy), u4);
75+
imageStore(uImageNoFmtI, ivec2(gl_GlobalInvocationID.xy), i4);
76+
}
77+

spirv_cross_c.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
481481
case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV:
482482
options->hlsl.force_storage_buffer_as_uav = value != 0;
483483
break;
484+
485+
case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV:
486+
options->hlsl.nonwritable_uav_texture_as_srv = value != 0;
487+
break;
484488
#endif
485489

486490
#if SPIRV_CROSS_C_API_MSL

spirv_cross_c.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ extern "C" {
3333
/* Bumped if ABI or API breaks backwards compatibility. */
3434
#define SPVC_C_API_VERSION_MAJOR 0
3535
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
36-
#define SPVC_C_API_VERSION_MINOR 28
36+
#define SPVC_C_API_VERSION_MINOR 29
3737
/* Bumped if internal implementation details change. */
3838
#define SPVC_C_API_VERSION_PATCH 0
3939

@@ -580,6 +580,8 @@ typedef enum spvc_compiler_option
580580

581581
SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT,
582582

583+
SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV = 55 | SPVC_COMPILER_OPTION_HLSL_BIT,
584+
583585
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
584586
} spvc_compiler_option;
585587

spirv_hlsl.cpp

+32-5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
210210
bool typed_load = false;
211211
uint32_t components = 4;
212212

213+
bool force_image_srv = hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(id, DecorationNonWritable);
214+
213215
switch (type.image.dim)
214216
{
215217
case Dim1D:
@@ -239,7 +241,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
239241
if (interlocked_resources.count(id))
240242
return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype),
241243
">");
242-
return join("RWBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">");
244+
245+
typed_load = !force_image_srv && type.image.sampled == 2;
246+
247+
const char *rw = force_image_srv ? "" : "RW";
248+
return join(rw, "Buffer<",
249+
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
250+
join(type_to_glsl(imagetype), components),
251+
">");
243252
}
244253
else
245254
SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime.");
@@ -252,9 +261,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
252261
}
253262
const char *arrayed = type.image.arrayed ? "Array" : "";
254263
const char *ms = type.image.ms ? "MS" : "";
255-
const char *rw = typed_load ? "RW" : "";
264+
const char *rw = typed_load && !force_image_srv ? "RW" : "";
265+
266+
if (force_image_srv)
267+
typed_load = false;
268+
256269
if (typed_load && interlocked_resources.count(id))
257270
rw = "RasterizerOrdered";
271+
258272
return join(rw, "Texture", dim, ms, arrayed, "<",
259273
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
260274
join(type_to_glsl(imagetype), components),
@@ -2971,8 +2985,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
29712985
case SPIRType::Image:
29722986
if (type.image.sampled == 2 && type.image.dim != DimSubpassData)
29732987
{
2974-
space = 'u'; // UAV
2975-
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
2988+
if (has_decoration(var.self, DecorationNonWritable) && hlsl_options.nonwritable_uav_texture_as_srv)
2989+
{
2990+
space = 't'; // SRV
2991+
resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
2992+
}
2993+
else
2994+
{
2995+
space = 'u'; // UAV
2996+
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
2997+
}
29762998
}
29772999
else
29783000
{
@@ -4813,7 +4835,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
48134835
imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]");
48144836
// The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
48154837
// except that the underlying type changes how the data is interpreted.
4816-
if (var && !subpass_data)
4838+
4839+
bool force_srv =
4840+
hlsl_options.nonwritable_uav_texture_as_srv && var && has_decoration(var->self, DecorationNonWritable);
4841+
pure = force_srv;
4842+
4843+
if (var && !subpass_data && !force_srv)
48174844
imgexpr = remap_swizzle(get<SPIRType>(result_type),
48184845
image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
48194846
}

spirv_hlsl.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ class CompilerHLSL : public CompilerGLSL
113113
// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
114114
// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
115115
bool force_storage_buffer_as_uav = false;
116+
117+
// Forces any storage image type marked as NonWritable to be considered an SRV instead.
118+
// For this to work with function call parameters, NonWritable must be considered to be part of the type system
119+
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
120+
bool nonwritable_uav_texture_as_srv = false;
116121
};
117122

118123
explicit CompilerHLSL(std::vector<uint32_t> spirv_)

test_shaders.py

+2
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati
364364
hlsl_args.append('--hlsl-force-storage-buffer-as-uav')
365365
if '.zero-initialize.' in shader:
366366
hlsl_args.append('--force-zero-initialized-variables')
367+
if '.nonwritable-uav-texture.' in shader:
368+
hlsl_args.append('--hlsl-nonwritable-uav-texture-as-srv')
367369

368370
subprocess.check_call(hlsl_args)
369371

0 commit comments

Comments
 (0)