GLSL: Support emitting push constant block as a plain UBO.

This commit is contained in:
Hans-Kristian Arntzen 2019-03-19 10:58:37 +01:00
parent 66f32eca72
commit 0474848d4a
12 changed files with 103 additions and 6 deletions

View File

@ -195,7 +195,7 @@ endif()
if (SPIRV_CROSS_SHARED)
set(spirv-cross-abi-major 0)
set(spirv-cross-abi-minor 2)
set(spirv-cross-abi-minor 3)
set(spirv-cross-abi-patch 0)
set(SPIRV_CROSS_VERSION ${spirv-cross-abi-major}.${spirv-cross-abi-minor}.${spirv-cross-abi-patch})
set(SPIRV_CROSS_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib)

View File

@ -496,6 +496,7 @@ struct CLIArguments
bool msl_pad_fragment_output = false;
bool msl_domain_lower_left = false;
bool msl_argument_buffers = false;
bool glsl_emit_push_constant_as_ubo = false;
vector<uint32_t> msl_discrete_descriptor_sets;
vector<PLSArg> pls_in;
vector<PLSArg> pls_out;
@ -547,6 +548,7 @@ static void print_help()
"\t[--iterations iter]\n"
"\t[--cpp]\n"
"\t[--cpp-interface-name <name>]\n"
"\t[--glsl-emit-push-constant-as-ubo]\n"
"\t[--msl]\n"
"\t[--msl-version <MMmmpp>]\n"
"\t[--msl-capture-output]\n"
@ -714,6 +716,7 @@ static int main_inner(int argc, char *argv[])
cbs.add("--reflect", [&args](CLIParser &parser) { args.reflect = parser.next_value_string("json"); });
cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); });
cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
cbs.add("--msl", [&args](CLIParser &) { args.msl = true; });
cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
@ -986,6 +989,7 @@ static int main_inner(int argc, char *argv[])
opts.vertex.fixup_clipspace = args.fixup;
opts.vertex.flip_vert_y = args.yflip;
opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance;
opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
compiler->set_common_options(opts);
// Set HLSL specific options.

View File

@ -0,0 +1,14 @@
#version 450
layout(std140) uniform UBO
{
float ubo[4];
} _14;
layout(location = 0) out float FragColor;
void main()
{
FragColor = _14.ubo[1];
}

View File

@ -0,0 +1,14 @@
#version 450
layout(push_constant, std140) uniform UBO
{
float ubo[4];
} _14;
layout(location = 0) out float FragColor;
void main()
{
FragColor = _14.ubo[1];
}

View File

@ -0,0 +1,14 @@
#version 450
layout(std140) uniform UBO
{
float ubo[4];
} _14;
layout(location = 0) out float FragColor;
void main()
{
FragColor = _14.ubo[1];
}

View File

@ -0,0 +1,14 @@
#version 450
layout(push_constant, std140) uniform UBO
{
float ubo[4];
} _14;
layout(location = 0) out float FragColor;
void main()
{
FragColor = _14.ubo[1];
}

View File

@ -0,0 +1,13 @@
#version 450
layout(push_constant, std140) uniform UBO
{
float ubo[4];
};
layout(location = 0) out float FragColor;
void main()
{
FragColor = ubo[1];
}

View File

@ -316,14 +316,19 @@ spvc_result spvc_compiler_create_compiler_options(spvc_compiler compiler, spvc_c
{
case SPVC_BACKEND_MSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_MSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT;
opt->glsl = static_cast<CompilerMSL *>(compiler->compiler.get())->get_common_options();
opt->msl = static_cast<CompilerMSL *>(compiler->compiler.get())->get_msl_options();
break;
case SPVC_BACKEND_HLSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_HLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT;
opt->glsl = static_cast<CompilerHLSL *>(compiler->compiler.get())->get_common_options();
opt->hlsl = static_cast<CompilerHLSL *>(compiler->compiler.get())->get_hlsl_options();
break;
case SPVC_BACKEND_GLSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_GLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT;
opt->glsl = static_cast<CompilerGLSL *>(compiler->compiler.get())->get_common_options();
break;
default:
@ -474,6 +479,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
options->msl.argument_buffers = value != 0;
break;
case SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER:
options->glsl.emit_push_constant_as_uniform_buffer = value != 0;
break;
default:
options->context->report_error("Unknown option.");
return SPVC_ERROR_INVALID_ARGUMENT;

View File

@ -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 2
#define SPVC_C_API_VERSION_MINOR 3
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@ -420,6 +420,8 @@ typedef enum spvc_compiler_option
SPVC_COMPILER_OPTION_MSL_PLATFORM = 31 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS = 32 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER = 33 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;

View File

@ -1365,10 +1365,12 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
bool ssbo_block = var.storage == StorageClassStorageBuffer ||
(var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
// Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
// If SPIR-V does not comply with either layout, we cannot really work around it.
if (can_use_buffer_blocks && var.storage == StorageClassUniform && typeflags.get(DecorationBlock))
if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
{
if (buffer_is_packing_standard(type, BufferPackingStd140))
attr.push_back("std140");
@ -1379,7 +1381,7 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
// however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
// Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
if (options.es && !options.vulkan_semantics)
SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
SPIRV_CROSS_THROW("Uniform buffer block cannot be expressed as std140. ES-targets do "
"not support GL_ARB_enhanced_layouts.");
if (!options.es && !options.vulkan_semantics && options.version < 440)
require_extension_internal("GL_ARB_enhanced_layouts");
@ -1461,6 +1463,8 @@ void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
emit_buffer_block_flattened(var);
else if (options.vulkan_semantics)
emit_push_constant_block_vulkan(var);
else if (options.emit_push_constant_as_uniform_buffer)
emit_buffer_block_native(var);
else
emit_push_constant_block_glsl(var);
}

View File

@ -96,6 +96,9 @@ public:
// If disabled on older targets, binding decorations will be stripped.
bool enable_420pack_extension = true;
// In non-Vulkan GLSL, emit push constant blocks as UBOs rather than plain uniforms.
bool emit_push_constant_as_uniform_buffer = false;
enum Precision
{
DontCare,

View File

@ -302,7 +302,7 @@ def validate_shader(shader, vulkan, paths):
else:
subprocess.check_call([paths.glslang, shader])
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt, paths):
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt, push_ubo, paths):
spirv_path = create_temporary()
glsl_path = create_temporary(os.path.basename(shader))
@ -335,6 +335,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
extra_args += ['--separate-shader-objects']
if flatten_dim:
extra_args += ['--flatten-multidimensional-arrays']
if push_ubo:
extra_args += ['--glsl-emit-push-constant-as-ubo']
spirv_cross_path = './spirv-cross'
@ -496,6 +498,9 @@ def shader_is_flatten_dimensions(shader):
def shader_is_noopt(shader):
return '.noopt.' in shader
def shader_is_push_ubo(shader):
return '.push-ubo.' in shader
def test_shader(stats, shader, update, keep, opt, paths):
joined_path = os.path.join(shader[0], shader[1])
vulkan = shader_is_vulkan(shader[1])
@ -508,9 +513,10 @@ def test_shader(stats, shader, update, keep, opt, paths):
sso = shader_is_sso(shader[1])
flatten_dim = shader_is_flatten_dimensions(shader[1])
noopt = shader_is_noopt(shader[1])
push_ubo = shader_is_push_ubo(shader[1])
print('Testing shader:', joined_path)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt), paths)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt), push_ubo, paths)
# Only test GLSL stats if we have a shader following GL semantics.
if stats and (not vulkan) and (not is_spirv) and (not desktop):