Add support for Vulkan GLSL as output target.
Mostly useful for debugging SPIR-V where it is useful to see the "original" Vulkan GLSL constructs which created the SPIR-V.
This commit is contained in:
parent
5af1a51727
commit
dbee4e4346
5
main.cpp
5
main.cpp
@ -268,11 +268,12 @@ struct CLIArguments
|
||||
uint32_t iterations = 1;
|
||||
bool cpp = false;
|
||||
bool metal = false;
|
||||
bool vulkan_semantics = false;
|
||||
};
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
fprintf(stderr, "Usage: spirv-cross [--output <output path>] [SPIR-V file] [--es] [--no-es] [--version <GLSL version>] [--dump-resources] [--help] [--force-temporary] [--cpp] [--metal] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in format input-name] [--pls-out format output-name]\n");
|
||||
fprintf(stderr, "Usage: spirv-cross [--output <output path>] [SPIR-V file] [--es] [--no-es] [--version <GLSL version>] [--dump-resources] [--help] [--force-temporary] [--cpp] [--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in format input-name] [--pls-out format output-name]\n");
|
||||
}
|
||||
|
||||
static vector<PlsRemap> remap_pls(const vector<PLSArg> &pls_variables, const vector<Resource> &resources, const vector<Resource> *secondary_resources)
|
||||
@ -347,6 +348,7 @@ int main(int argc, char *argv[])
|
||||
cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); });
|
||||
cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; });
|
||||
cbs.add("--metal", [&args](CLIParser &) { args.metal = true; });
|
||||
cbs.add("--vulkan-semantics",[&args](CLIParser &) { args.vulkan_semantics = true; });
|
||||
|
||||
cbs.add("--pls-in", [&args](CLIParser &parser) {
|
||||
auto fmt = pls_format(parser.next_string());
|
||||
@ -401,6 +403,7 @@ int main(int argc, char *argv[])
|
||||
if (args.set_es)
|
||||
opts.es = args.es;
|
||||
opts.force_temporary = args.force_temporary;
|
||||
opts.vulkan_semantics = args.vulkan_semantics;
|
||||
opts.vertex.fixup_clipspace = args.fixup;
|
||||
compiler->set_options(opts);
|
||||
|
||||
|
14
reference/shaders-vulkan/frag/input-attachment.frag.vk
Normal file
14
reference/shaders-vulkan/frag/input-attachment.frag.vk
Normal file
@ -0,0 +1,14 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(input_attachment_index = 0, binding = 0) uniform mediump subpassInput uSubpass0;
|
||||
layout(input_attachment_index = 1, binding = 1) uniform mediump subpassInput uSubpass1;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = (subpassLoad(uSubpass0) + subpassLoad(uSubpass1));
|
||||
}
|
||||
|
20
reference/shaders-vulkan/frag/push-constant.frag
Normal file
20
reference/shaders-vulkan/frag/push-constant.frag
Normal file
@ -0,0 +1,20 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
struct PushConstants
|
||||
{
|
||||
vec4 value0;
|
||||
vec4 value1;
|
||||
};
|
||||
|
||||
uniform PushConstants push;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(location = 0) in vec4 vColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = ((vColor + push.value0) + push.value1);
|
||||
}
|
||||
|
18
reference/shaders-vulkan/frag/push-constant.frag.vk
Normal file
18
reference/shaders-vulkan/frag/push-constant.frag.vk
Normal file
@ -0,0 +1,18 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(push_constant, std430) uniform PushConstants
|
||||
{
|
||||
vec4 value0;
|
||||
vec4 value1;
|
||||
} push;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(location = 0) in vec4 vColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = ((vColor + push.value0) + push.value1);
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(binding = 1) uniform mediump texture2D uTexture;
|
||||
layout(binding = 0) uniform mediump sampler uSampler;
|
||||
layout(binding = 4) uniform mediump texture2DArray uTextureArray;
|
||||
layout(binding = 3) uniform mediump textureCube uTextureCube;
|
||||
layout(binding = 2) uniform mediump texture3D uTexture3D;
|
||||
|
||||
layout(location = 0) in vec2 vTex;
|
||||
layout(location = 1) in vec3 vTex3;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 sample_func(mediump sampler samp, vec2 uv)
|
||||
{
|
||||
return texture(sampler2D(uTexture, samp), uv);
|
||||
}
|
||||
|
||||
vec4 sample_func_dual(mediump sampler samp, mediump texture2D tex, vec2 uv)
|
||||
{
|
||||
return texture(sampler2D(tex, samp), uv);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 off = (vec2(1.0) / vec2(textureSize(uTexture, 0)));
|
||||
vec2 off2 = (vec2(1.0) / vec2(textureSize(sampler2D(uTexture, uSampler), 1)));
|
||||
highp vec2 param = ((vTex + off) + off2);
|
||||
vec4 c0 = sample_func(uSampler, param);
|
||||
highp vec2 param_1 = ((vTex + off) + off2);
|
||||
vec4 c1 = sample_func_dual(uSampler, uTexture, param_1);
|
||||
vec4 c2 = texture(sampler2DArray(uTextureArray, uSampler), vTex3);
|
||||
vec4 c3 = texture(samplerCube(uTextureCube, uSampler), vTex3);
|
||||
vec4 c4 = texture(sampler3D(uTexture3D, uSampler), vTex3);
|
||||
FragColor = ((((c0 + c1) + c2) + c3) + c4);
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(binding = 1) uniform mediump texture2D uTexture;
|
||||
layout(binding = 0) uniform mediump sampler uSampler;
|
||||
layout(binding = 4) uniform mediump texture2DArray uTextureArray;
|
||||
layout(binding = 3) uniform mediump textureCube uTextureCube;
|
||||
layout(binding = 2) uniform mediump texture3D uTexture3D;
|
||||
|
||||
layout(location = 0) in vec2 vTex;
|
||||
layout(location = 1) in vec3 vTex3;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 sample_func(mediump sampler samp, vec2 uv)
|
||||
{
|
||||
return texture(sampler2D(uTexture, samp), uv);
|
||||
}
|
||||
|
||||
vec4 sample_func_dual(mediump sampler samp, mediump texture2D tex, vec2 uv)
|
||||
{
|
||||
return texture(sampler2D(tex, samp), uv);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 off = (vec2(1.0) / vec2(textureSize(uTexture, 0)));
|
||||
vec2 off2 = (vec2(1.0) / vec2(textureSize(sampler2D(uTexture, uSampler), 1)));
|
||||
highp vec2 param = ((vTex + off) + off2);
|
||||
vec4 c0 = sample_func(uSampler, param);
|
||||
highp vec2 param_1 = ((vTex + off) + off2);
|
||||
vec4 c1 = sample_func_dual(uSampler, uTexture, param_1);
|
||||
vec4 c2 = texture(sampler2DArray(uTextureArray, uSampler), vTex3);
|
||||
vec4 c3 = texture(samplerCube(uTextureCube, uSampler), vTex3);
|
||||
vec4 c4 = texture(sampler3D(uTexture3D, uSampler), vTex3);
|
||||
FragColor = ((((c0 + c1) + c2) + c3) + c4);
|
||||
}
|
||||
|
9
reference/shaders-vulkan/vert/vulkan-vertex.vert
Normal file
9
reference/shaders-vulkan/vert/vulkan-vertex.vert
Normal file
@ -0,0 +1,9 @@
|
||||
#version 310 es
|
||||
|
||||
uniform int SPIRV_Cross_BaseInstance;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = (vec4(1.0, 2.0, 3.0, 4.0) * float((gl_VertexID + (gl_InstanceID + SPIRV_Cross_BaseInstance))));
|
||||
}
|
||||
|
7
reference/shaders-vulkan/vert/vulkan-vertex.vert.vk
Normal file
7
reference/shaders-vulkan/vert/vulkan-vertex.vert.vk
Normal file
@ -0,0 +1,7 @@
|
||||
#version 310 es
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = (vec4(1.0, 2.0, 3.0, 4.0) * float((gl_VertexIndex + gl_InstanceIndex)));
|
||||
}
|
||||
|
16
shaders-vulkan/frag/push-constant.frag
Normal file
16
shaders-vulkan/frag/push-constant.frag
Normal file
@ -0,0 +1,16 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(push_constant, std430) uniform PushConstants
|
||||
{
|
||||
vec4 value0;
|
||||
vec4 value1;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec4 vColor;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vColor + push.value0 + push.value1;
|
||||
}
|
6
shaders-vulkan/vert/vulkan-vertex.vert
Normal file
6
shaders-vulkan/vert/vulkan-vertex.vert
Normal file
@ -0,0 +1,6 @@
|
||||
#version 310 es
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = float(gl_VertexIndex + gl_InstanceIndex) * vec4(1.0, 2.0, 3.0, 4.0);
|
||||
}
|
@ -673,10 +673,20 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
||||
auto flags = dec.decoration_flags;
|
||||
auto typeflags = meta[type.self].decoration.decoration_flags;
|
||||
|
||||
if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
|
||||
attr.push_back("push_constant");
|
||||
|
||||
if (flags & (1ull << DecorationRowMajor))
|
||||
attr.push_back("row_major");
|
||||
if (flags & (1ull << DecorationColMajor))
|
||||
attr.push_back("column_major");
|
||||
|
||||
if (options.vulkan_semantics)
|
||||
{
|
||||
if (flags & (1ull << DecorationInputAttachmentIndex))
|
||||
attr.push_back(join("input_attachment_index = ", dec.input_attachment));
|
||||
}
|
||||
|
||||
if (flags & (1ull << DecorationLocation))
|
||||
attr.push_back(join("location = ", dec.location));
|
||||
if ((flags & (1ull << DecorationDescriptorSet)) && dec.set != 0) // set = 0 is the default.
|
||||
@ -692,8 +702,9 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
||||
// If SPIR-V does not comply with either layout, we cannot really work around it.
|
||||
if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
|
||||
attr.push_back("std140");
|
||||
|
||||
if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)))
|
||||
else if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)))
|
||||
attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
|
||||
else if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
|
||||
attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
|
||||
|
||||
// For images, the type itself adds a layout qualifer.
|
||||
@ -714,6 +725,19 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
|
||||
{
|
||||
if (options.vulkan_semantics)
|
||||
emit_push_constant_block_vulkan(var);
|
||||
else
|
||||
emit_push_constant_block_glsl(var);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
|
||||
{
|
||||
emit_buffer_block(var);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
|
||||
{
|
||||
// OpenGL has no concept of push constant blocks, implement it as a uniform struct.
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
@ -988,7 +1012,7 @@ void CompilerGLSL::emit_resources()
|
||||
{
|
||||
// For gl_InstanceIndex emulation on GLES, the API user needs to
|
||||
// supply this uniform.
|
||||
if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex)
|
||||
if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
|
||||
{
|
||||
statement("uniform int SPIRV_Cross_BaseInstance;");
|
||||
emitted = true;
|
||||
@ -1942,13 +1966,25 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
|
||||
case BuiltInPointSize:
|
||||
return "gl_PointSize";
|
||||
case BuiltInVertexId:
|
||||
if (options.vulkan_semantics)
|
||||
throw CompilerError(
|
||||
"Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
|
||||
return "gl_VertexID";
|
||||
case BuiltInInstanceId:
|
||||
if (options.vulkan_semantics)
|
||||
throw CompilerError(
|
||||
"Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
|
||||
return "gl_InstanceID";
|
||||
case BuiltInVertexIndex:
|
||||
return "gl_VertexID"; // gl_VertexID already has the base offset applied.
|
||||
if (options.vulkan_semantics)
|
||||
return "gl_VertexIndex";
|
||||
else
|
||||
return "gl_VertexID"; // gl_VertexID already has the base offset applied.
|
||||
case BuiltInInstanceIndex:
|
||||
return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
|
||||
if (options.vulkan_semantics)
|
||||
return "gl_InstanceIndex";
|
||||
else
|
||||
return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
|
||||
case BuiltInPrimitiveId:
|
||||
return "gl_PrimitiveID";
|
||||
case BuiltInInvocationId:
|
||||
@ -3191,9 +3227,16 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
}
|
||||
else if (type.image.dim == DimSubpassData)
|
||||
{
|
||||
// Implement subpass loads via texture barrier style sampling.
|
||||
// Fairly ugly, but should essentially work as a fallback for desktop.
|
||||
imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
|
||||
if (options.vulkan_semantics)
|
||||
{
|
||||
// With Vulkan semantics, use the proper Vulkan GLSL construct.
|
||||
imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Implement subpass loads via texture barrier style sampling.
|
||||
imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
|
||||
}
|
||||
pure = true;
|
||||
}
|
||||
else
|
||||
@ -3504,6 +3547,9 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
|
||||
return res + "subpassInput";
|
||||
|
||||
// If we're emulating subpassInput with samplers, force sampler2D
|
||||
// so we don't have to specify format.
|
||||
if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
|
||||
|
@ -60,6 +60,10 @@ public:
|
||||
bool es = false;
|
||||
bool force_temporary = false;
|
||||
|
||||
// If true, Vulkan GLSL features are used instead of GL-compatible features.
|
||||
// Mostly useful for debugging SPIR-V files.
|
||||
bool vulkan_semantics = false;
|
||||
|
||||
enum Precision
|
||||
{
|
||||
DontCare,
|
||||
@ -208,6 +212,8 @@ protected:
|
||||
void emit_resources();
|
||||
void emit_buffer_block(const SPIRVariable &type);
|
||||
void emit_push_constant_block(const SPIRVariable &var);
|
||||
void emit_push_constant_block_vulkan(const SPIRVariable &var);
|
||||
void emit_push_constant_block_glsl(const SPIRVariable &var);
|
||||
void emit_interface_block(const SPIRVariable &type);
|
||||
void emit_block_chain(SPIRBlock &block);
|
||||
std::string emit_continue_block(uint32_t continue_block);
|
||||
|
@ -72,10 +72,22 @@ def cross_compile(shader, vulkan):
|
||||
os.close(spirv_f)
|
||||
os.close(glsl_f)
|
||||
|
||||
if vulkan:
|
||||
vulkan_glsl_f, vulkan_glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
||||
os.close(vulkan_glsl_f)
|
||||
|
||||
subprocess.check_call(['glslangValidator', '-V' if vulkan else '-G', '-o', spirv_path, shader])
|
||||
|
||||
subprocess.check_call(['./spirv-cross', '--output', glsl_path, spirv_path])
|
||||
validate_shader(glsl_path, vulkan)
|
||||
return (spirv_path, glsl_path)
|
||||
|
||||
if not ('nocompat' in glsl_path):
|
||||
validate_shader(glsl_path, False)
|
||||
|
||||
if vulkan:
|
||||
subprocess.check_call(['./spirv-cross', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path])
|
||||
validate_shader(vulkan_glsl_path, vulkan)
|
||||
|
||||
return (spirv_path, glsl_path, vulkan_glsl_path if vulkan else None)
|
||||
|
||||
def md5_for_file(path):
|
||||
md5 = hashlib.md5()
|
||||
@ -115,12 +127,14 @@ def regression_check(shader, glsl, update, keep):
|
||||
|
||||
def test_shader(stats, shader, update, keep, vulkan):
|
||||
print('Testing shader:', shader)
|
||||
spirv, glsl = cross_compile(shader, vulkan)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(shader, vulkan)
|
||||
|
||||
if stats:
|
||||
cross_stats = get_shader_stats(glsl)
|
||||
|
||||
regression_check(shader, glsl, update, keep)
|
||||
if vulkan_glsl:
|
||||
regression_check(shader + '.vk', vulkan_glsl, update, keep)
|
||||
os.remove(spirv)
|
||||
|
||||
if stats:
|
||||
|
Loading…
Reference in New Issue
Block a user