Add separate shader object support.
Allow redeclaring gl_PerVertex for stage compatibility.
This commit is contained in:
parent
c3e6fdc579
commit
36650c890c
4
main.cpp
4
main.cpp
@ -432,6 +432,7 @@ struct CLIArguments
|
||||
bool force_temporary = false;
|
||||
bool flatten_ubo = false;
|
||||
bool fixup = false;
|
||||
bool sso = false;
|
||||
vector<PLSArg> pls_in;
|
||||
vector<PLSArg> pls_out;
|
||||
vector<Remap> remaps;
|
||||
@ -458,6 +459,7 @@ static void print_help()
|
||||
"[--cpp] [--cpp-interface-name <name>] "
|
||||
"[--msl] [--msl-no-pack-ubos] "
|
||||
"[--hlsl] [--shader-model] [--hlsl-enable-compat] "
|
||||
"[--separate-shader-objects]"
|
||||
"[--pls-in format input-name] [--pls-out format output-name] [--remap source_name target_name "
|
||||
"components] [--extension ext] [--entry name] [--remove-unused-variables] "
|
||||
"[--remap-variable-type <variable_name> <new_variable_type>]\n");
|
||||
@ -585,6 +587,7 @@ int main(int argc, char *argv[])
|
||||
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
|
||||
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
||||
cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
|
||||
cbs.add("--separate-shader-objects", [&args](CLIParser &) { args.sso = true; });
|
||||
cbs.add("--remap", [&args](CLIParser &parser) {
|
||||
string src = parser.next_string();
|
||||
string dst = parser.next_string();
|
||||
@ -689,6 +692,7 @@ int main(int argc, char *argv[])
|
||||
if (args.set_es)
|
||||
opts.es = args.es;
|
||||
opts.force_temporary = args.force_temporary;
|
||||
opts.separate_shader_objects = args.sso;
|
||||
opts.vulkan_semantics = args.vulkan_semantics;
|
||||
opts.vertex.fixup_clipspace = args.fixup;
|
||||
opts.cfg_analysis = args.cfg_analysis;
|
||||
|
@ -300,6 +300,9 @@ void CompilerGLSL::find_static_extensions()
|
||||
|
||||
if (!pls_inputs.empty() || !pls_outputs.empty())
|
||||
require_extension("GL_EXT_shader_pixel_local_storage");
|
||||
|
||||
if (options.separate_shader_objects && !options.es && options.version < 410)
|
||||
require_extension("GL_ARB_separate_shader_objects");
|
||||
}
|
||||
|
||||
string CompilerGLSL::compile()
|
||||
@ -1495,6 +1498,64 @@ void CompilerGLSL::fixup_image_load_store_access()
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
|
||||
{
|
||||
bool emitted_block = false;
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() != TypeVariable)
|
||||
continue;
|
||||
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
bool block = has_decoration(type.self, DecorationBlock);
|
||||
uint64_t builtins = 0;
|
||||
|
||||
if (var.storage == storage && block && is_builtin_variable(var))
|
||||
{
|
||||
for (auto &m : meta[type.self].members)
|
||||
if (m.builtin)
|
||||
builtins |= 1ull << m.builtin_type;
|
||||
}
|
||||
|
||||
if (!builtins)
|
||||
continue;
|
||||
|
||||
if (emitted_block)
|
||||
SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
|
||||
|
||||
if (storage == StorageClassOutput)
|
||||
statement("out gl_PerVertex");
|
||||
else
|
||||
statement("in gl_PerVertex");
|
||||
|
||||
begin_scope();
|
||||
if (builtins & (1ull << BuiltInPosition))
|
||||
statement("vec4 gl_Position;");
|
||||
if (builtins & (1ull << BuiltInPointSize))
|
||||
statement("float gl_PointSize;");
|
||||
if (builtins & (1ull << BuiltInClipDistance))
|
||||
statement("float gl_ClipDistance[];"); // TODO: Do we need a fixed array size here?
|
||||
if (builtins & (1ull << BuiltInCullDistance))
|
||||
statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here?
|
||||
|
||||
bool builtin_array = !type.array.empty();
|
||||
bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl;
|
||||
if (builtin_array)
|
||||
{
|
||||
if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
|
||||
end_scope_decl(join(to_name(var.self), "[", get_entry_point().output_vertices, "]"));
|
||||
else
|
||||
end_scope_decl(join(to_name(var.self), tessellation ? "[gl_MaxPatchVertices]" : "[]"));
|
||||
}
|
||||
else
|
||||
end_scope_decl();
|
||||
statement("");
|
||||
|
||||
emitted_block = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_resources()
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
@ -1510,6 +1571,27 @@ void CompilerGLSL::emit_resources()
|
||||
if (!pls_inputs.empty() || !pls_outputs.empty())
|
||||
emit_pls();
|
||||
|
||||
// Emit custom gl_PerVertex for SSO compatibility.
|
||||
if (options.separate_shader_objects && !options.es)
|
||||
{
|
||||
switch (execution.model)
|
||||
{
|
||||
case ExecutionModelGeometry:
|
||||
case ExecutionModelTessellationControl:
|
||||
case ExecutionModelTessellationEvaluation:
|
||||
emit_declared_builtin_block(StorageClassInput, execution.model);
|
||||
emit_declared_builtin_block(StorageClassOutput, execution.model);
|
||||
break;
|
||||
|
||||
case ExecutionModelVertex:
|
||||
emit_declared_builtin_block(StorageClassOutput, execution.model);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool emitted = false;
|
||||
|
||||
// If emitted Vulkan GLSL,
|
||||
|
@ -67,6 +67,12 @@ public:
|
||||
// Mostly useful for debugging SPIR-V files.
|
||||
bool vulkan_semantics = false;
|
||||
|
||||
// If true, gl_PerVertex is explicitly redeclared in vertex, geometry and tessellation shaders.
|
||||
// The members of gl_PerVertex is determined by which built-ins are declared by the shader.
|
||||
// This option is ignored in ES versions, as redeclaration in ES is not required, and it depends on a different extension
|
||||
// (EXT_shader_io_blocks) which makes things a bit more fuzzy.
|
||||
bool separate_shader_objects = false;
|
||||
|
||||
enum Precision
|
||||
{
|
||||
DontCare,
|
||||
@ -284,6 +290,7 @@ protected:
|
||||
void emit_buffer_block_native(const SPIRVariable &var);
|
||||
void emit_buffer_block_legacy(const SPIRVariable &var);
|
||||
void emit_buffer_block_flattened(const SPIRVariable &type);
|
||||
void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
|
||||
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);
|
||||
|
@ -120,7 +120,7 @@ def validate_shader(shader, vulkan):
|
||||
else:
|
||||
subprocess.check_call(['glslangValidator', shader])
|
||||
|
||||
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo):
|
||||
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso):
|
||||
spirv_f, spirv_path = tempfile.mkstemp()
|
||||
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
||||
os.close(spirv_f)
|
||||
@ -145,6 +145,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
|
||||
extra_args += ['--version', '100', '--es']
|
||||
if flatten_ubo:
|
||||
extra_args += ['--flatten-ubo']
|
||||
if sso:
|
||||
extra_args += ['--separate-shader-objects']
|
||||
|
||||
spirv_cross_path = './spirv-cross'
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args)
|
||||
@ -238,6 +240,9 @@ def shader_is_legacy(shader):
|
||||
def shader_is_flatten_ubo(shader):
|
||||
return '.flatten.' in shader
|
||||
|
||||
def shader_is_sso(shader):
|
||||
return '.sso.' in shader
|
||||
|
||||
def test_shader(stats, shader, update, keep):
|
||||
joined_path = os.path.join(shader[0], shader[1])
|
||||
vulkan = shader_is_vulkan(shader[1])
|
||||
@ -247,9 +252,10 @@ def test_shader(stats, shader, update, keep):
|
||||
invalid_spirv = shader_is_invalid_spirv(shader[1])
|
||||
is_legacy = shader_is_legacy(shader[1])
|
||||
flatten_ubo = shader_is_flatten_ubo(shader[1])
|
||||
sso = shader_is_sso(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)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso)
|
||||
|
||||
# Only test GLSL stats if we have a shader following GL semantics.
|
||||
if stats and (not vulkan) and (not is_spirv) and (not desktop):
|
||||
|
Loading…
Reference in New Issue
Block a user