Merge pull request #465 from KhronosGroup/fix-445

Overhaul Clip/CullDistance in GLSL and HLSL.
This commit is contained in:
Hans-Kristian Arntzen 2018-02-22 18:02:03 +01:00 committed by GitHub
commit 3f64f56037
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 418 additions and 22 deletions

View File

@ -0,0 +1,30 @@
static float gl_ClipDistance[2];
static float gl_CullDistance[1];
static float FragColor;
struct SPIRV_Cross_Input
{
float2 gl_ClipDistance0 : SV_ClipDistance0;
float gl_CullDistance0 : SV_CullDistance0;
};
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = (gl_ClipDistance[0] + gl_CullDistance[0]) + gl_ClipDistance[1];
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_ClipDistance[0] = stage_input.gl_ClipDistance0.x;
gl_ClipDistance[1] = stage_input.gl_ClipDistance0.y;
gl_CullDistance[0] = stage_input.gl_CullDistance0.x;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,28 @@
static float4 gl_Position;
static float gl_ClipDistance[2];
static float gl_CullDistance[1];
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
float2 gl_ClipDistance0 : SV_ClipDistance0;
float gl_CullDistance0 : SV_CullDistance0;
};
void vert_main()
{
gl_Position = 1.0f.xxxx;
gl_ClipDistance[0] = 0.0f;
gl_ClipDistance[1] = 0.0f;
gl_CullDistance[0] = 4.0f;
}
SPIRV_Cross_Output main()
{
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.gl_ClipDistance0.x = gl_ClipDistance[0];
stage_output.gl_ClipDistance0.y = gl_ClipDistance[1];
stage_output.gl_CullDistance0.x = gl_CullDistance[0];
return stage_output;
}

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,30 @@
static float gl_ClipDistance[2];
static float gl_CullDistance[1];
static float FragColor;
struct SPIRV_Cross_Input
{
float2 gl_ClipDistance0 : SV_ClipDistance0;
float gl_CullDistance0 : SV_CullDistance0;
};
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = (gl_ClipDistance[0] + gl_CullDistance[0]) + gl_ClipDistance[1];
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_ClipDistance[0] = stage_input.gl_ClipDistance0.x;
gl_ClipDistance[1] = stage_input.gl_ClipDistance0.y;
gl_CullDistance[0] = stage_input.gl_CullDistance0.x;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,28 @@
static float4 gl_Position;
static float gl_ClipDistance[2];
static float gl_CullDistance[1];
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
float2 gl_ClipDistance0 : SV_ClipDistance0;
float gl_CullDistance0 : SV_CullDistance0;
};
void vert_main()
{
gl_Position = 1.0f.xxxx;
gl_ClipDistance[0] = 0.0f;
gl_ClipDistance[1] = 0.0f;
gl_CullDistance[0] = 4.0f;
}
SPIRV_Cross_Output main()
{
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
stage_output.gl_ClipDistance0.x = gl_ClipDistance[0];
stage_output.gl_ClipDistance0.y = gl_ClipDistance[1];
stage_output.gl_CullDistance0.x = gl_CullDistance[0];
return stage_output;
}

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[2];
in float gl_CullDistance[1];
layout(location = 0) out float FragColor;
void main()
{
FragColor = gl_ClipDistance[0] + gl_CullDistance[0] + gl_ClipDistance[1];
}

View File

@ -0,0 +1,11 @@
#version 450
out float gl_ClipDistance[2];
out float gl_CullDistance[1];
void main()
{
gl_Position = vec4(1.0);
gl_ClipDistance[0] = 0.0;
gl_ClipDistance[1] = 0.0;
gl_CullDistance[0] = 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;

View File

@ -509,6 +509,40 @@ void CompilerHLSL::emit_builtin_outputs_in_struct()
semantic = legacy ? "DEPTH" : "SV_Depth";
break;
case BuiltInClipDistance:
// HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors.
for (uint32_t clip = 0; clip < clip_distance_count; clip += 4)
{
uint32_t to_declare = clip_distance_count - clip;
if (to_declare > 4)
to_declare = 4;
uint32_t semantic_index = clip / 4;
static const char *types[] = { "float", "float2", "float3", "float4" };
statement(types[to_declare - 1], " ",
builtin_to_glsl(builtin, StorageClassOutput),
semantic_index, " : SV_ClipDistance", semantic_index, ";");
}
break;
case BuiltInCullDistance:
// HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors.
for (uint32_t cull = 0; cull < cull_distance_count; cull += 4)
{
uint32_t to_declare = cull_distance_count - cull;
if (to_declare > 4)
to_declare = 4;
uint32_t semantic_index = cull / 4;
static const char *types[] = { "float", "float2", "float3", "float4" };
statement(types[to_declare - 1], " ",
builtin_to_glsl(builtin, StorageClassOutput),
semantic_index, " : SV_CullDistance", semantic_index, ";");
}
break;
case BuiltInPointSize:
// If point_size_compat is enabled, just ignore PointSize.
// PointSize does not exist in HLSL, but some code bases might want to be able to use these shaders,
@ -598,6 +632,40 @@ void CompilerHLSL::emit_builtin_inputs_in_struct()
// Handled specially.
break;
case BuiltInClipDistance:
// HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors.
for (uint32_t clip = 0; clip < clip_distance_count; clip += 4)
{
uint32_t to_declare = clip_distance_count - clip;
if (to_declare > 4)
to_declare = 4;
uint32_t semantic_index = clip / 4;
static const char *types[] = { "float", "float2", "float3", "float4" };
statement(types[to_declare - 1], " ",
builtin_to_glsl(builtin, StorageClassInput),
semantic_index, " : SV_ClipDistance", semantic_index, ";");
}
break;
case BuiltInCullDistance:
// HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors.
for (uint32_t cull = 0; cull < cull_distance_count; cull += 4)
{
uint32_t to_declare = cull_distance_count - cull;
if (to_declare > 4)
to_declare = 4;
uint32_t semantic_index = cull / 4;
static const char *types[] = { "float", "float2", "float3", "float4" };
statement(types[to_declare - 1], " ",
builtin_to_glsl(builtin, StorageClassInput),
semantic_index, " : SV_CullDistance", semantic_index, ";");
}
break;
default:
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
break;
@ -807,6 +875,7 @@ void CompilerHLSL::emit_builtin_variables()
const char *type = nullptr;
auto builtin = static_cast<BuiltIn>(i);
uint32_t array_size = 0;
switch (builtin)
{
@ -855,6 +924,16 @@ void CompilerHLSL::emit_builtin_variables()
// Handled specially.
break;
case BuiltInClipDistance:
array_size = clip_distance_count;
type = "float";
break;
case BuiltInCullDistance:
array_size = cull_distance_count;
type = "float";
break;
default:
SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin)));
break;
@ -865,8 +944,13 @@ void CompilerHLSL::emit_builtin_variables()
// need to distinguish that when we add support for that.
if (type)
{
if (array_size)
statement("static ", type, " ", builtin_to_glsl(builtin, storage), "[", array_size, "];");
else
statement("static ", type, " ", builtin_to_glsl(builtin, storage), ";");
}
}
}
void CompilerHLSL::emit_composite_constants()
@ -1843,7 +1927,16 @@ void CompilerHLSL::emit_hlsl_entry_point()
break;
case BuiltInNumWorkgroups:
// Handled specially.
break;
case BuiltInClipDistance:
for (uint32_t clip = 0; clip < clip_distance_count; clip++)
statement("gl_ClipDistance[", clip, "] = stage_input.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3], ";");
break;
case BuiltInCullDistance:
for (uint32_t cull = 0; cull < cull_distance_count; cull++)
statement("gl_CullDistance[", cull, "] = stage_input.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3], ";");
break;
default:
@ -1938,8 +2031,25 @@ void CompilerHLSL::emit_hlsl_entry_point()
if (i == BuiltInPointSize)
continue;
auto builtin = builtin_to_glsl(static_cast<BuiltIn>(i), StorageClassOutput);
statement("stage_output.", builtin, " = ", builtin, ";");
switch (static_cast<BuiltIn>(i))
{
case BuiltInClipDistance:
for (uint32_t clip = 0; clip < clip_distance_count; clip++)
statement("stage_output.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3], " = gl_ClipDistance[", clip, "];");
break;
case BuiltInCullDistance:
for (uint32_t cull = 0; cull < cull_distance_count; cull++)
statement("stage_output.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3], " = gl_CullDistance[", cull, "];");
break;
default:
{
auto builtin_expr = builtin_to_glsl(static_cast<BuiltIn>(i), StorageClassOutput);
statement("stage_output.", builtin_expr, " = ", builtin_expr, ";");
break;
}
}
}
for (auto &id : ids)