Merge pull request #1633 from KhronosGroup/fix-1626
GLSL: Handle complex load/store scenarios to gl_SampleMask.
This commit is contained in:
commit
60aa24566e
@ -0,0 +1,28 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 0, std140) uniform uBuffer
|
||||||
|
{
|
||||||
|
vec4 color;
|
||||||
|
} x_12;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
const vec4 _2_init = vec4(0.0);
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = _2_init;
|
||||||
|
gl_SampleMask[0] = 0;
|
||||||
|
fragColor = x_12.color;
|
||||||
|
gl_SampleMask[0] = int(uint(6));
|
||||||
|
gl_SampleMask[0] = int(uint(gl_SampleMask[0]));
|
||||||
|
uint _30_unrolled[1];
|
||||||
|
for (int i = 0; i < int(1); i++)
|
||||||
|
{
|
||||||
|
_30_unrolled[i] = int(gl_SampleMask[i]);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < int(1); i++)
|
||||||
|
{
|
||||||
|
gl_SampleMask[i] = int(_30_unrolled[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
|||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 29
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %main "main" %fragColor %gl_SampleMask
|
||||||
|
OpExecutionMode %main OriginUpperLeft
|
||||||
|
OpName %fragColor "fragColor"
|
||||||
|
OpName %uBuffer "uBuffer"
|
||||||
|
OpMemberName %uBuffer 0 "color"
|
||||||
|
OpName %x_12 "x_12"
|
||||||
|
OpName %gl_SampleMask "gl_SampleMask"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %fragColor Location 0
|
||||||
|
OpDecorate %uBuffer Block
|
||||||
|
OpMemberDecorate %uBuffer 0 Offset 0
|
||||||
|
OpDecorate %x_12 DescriptorSet 0
|
||||||
|
OpDecorate %x_12 Binding 0
|
||||||
|
OpDecorate %gl_SampleMask BuiltIn SampleMask
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%v4float = OpTypeVector %float 4
|
||||||
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||||
|
%5 = OpConstantNull %v4float
|
||||||
|
%fragColor = OpVariable %_ptr_Output_v4float Output %5
|
||||||
|
%uBuffer = OpTypeStruct %v4float
|
||||||
|
%_ptr_Uniform_uBuffer = OpTypePointer Uniform %uBuffer
|
||||||
|
%x_12 = OpVariable %_ptr_Uniform_uBuffer Uniform
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
|
||||||
|
%_ptr_Output__arr_uint_uint_1 = OpTypePointer Output %_arr_uint_uint_1
|
||||||
|
%14 = OpConstantNull %_arr_uint_uint_1
|
||||||
|
%gl_SampleMask = OpVariable %_ptr_Output__arr_uint_uint_1 Output %14
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%15 = OpTypeFunction %void
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%int_0 = OpConstant %int 0
|
||||||
|
%_ptr_Output_uint = OpTypePointer Output %uint
|
||||||
|
%int_6 = OpConstant %int 6
|
||||||
|
%main = OpFunction %void None %15
|
||||||
|
%18 = OpLabel
|
||||||
|
%21 = OpAccessChain %_ptr_Uniform_v4float %x_12 %uint_0
|
||||||
|
%22 = OpLoad %v4float %21
|
||||||
|
OpStore %fragColor %22
|
||||||
|
%26 = OpAccessChain %_ptr_Output_uint %gl_SampleMask %int_0
|
||||||
|
%27 = OpBitcast %uint %int_6
|
||||||
|
OpStore %26 %27
|
||||||
|
%loaded_scalar = OpLoad %uint %26
|
||||||
|
OpStore %26 %loaded_scalar
|
||||||
|
%loaded = OpLoad %_arr_uint_uint_1 %gl_SampleMask
|
||||||
|
OpStore %gl_SampleMask %loaded
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
100
spirv_glsl.cpp
100
spirv_glsl.cpp
@ -3608,6 +3608,21 @@ void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var)
|
|||||||
statement(to_expression(var.self), "[gl_InvocationID] = ", lut_name, "[gl_InvocationID];");
|
statement(to_expression(var.self), "[gl_InvocationID] = ", lut_name, "[gl_InvocationID];");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (has_decoration(var.self, DecorationBuiltIn) &&
|
||||||
|
BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInSampleMask)
|
||||||
|
{
|
||||||
|
// We cannot copy the array since gl_SampleMask is unsized in GLSL. Unroll time! <_<
|
||||||
|
entry_func.fixup_hooks_in.push_back([&] {
|
||||||
|
auto &c = this->get<SPIRConstant>(var.initializer);
|
||||||
|
uint32_t num_constants = uint32_t(c.subconstants.size());
|
||||||
|
for (uint32_t i = 0; i < num_constants; i++)
|
||||||
|
{
|
||||||
|
// Don't use to_expression on constant since it might be uint, just fish out the raw int.
|
||||||
|
statement(to_expression(var.self), "[", i, "] = ",
|
||||||
|
convert_to_string(this->get<SPIRConstant>(c.subconstants[i]).scalar_i32()), ";");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto lut_name = join("_", var.self, "_init");
|
auto lut_name = join("_", var.self, "_init");
|
||||||
@ -9664,17 +9679,20 @@ void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_ex
|
|||||||
{
|
{
|
||||||
handle_store_to_invariant_variable(lhs_expression, rhs_expression);
|
handle_store_to_invariant_variable(lhs_expression, rhs_expression);
|
||||||
|
|
||||||
auto lhs = to_dereferenced_expression(lhs_expression);
|
if (!unroll_array_to_complex_store(lhs_expression, rhs_expression))
|
||||||
|
{
|
||||||
|
auto lhs = to_dereferenced_expression(lhs_expression);
|
||||||
|
|
||||||
// We might need to cast in order to store to a builtin.
|
// We might need to cast in order to store to a builtin.
|
||||||
cast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression));
|
cast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression));
|
||||||
|
|
||||||
// Tries to optimize assignments like "<lhs> = <lhs> op expr".
|
// Tries to optimize assignments like "<lhs> = <lhs> op expr".
|
||||||
// While this is purely cosmetic, this is important for legacy ESSL where loop
|
// While this is purely cosmetic, this is important for legacy ESSL where loop
|
||||||
// variable increments must be in either i++ or i += const-expr.
|
// variable increments must be in either i++ or i += const-expr.
|
||||||
// Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
|
// Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
|
||||||
if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
|
if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
|
||||||
statement(lhs, " = ", rhs, ";");
|
statement(lhs, " = ", rhs, ";");
|
||||||
|
}
|
||||||
register_write(lhs_expression);
|
register_write(lhs_expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9836,6 +9854,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||||||
// We might be trying to load a gl_Position[N], where we should be
|
// We might be trying to load a gl_Position[N], where we should be
|
||||||
// doing float4[](gl_in[i].gl_Position, ...) instead.
|
// doing float4[](gl_in[i].gl_Position, ...) instead.
|
||||||
// Similar workarounds are required for input arrays in tessellation.
|
// Similar workarounds are required for input arrays in tessellation.
|
||||||
|
// Also, loading from gl_SampleMask array needs special unroll.
|
||||||
unroll_array_from_complex_load(id, ptr, expr);
|
unroll_array_from_complex_load(id, ptr, expr);
|
||||||
|
|
||||||
// Shouldn't need to check for ID, but current glslang codegen requires it in some cases
|
// Shouldn't need to check for ID, but current glslang codegen requires it in some cases
|
||||||
@ -14966,6 +14985,43 @@ void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCl
|
|||||||
statement(lhs, " = ", to_expression(rhs_id), ";");
|
statement(lhs, " = ", to_expression(rhs_id), ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
|
||||||
|
{
|
||||||
|
if (!backend.force_gl_in_out_block)
|
||||||
|
return false;
|
||||||
|
// This path is only relevant for GL backends.
|
||||||
|
|
||||||
|
auto *var = maybe_get<SPIRVariable>(target_id);
|
||||||
|
if (!var || var->storage != StorageClassOutput)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!is_builtin_variable(*var) || BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSampleMask)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto &type = expression_type(source_id);
|
||||||
|
string array_expr;
|
||||||
|
if (type.array_size_literal.back())
|
||||||
|
{
|
||||||
|
array_expr = convert_to_string(type.array.back());
|
||||||
|
if (type.array.back() == 0)
|
||||||
|
SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
array_expr = to_expression(type.array.back());
|
||||||
|
|
||||||
|
SPIRType target_type;
|
||||||
|
target_type.basetype = SPIRType::Int;
|
||||||
|
|
||||||
|
statement("for (int i = 0; i < int(", array_expr, "); i++)");
|
||||||
|
begin_scope();
|
||||||
|
statement(to_expression(target_id), "[i] = ",
|
||||||
|
bitcast_expression(target_type, type.basetype, join(to_expression(source_id), "[i]")),
|
||||||
|
";");
|
||||||
|
end_scope();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr)
|
void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr)
|
||||||
{
|
{
|
||||||
if (!backend.force_gl_in_out_block)
|
if (!backend.force_gl_in_out_block)
|
||||||
@ -14976,7 +15032,7 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s
|
|||||||
if (!var)
|
if (!var)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (var->storage != StorageClassInput)
|
if (var->storage != StorageClassInput && var->storage != StorageClassOutput)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &type = get_variable_data_type(*var);
|
auto &type = get_variable_data_type(*var);
|
||||||
@ -14984,9 +15040,13 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
|
auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
|
||||||
bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition);
|
bool is_builtin = is_builtin_variable(*var) &&
|
||||||
|
(builtin == BuiltInPointSize ||
|
||||||
|
builtin == BuiltInPosition ||
|
||||||
|
builtin == BuiltInSampleMask);
|
||||||
bool is_tess = is_tessellation_shader();
|
bool is_tess = is_tessellation_shader();
|
||||||
bool is_patch = has_decoration(var->self, DecorationPatch);
|
bool is_patch = has_decoration(var->self, DecorationPatch);
|
||||||
|
bool is_sample_mask = is_builtin && builtin == BuiltInSampleMask;
|
||||||
|
|
||||||
// Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
|
// Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
|
||||||
// We must unroll the array load.
|
// We must unroll the array load.
|
||||||
@ -15010,8 +15070,14 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s
|
|||||||
// The array size might be a specialization constant, so use a for-loop instead.
|
// The array size might be a specialization constant, so use a for-loop instead.
|
||||||
statement("for (int i = 0; i < int(", array_expr, "); i++)");
|
statement("for (int i = 0; i < int(", array_expr, "); i++)");
|
||||||
begin_scope();
|
begin_scope();
|
||||||
if (is_builtin)
|
if (is_builtin && !is_sample_mask)
|
||||||
statement(new_expr, "[i] = gl_in[i].", expr, ";");
|
statement(new_expr, "[i] = gl_in[i].", expr, ";");
|
||||||
|
else if (is_sample_mask)
|
||||||
|
{
|
||||||
|
SPIRType target_type;
|
||||||
|
target_type.basetype = SPIRType::Int;
|
||||||
|
statement(new_expr, "[i] = ", bitcast_expression(target_type, type.basetype, join(expr, "[i]")), ";");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
statement(new_expr, "[i] = ", expr, "[i];");
|
statement(new_expr, "[i] = ", expr, "[i];");
|
||||||
end_scope();
|
end_scope();
|
||||||
@ -15022,6 +15088,10 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s
|
|||||||
|
|
||||||
void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
|
void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
|
||||||
{
|
{
|
||||||
|
// We will handle array cases elsewhere.
|
||||||
|
if (!expr_type.array.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
auto *var = maybe_get_backing_variable(source_id);
|
auto *var = maybe_get_backing_variable(source_id);
|
||||||
if (var)
|
if (var)
|
||||||
source_id = var->self;
|
source_id = var->self;
|
||||||
@ -15049,6 +15119,7 @@ void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr,
|
|||||||
case BuiltInDrawIndex:
|
case BuiltInDrawIndex:
|
||||||
case BuiltInFragStencilRefEXT:
|
case BuiltInFragStencilRefEXT:
|
||||||
case BuiltInInstanceCustomIndexNV:
|
case BuiltInInstanceCustomIndexNV:
|
||||||
|
case BuiltInSampleMask:
|
||||||
expected_type = SPIRType::Int;
|
expected_type = SPIRType::Int;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -15074,6 +15145,10 @@ void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr,
|
|||||||
|
|
||||||
void CompilerGLSL::cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
|
void CompilerGLSL::cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
|
||||||
{
|
{
|
||||||
|
auto *var = maybe_get_backing_variable(target_id);
|
||||||
|
if (var)
|
||||||
|
target_id = var->self;
|
||||||
|
|
||||||
// Only interested in standalone builtin variables.
|
// Only interested in standalone builtin variables.
|
||||||
if (!has_decoration(target_id, DecorationBuiltIn))
|
if (!has_decoration(target_id, DecorationBuiltIn))
|
||||||
return;
|
return;
|
||||||
@ -15088,6 +15163,7 @@ void CompilerGLSL::cast_to_builtin_store(uint32_t target_id, std::string &expr,
|
|||||||
case BuiltInPrimitiveId:
|
case BuiltInPrimitiveId:
|
||||||
case BuiltInViewportIndex:
|
case BuiltInViewportIndex:
|
||||||
case BuiltInFragStencilRefEXT:
|
case BuiltInFragStencilRefEXT:
|
||||||
|
case BuiltInSampleMask:
|
||||||
expected_type = SPIRType::Int;
|
expected_type = SPIRType::Int;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -880,6 +880,7 @@ protected:
|
|||||||
virtual void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
|
virtual void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
|
||||||
virtual void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
|
virtual void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
|
||||||
void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr);
|
void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr);
|
||||||
|
bool unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id);
|
||||||
void convert_non_uniform_expression(const SPIRType &type, std::string &expr);
|
void convert_non_uniform_expression(const SPIRType &type, std::string &expr);
|
||||||
|
|
||||||
void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
|
void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user