Overhaul clip/cull distance support in GLSL.

This commit is contained in:
Hans-Kristian Arntzen 2018-02-22 14:36:50 +01:00
parent 11bbccb54a
commit fb3f92a3ff
12 changed files with 165 additions and 18 deletions

View File

@ -0,0 +1,12 @@
#version 450
in float gl_ClipDistance[4];
in float gl_CullDistance[3];
layout(location = 0) out float FragColor;
void main()
{
FragColor = gl_ClipDistance[0] + gl_CullDistance[0];
}

View File

@ -0,0 +1,20 @@
#version 450
out gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[4];
float gl_CullDistance[3];
};
void main()
{
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -1,11 +1,15 @@
#version 450
out float gl_ClipDistance[4];
out float gl_CullDistance[3];
void main()
{
gl_Position = vec4(10.0);
gl_ClipDistance[0] = 1.0;
gl_ClipDistance[1] = 4.0;
gl_CullDistance[0] = 4.0;
gl_CullDistance[1] = 9.0;
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -0,0 +1,12 @@
#version 450
in float gl_ClipDistance[4];
in float gl_CullDistance[3];
layout(location = 0) out float FragColor;
void main()
{
FragColor = gl_ClipDistance[0] + gl_CullDistance[0];
}

View File

@ -0,0 +1,20 @@
#version 450
out gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[4];
float gl_CullDistance[3];
};
void main()
{
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -1,11 +1,15 @@
#version 450
out float gl_ClipDistance[4];
out float gl_CullDistance[3];
void main()
{
gl_Position = vec4(10.0);
gl_ClipDistance[0] = 1.0;
gl_ClipDistance[1] = 4.0;
gl_CullDistance[0] = 4.0;
gl_CullDistance[1] = 9.0;
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -0,0 +1,12 @@
#version 450
in float gl_ClipDistance[4];
in float gl_CullDistance[3];
layout(location = 0) out float FragColor;
void main()
{
FragColor = gl_ClipDistance[0] + gl_CullDistance[0];
}

View File

@ -0,0 +1,13 @@
#version 450
out float gl_ClipDistance[4];
out float gl_CullDistance[3];
void main()
{
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -1,10 +1,13 @@
#version 450
out float gl_ClipDistance[4];
out float gl_CullDistance[3];
void main()
{
gl_Position = vec4(10.0);
gl_ClipDistance[0] = 1.0;
gl_ClipDistance[1] = 4.0;
gl_CullDistance[0] = 4.0;
gl_CullDistance[1] = 9.0;
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_ClipDistance[2] = 0.0;
gl_ClipDistance[3] = 0.0;
gl_CullDistance[1] = 4.0;
}

View File

@ -3749,6 +3749,30 @@ bool Compiler::get_common_basic_type(const SPIRType &type, SPIRType::BaseType &b
}
}
void Compiler::ActiveBuiltinHandler::handle_builtin(const SPIRType &type, BuiltIn builtin)
{
// If used, we will need to explicitly declare a new array size for these builtins.
if (builtin == BuiltInClipDistance)
{
if (!type.array_size_literal[0])
SPIRV_CROSS_THROW("Array size for ClipDistance must be a literal.");
uint32_t array_size = type.array[0];
if (array_size == 0)
SPIRV_CROSS_THROW("Array size for ClipDistance must not be unsized.");
compiler.clip_distance_count = array_size;
}
else if (builtin == BuiltInCullDistance)
{
if (!type.array_size_literal[0])
SPIRV_CROSS_THROW("Array size for CullDistance must be a literal.");
uint32_t array_size = type.array[0];
if (array_size == 0)
SPIRV_CROSS_THROW("Array size for CullDistance must not be unsized.");
compiler.cull_distance_count = array_size;
}
}
bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
{
const auto add_if_builtin = [&](uint32_t id) {
@ -3761,6 +3785,7 @@ bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args
auto &flags =
type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
flags |= 1ull << compiler.meta[id].decoration.builtin_type;
handle_builtin(type, compiler.meta[id].decoration.builtin_type);
}
};
@ -3846,7 +3871,10 @@ bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args
{
auto &decorations = compiler.meta[type->self].members[index];
if (decorations.builtin)
{
flags |= 1ull << decorations.builtin_type;
handle_builtin(compiler.get<SPIRType>(type->member_types[index]), decorations.builtin_type);
}
}
type = &compiler.get<SPIRType>(type->member_types[index]);
@ -3871,6 +3899,8 @@ void Compiler::update_active_builtins()
{
active_input_builtins = 0;
active_output_builtins = 0;
cull_distance_count = 0;
clip_distance_count = 0;
ActiveBuiltinHandler handler(*this);
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
}

View File

@ -715,6 +715,8 @@ protected:
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
void handle_builtin(const SPIRType &type, spv::BuiltIn builtin);
};
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
@ -735,6 +737,9 @@ protected:
uint64_t active_input_builtins = 0;
uint64_t active_output_builtins = 0;
uint32_t clip_distance_count = 0;
uint32_t cull_distance_count = 0;
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
void update_active_builtins();
bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage);

View File

@ -1871,9 +1871,9 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
if (emitted_builtins & (1ull << BuiltInPointSize))
statement("float gl_PointSize;");
if (emitted_builtins & (1ull << BuiltInClipDistance))
statement("float gl_ClipDistance[];"); // TODO: Do we need a fixed array size here?
statement("float gl_ClipDistance[", clip_distance_count, "];");
if (emitted_builtins & (1ull << BuiltInCullDistance))
statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here?
statement("float gl_CullDistance[", cull_distance_count, "];");
bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl;
if (builtin_array)
@ -1927,7 +1927,7 @@ void CompilerGLSL::emit_resources()
emit_pls();
// Emit custom gl_PerVertex for SSO compatibility.
if (options.separate_shader_objects && !options.es)
if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
{
switch (execution.model)
{
@ -1946,6 +1946,18 @@ void CompilerGLSL::emit_resources()
break;
}
}
else
{
// Need to redeclare clip/cull distance with explicit size to use them.
// SPIR-V mandates these builtins have a size declared.
const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
if (clip_distance_count != 0)
statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
if (cull_distance_count != 0)
statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
if (clip_distance_count != 0 || cull_distance_count != 0)
statement("");
}
bool emitted = false;