Skip to content

Commit

Permalink
Merge pull request #1308 from KhronosGroup/fix-1306
Browse files Browse the repository at this point in the history
HLSL: Add support for treating NonWritable UAV texture as SRV instead.
  • Loading branch information
HansKristian-Work authored Apr 3, 2020
2 parents cfcd843 + 28bf905 commit 14f24d7
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ if (SPIRV_CROSS_STATIC)
endif()

set(spirv-cross-abi-major 0)
set(spirv-cross-abi-minor 28)
set(spirv-cross-abi-minor 29)
set(spirv-cross-abi-patch 0)

if (SPIRV_CROSS_SHARED)
Expand Down
5 changes: 5 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ struct CLIArguments
bool hlsl_compat = false;
bool hlsl_support_nonzero_base = false;
bool hlsl_force_storage_buffer_as_uav = false;
bool hlsl_nonwritable_uav_texture_as_srv = false;
HLSLBindingFlags hlsl_binding_flags = 0;
bool vulkan_semantics = false;
bool flatten_multidimensional_arrays = false;
Expand Down Expand Up @@ -632,6 +633,7 @@ static void print_help()
"\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
"\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
"\t[--hlsl-force-storage-buffer-as-uav]\n"
"\t[--hlsl-nonwritable-uav-texture-as-srv]\n"
"\t[--separate-shader-objects]\n"
"\t[--pls-in format input-name]\n"
"\t[--pls-out format output-name]\n"
Expand Down Expand Up @@ -988,6 +990,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>

hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav;
hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv;
hlsl->set_hlsl_options(hlsl_opts);
hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
}
Expand Down Expand Up @@ -1154,6 +1157,8 @@ static int main_inner(int argc, char *argv[])
});
cbs.add("--hlsl-force-storage-buffer-as-uav",
[&args](CLIParser &) { args.hlsl_force_storage_buffer_as_uav = true; });
cbs.add("--hlsl-nonwritable-uav-texture-as-srv",
[&args](CLIParser &) { args.hlsl_nonwritable_uav_texture_as_srv = true; });
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
Expand Down
66 changes: 66 additions & 0 deletions reference/opt/shaders-hlsl/comp/image.nonwritable-uav-texture.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u);

Texture2D<float4> uImageInF : register(t0);
RWTexture2D<float> uImageOutF : register(u1);
Texture2D<int4> uImageInI : register(t2);
RWTexture2D<int> uImageOutI : register(u3);
Texture2D<uint4> uImageInU : register(t4);
RWTexture2D<uint> uImageOutU : register(u5);
Buffer<float4> uImageInBuffer : register(t6);
RWBuffer<float> uImageOutBuffer : register(u7);
Texture2D<float4> uImageInF2 : register(t8);
RWTexture2D<float2> uImageOutF2 : register(u9);
Texture2D<int4> uImageInI2 : register(t10);
RWTexture2D<int2> uImageOutI2 : register(u11);
Texture2D<uint4> uImageInU2 : register(t12);
RWTexture2D<uint2> uImageOutU2 : register(u13);
Buffer<float4> uImageInBuffer2 : register(t14);
RWBuffer<float2> uImageOutBuffer2 : register(u15);
Texture2D<float4> uImageInF4 : register(t16);
RWTexture2D<float4> uImageOutF4 : register(u17);
Texture2D<int4> uImageInI4 : register(t18);
RWTexture2D<int4> uImageOutI4 : register(u19);
Texture2D<uint4> uImageInU4 : register(t20);
RWTexture2D<uint4> uImageOutU4 : register(u21);
Buffer<float4> uImageInBuffer4 : register(t22);
RWBuffer<float4> uImageOutBuffer4 : register(u23);
RWTexture2D<float4> uImageNoFmtF : register(u24);
RWTexture2D<uint4> uImageNoFmtU : register(u25);
RWTexture2D<int4> uImageNoFmtI : register(u26);

static uint3 gl_GlobalInvocationID;
struct SPIRV_Cross_Input
{
uint3 gl_GlobalInvocationID : SV_DispatchThreadID;
};

void comp_main()
{
int2 _23 = int2(gl_GlobalInvocationID.xy);
uImageOutF[_23] = uImageInF[_23].x;
uImageOutI[_23] = uImageInI[_23].x;
uImageOutU[_23] = uImageInU[_23].x;
int _74 = int(gl_GlobalInvocationID.x);
uImageOutBuffer[_74] = uImageInBuffer[_74].x;
uImageOutF2[_23] = uImageInF2[_23].xy;
uImageOutI2[_23] = uImageInI2[_23].xy;
uImageOutU2[_23] = uImageInU2[_23].xy;
float4 _135 = uImageInBuffer2[_74];
uImageOutBuffer2[_74] = _135.xy;
uImageOutF4[_23] = uImageInF4[_23];
int4 _165 = uImageInI4[_23];
uImageOutI4[_23] = _165;
uint4 _180 = uImageInU4[_23];
uImageOutU4[_23] = _180;
uImageOutBuffer4[_74] = uImageInBuffer4[_74];
uImageNoFmtF[_23] = _135;
uImageNoFmtU[_23] = _180;
uImageNoFmtI[_23] = _165;
}

[numthreads(1, 1, 1)]
void main(SPIRV_Cross_Input stage_input)
{
gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID;
comp_main();
}
73 changes: 73 additions & 0 deletions reference/shaders-hlsl/comp/image.nonwritable-uav-texture.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u);

Texture2D<float4> uImageInF : register(t0);
RWTexture2D<float> uImageOutF : register(u1);
Texture2D<int4> uImageInI : register(t2);
RWTexture2D<int> uImageOutI : register(u3);
Texture2D<uint4> uImageInU : register(t4);
RWTexture2D<uint> uImageOutU : register(u5);
Buffer<float4> uImageInBuffer : register(t6);
RWBuffer<float> uImageOutBuffer : register(u7);
Texture2D<float4> uImageInF2 : register(t8);
RWTexture2D<float2> uImageOutF2 : register(u9);
Texture2D<int4> uImageInI2 : register(t10);
RWTexture2D<int2> uImageOutI2 : register(u11);
Texture2D<uint4> uImageInU2 : register(t12);
RWTexture2D<uint2> uImageOutU2 : register(u13);
Buffer<float4> uImageInBuffer2 : register(t14);
RWBuffer<float2> uImageOutBuffer2 : register(u15);
Texture2D<float4> uImageInF4 : register(t16);
RWTexture2D<float4> uImageOutF4 : register(u17);
Texture2D<int4> uImageInI4 : register(t18);
RWTexture2D<int4> uImageOutI4 : register(u19);
Texture2D<uint4> uImageInU4 : register(t20);
RWTexture2D<uint4> uImageOutU4 : register(u21);
Buffer<float4> uImageInBuffer4 : register(t22);
RWBuffer<float4> uImageOutBuffer4 : register(u23);
RWTexture2D<float4> uImageNoFmtF : register(u24);
RWTexture2D<uint4> uImageNoFmtU : register(u25);
RWTexture2D<int4> uImageNoFmtI : register(u26);

static uint3 gl_GlobalInvocationID;
struct SPIRV_Cross_Input
{
uint3 gl_GlobalInvocationID : SV_DispatchThreadID;
};

void comp_main()
{
float4 f = uImageInF[int2(gl_GlobalInvocationID.xy)];
uImageOutF[int2(gl_GlobalInvocationID.xy)] = f.x;
int4 i = uImageInI[int2(gl_GlobalInvocationID.xy)];
uImageOutI[int2(gl_GlobalInvocationID.xy)] = i.x;
uint4 u = uImageInU[int2(gl_GlobalInvocationID.xy)];
uImageOutU[int2(gl_GlobalInvocationID.xy)] = u.x;
float4 b = uImageInBuffer[int(gl_GlobalInvocationID.x)];
uImageOutBuffer[int(gl_GlobalInvocationID.x)] = b.x;
float4 f2 = uImageInF2[int2(gl_GlobalInvocationID.xy)];
uImageOutF2[int2(gl_GlobalInvocationID.xy)] = f2.xy;
int4 i2 = uImageInI2[int2(gl_GlobalInvocationID.xy)];
uImageOutI2[int2(gl_GlobalInvocationID.xy)] = i2.xy;
uint4 u2 = uImageInU2[int2(gl_GlobalInvocationID.xy)];
uImageOutU2[int2(gl_GlobalInvocationID.xy)] = u2.xy;
float4 b2 = uImageInBuffer2[int(gl_GlobalInvocationID.x)];
uImageOutBuffer2[int(gl_GlobalInvocationID.x)] = b2.xy;
float4 f4 = uImageInF4[int2(gl_GlobalInvocationID.xy)];
uImageOutF4[int2(gl_GlobalInvocationID.xy)] = f4;
int4 i4 = uImageInI4[int2(gl_GlobalInvocationID.xy)];
uImageOutI4[int2(gl_GlobalInvocationID.xy)] = i4;
uint4 u4 = uImageInU4[int2(gl_GlobalInvocationID.xy)];
uImageOutU4[int2(gl_GlobalInvocationID.xy)] = u4;
float4 b4 = uImageInBuffer4[int(gl_GlobalInvocationID.x)];
uImageOutBuffer4[int(gl_GlobalInvocationID.x)] = b4;
uImageNoFmtF[int2(gl_GlobalInvocationID.xy)] = b2;
uImageNoFmtU[int2(gl_GlobalInvocationID.xy)] = u4;
uImageNoFmtI[int2(gl_GlobalInvocationID.xy)] = i4;
}

[numthreads(1, 1, 1)]
void main(SPIRV_Cross_Input stage_input)
{
gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID;
comp_main();
}
77 changes: 77 additions & 0 deletions shaders-hlsl/comp/image.nonwritable-uav-texture.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#version 450
layout(local_size_x = 1) in;

layout(r32f, binding = 0) uniform readonly image2D uImageInF;
layout(r32f, binding = 1) uniform writeonly image2D uImageOutF;
layout(r32i, binding = 2) uniform readonly iimage2D uImageInI;
layout(r32i, binding = 3) uniform writeonly iimage2D uImageOutI;
layout(r32ui, binding = 4) uniform readonly uimage2D uImageInU;
layout(r32ui, binding = 5) uniform writeonly uimage2D uImageOutU;
layout(r32f, binding = 6) uniform readonly imageBuffer uImageInBuffer;
layout(r32f, binding = 7) uniform writeonly imageBuffer uImageOutBuffer;

layout(rg32f, binding = 8) uniform readonly image2D uImageInF2;
layout(rg32f, binding = 9) uniform writeonly image2D uImageOutF2;
layout(rg32i, binding = 10) uniform readonly iimage2D uImageInI2;
layout(rg32i, binding = 11) uniform writeonly iimage2D uImageOutI2;
layout(rg32ui, binding = 12) uniform readonly uimage2D uImageInU2;
layout(rg32ui, binding = 13) uniform writeonly uimage2D uImageOutU2;
layout(rg32f, binding = 14) uniform readonly imageBuffer uImageInBuffer2;
layout(rg32f, binding = 15) uniform writeonly imageBuffer uImageOutBuffer2;

layout(rgba32f, binding = 16) uniform readonly image2D uImageInF4;
layout(rgba32f, binding = 17) uniform writeonly image2D uImageOutF4;
layout(rgba32i, binding = 18) uniform readonly iimage2D uImageInI4;
layout(rgba32i, binding = 19) uniform writeonly iimage2D uImageOutI4;
layout(rgba32ui, binding = 20) uniform readonly uimage2D uImageInU4;
layout(rgba32ui, binding = 21) uniform writeonly uimage2D uImageOutU4;
layout(rgba32f, binding = 22) uniform readonly imageBuffer uImageInBuffer4;
layout(rgba32f, binding = 23) uniform writeonly imageBuffer uImageOutBuffer4;

layout(binding = 24) uniform writeonly image2D uImageNoFmtF;
layout(binding = 25) uniform writeonly uimage2D uImageNoFmtU;
layout(binding = 26) uniform writeonly iimage2D uImageNoFmtI;

void main()
{
vec4 f = imageLoad(uImageInF, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutF, ivec2(gl_GlobalInvocationID.xy), f);

ivec4 i = imageLoad(uImageInI, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutI, ivec2(gl_GlobalInvocationID.xy), i);

uvec4 u = imageLoad(uImageInU, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutU, ivec2(gl_GlobalInvocationID.xy), u);

vec4 b = imageLoad(uImageInBuffer, int(gl_GlobalInvocationID.x));
imageStore(uImageOutBuffer, int(gl_GlobalInvocationID.x), b);

vec4 f2 = imageLoad(uImageInF2, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutF2, ivec2(gl_GlobalInvocationID.xy), f2);

ivec4 i2 = imageLoad(uImageInI2, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutI2, ivec2(gl_GlobalInvocationID.xy), i2);

uvec4 u2 = imageLoad(uImageInU2, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutU2, ivec2(gl_GlobalInvocationID.xy), u2);

vec4 b2 = imageLoad(uImageInBuffer2, int(gl_GlobalInvocationID.x));
imageStore(uImageOutBuffer2, int(gl_GlobalInvocationID.x), b2);

vec4 f4 = imageLoad(uImageInF4, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutF4, ivec2(gl_GlobalInvocationID.xy), f4);

ivec4 i4 = imageLoad(uImageInI4, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutI4, ivec2(gl_GlobalInvocationID.xy), i4);

uvec4 u4 = imageLoad(uImageInU4, ivec2(gl_GlobalInvocationID.xy));
imageStore(uImageOutU4, ivec2(gl_GlobalInvocationID.xy), u4);

vec4 b4 = imageLoad(uImageInBuffer4, int(gl_GlobalInvocationID.x));
imageStore(uImageOutBuffer4, int(gl_GlobalInvocationID.x), b4);

imageStore(uImageNoFmtF, ivec2(gl_GlobalInvocationID.xy), b2);
imageStore(uImageNoFmtU, ivec2(gl_GlobalInvocationID.xy), u4);
imageStore(uImageNoFmtI, ivec2(gl_GlobalInvocationID.xy), i4);
}

4 changes: 4 additions & 0 deletions spirv_cross_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV:
options->hlsl.force_storage_buffer_as_uav = value != 0;
break;

case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV:
options->hlsl.nonwritable_uav_texture_as_srv = value != 0;
break;
#endif

#if SPIRV_CROSS_C_API_MSL
Expand Down
4 changes: 3 additions & 1 deletion spirv_cross_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 28
#define SPVC_C_API_VERSION_MINOR 29
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0

Expand Down Expand Up @@ -580,6 +580,8 @@ typedef enum spvc_compiler_option

SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT,

SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV = 55 | SPVC_COMPILER_OPTION_HLSL_BIT,

SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;

Expand Down
37 changes: 32 additions & 5 deletions spirv_hlsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
bool typed_load = false;
uint32_t components = 4;

bool force_image_srv = hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(id, DecorationNonWritable);

switch (type.image.dim)
{
case Dim1D:
Expand Down Expand Up @@ -239,7 +241,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
if (interlocked_resources.count(id))
return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype),
">");
return join("RWBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">");

typed_load = !force_image_srv && type.image.sampled == 2;

const char *rw = force_image_srv ? "" : "RW";
return join(rw, "Buffer<",
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
join(type_to_glsl(imagetype), components),
">");
}
else
SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime.");
Expand All @@ -252,9 +261,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
}
const char *arrayed = type.image.arrayed ? "Array" : "";
const char *ms = type.image.ms ? "MS" : "";
const char *rw = typed_load ? "RW" : "";
const char *rw = typed_load && !force_image_srv ? "RW" : "";

if (force_image_srv)
typed_load = false;

if (typed_load && interlocked_resources.count(id))
rw = "RasterizerOrdered";

return join(rw, "Texture", dim, ms, arrayed, "<",
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
join(type_to_glsl(imagetype), components),
Expand Down Expand Up @@ -2971,8 +2985,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
case SPIRType::Image:
if (type.image.sampled == 2 && type.image.dim != DimSubpassData)
{
space = 'u'; // UAV
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
if (has_decoration(var.self, DecorationNonWritable) && hlsl_options.nonwritable_uav_texture_as_srv)
{
space = 't'; // SRV
resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
}
else
{
space = 'u'; // UAV
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
}
}
else
{
Expand Down Expand Up @@ -4813,7 +4835,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]");
// The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
// except that the underlying type changes how the data is interpreted.
if (var && !subpass_data)

bool force_srv =
hlsl_options.nonwritable_uav_texture_as_srv && var && has_decoration(var->self, DecorationNonWritable);
pure = force_srv;

if (var && !subpass_data && !force_srv)
imgexpr = remap_swizzle(get<SPIRType>(result_type),
image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
}
Expand Down
5 changes: 5 additions & 0 deletions spirv_hlsl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ class CompilerHLSL : public CompilerGLSL
// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
bool force_storage_buffer_as_uav = false;

// Forces any storage image type marked as NonWritable to be considered an SRV instead.
// For this to work with function call parameters, NonWritable must be considered to be part of the type system
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
bool nonwritable_uav_texture_as_srv = false;
};

explicit CompilerHLSL(std::vector<uint32_t> spirv_)
Expand Down
2 changes: 2 additions & 0 deletions test_shaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati
hlsl_args.append('--hlsl-force-storage-buffer-as-uav')
if '.zero-initialize.' in shader:
hlsl_args.append('--force-zero-initialized-variables')
if '.nonwritable-uav-texture.' in shader:
hlsl_args.append('--hlsl-nonwritable-uav-texture-as-srv')

subprocess.check_call(hlsl_args)

Expand Down

0 comments on commit 14f24d7

Please sign in to comment.