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) if (SPIRV_CROSS_SHARED)
set(spirv-cross-abi-major 0) 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-abi-patch 0)
set(SPIRV_CROSS_VERSION ${spirv-cross-abi-major}.${spirv-cross-abi-minor}.${spirv-cross-abi-patch}) 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) 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_pad_fragment_output = false;
bool msl_domain_lower_left = false; bool msl_domain_lower_left = false;
bool msl_argument_buffers = false; bool msl_argument_buffers = false;
bool glsl_emit_push_constant_as_ubo = false;
vector<uint32_t> msl_discrete_descriptor_sets; vector<uint32_t> msl_discrete_descriptor_sets;
vector<PLSArg> pls_in; vector<PLSArg> pls_in;
vector<PLSArg> pls_out; vector<PLSArg> pls_out;
@ -547,6 +548,7 @@ static void print_help()
"\t[--iterations iter]\n" "\t[--iterations iter]\n"
"\t[--cpp]\n" "\t[--cpp]\n"
"\t[--cpp-interface-name <name>]\n" "\t[--cpp-interface-name <name>]\n"
"\t[--glsl-emit-push-constant-as-ubo]\n"
"\t[--msl]\n" "\t[--msl]\n"
"\t[--msl-version <MMmmpp>]\n" "\t[--msl-version <MMmmpp>]\n"
"\t[--msl-capture-output]\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("--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("--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("--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("--msl", [&args](CLIParser &) { args.msl = true; });
cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; }); cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = 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.fixup_clipspace = args.fixup;
opts.vertex.flip_vert_y = args.yflip; opts.vertex.flip_vert_y = args.yflip;
opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance; 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); compiler->set_common_options(opts);
// Set HLSL specific options. // 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: case SPVC_BACKEND_MSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_MSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; 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; break;
case SPVC_BACKEND_HLSL: case SPVC_BACKEND_HLSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_HLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; 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; break;
case SPVC_BACKEND_GLSL: case SPVC_BACKEND_GLSL:
opt->backend_flags |= SPVC_COMPILER_OPTION_GLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; 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; break;
default: default:
@ -474,6 +479,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
options->msl.argument_buffers = value != 0; options->msl.argument_buffers = value != 0;
break; break;
case SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER:
options->glsl.emit_push_constant_as_uniform_buffer = value != 0;
break;
default: default:
options->context->report_error("Unknown option."); options->context->report_error("Unknown option.");
return SPVC_ERROR_INVALID_ARGUMENT; return SPVC_ERROR_INVALID_ARGUMENT;

View File

@ -33,7 +33,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */ /* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0 #define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */ /* 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. */ /* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0 #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_PLATFORM = 31 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS = 32 | 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_INT_MAX = 0x7fffffff
} spvc_compiler_option; } 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 push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
bool ssbo_block = var.storage == StorageClassStorageBuffer || bool ssbo_block = var.storage == StorageClassStorageBuffer ||
(var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock)); (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. // 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 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)) if (buffer_is_packing_standard(type, BufferPackingStd140))
attr.push_back("std140"); 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. // 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. // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
if (options.es && !options.vulkan_semantics) 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."); "not support GL_ARB_enhanced_layouts.");
if (!options.es && !options.vulkan_semantics && options.version < 440) if (!options.es && !options.vulkan_semantics && options.version < 440)
require_extension_internal("GL_ARB_enhanced_layouts"); 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); emit_buffer_block_flattened(var);
else if (options.vulkan_semantics) else if (options.vulkan_semantics)
emit_push_constant_block_vulkan(var); emit_push_constant_block_vulkan(var);
else if (options.emit_push_constant_as_uniform_buffer)
emit_buffer_block_native(var);
else else
emit_push_constant_block_glsl(var); emit_push_constant_block_glsl(var);
} }

View File

@ -96,6 +96,9 @@ public:
// If disabled on older targets, binding decorations will be stripped. // If disabled on older targets, binding decorations will be stripped.
bool enable_420pack_extension = true; 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 enum Precision
{ {
DontCare, DontCare,

View File

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