Support ternary expressions in OpSpecConstantOp.

This commit is contained in:
Hans-Kristian Arntzen 2018-06-25 09:48:17 +02:00
parent 7607eb6923
commit ffa9133d77
13 changed files with 203 additions and 29 deletions

View File

@ -0,0 +1,23 @@
static const uint s = 10u;
static const bool _13 = (s > 20u);
static const uint _16 = _13 ? 30u : 50u;
static float FragColor;
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float(_16);
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
constant uint s_tmp [[function_constant(0)]];
constant uint s = is_function_constant_defined(s_tmp) ? s_tmp : 10u;
constant bool _13 = (s > 20u);
constant uint _16 = _13 ? 30u : 50u;
struct main0_out
{
float FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float(_16);
return out;
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
void main()
{
FragColor = float((10u > 20u) ? 30u : 50u);
}

View File

@ -0,0 +1,13 @@
#version 450
layout(constant_id = 0) const uint s = 10u;
const bool _13 = (s > 20u);
const uint _16 = _13 ? 30u : 50u;
layout(location = 0) out float FragColor;
void main()
{
FragColor = float(_16);
}

View File

@ -0,0 +1,23 @@
static const uint s = 10u;
static const bool _13 = (s > 20u);
static const uint _16 = _13 ? 30u : 50u;
static float FragColor;
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float(_16);
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
constant uint s_tmp [[function_constant(0)]];
constant uint s = is_function_constant_defined(s_tmp) ? s_tmp : 10u;
constant bool _13 = (s > 20u);
constant uint _16 = _13 ? 30u : 50u;
struct main0_out
{
float FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float(_16);
return out;
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
void main()
{
FragColor = float((10u > 20u) ? 30u : 50u);
}

View File

@ -0,0 +1,13 @@
#version 450
layout(constant_id = 0) const uint s = 10u;
const bool _13 = (s > 20u);
const uint _16 = _13 ? 30u : 50u;
layout(location = 0) out float FragColor;
void main()
{
FragColor = float(_16);
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -2553,11 +2553,14 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
// In order to preserve its compile-time constness in Vulkan GLSL,
// we need to reduce the OpSelect expression back to this simplified model.
// If we cannot, fail.
if (!to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
{
SPIRV_CROSS_THROW(
"Cannot implement specialization constant op OpSelect. "
"Need trivial select implementation which can be resolved to a simple cast from boolean.");
// Implement as a simple cast down below.
}
else
{
// Implement a ternary and pray the compiler understands it :)
return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
}
break;
}
@ -3578,6 +3581,37 @@ bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t
return ret;
}
string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
uint32_t false_value)
{
string expr;
auto &lerptype = expression_type(select);
if (lerptype.vecsize == 1)
expr = join(to_enclosed_expression(select), " ? ", to_enclosed_expression(true_value), " : ",
to_enclosed_expression(false_value));
else
{
auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
expr = type_to_glsl_constructor(restype);
expr += "(";
for (uint32_t i = 0; i < restype.vecsize; i++)
{
expr += swiz(select, i);
expr += " ? ";
expr += swiz(true_value, i);
expr += " : ";
expr += swiz(false_value, i);
if (i + 1 < restype.vecsize)
expr += ", ";
}
expr += ")";
}
return expr;
}
void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp)
{
auto &lerptype = expression_type(lerp);
@ -3608,31 +3642,7 @@ void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left,
// Could use GL_EXT_shader_integer_mix on desktop at least,
// but Apple doesn't support it. :(
// Just implement it as ternary expressions.
string expr;
if (lerptype.vecsize == 1)
expr = join(to_enclosed_expression(lerp), " ? ", to_enclosed_expression(right), " : ",
to_enclosed_expression(left));
else
{
auto swiz = [this](uint32_t expression, uint32_t i) {
return to_extract_component_expression(expression, i);
};
expr = type_to_glsl_constructor(restype);
expr += "(";
for (uint32_t i = 0; i < restype.vecsize; i++)
{
expr += swiz(lerp, i);
expr += " ? ";
expr += swiz(right, i);
expr += " : ";
expr += swiz(left, i);
if (i + 1 < restype.vecsize)
expr += ", ";
}
expr += ")";
}
auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
inherit_expression_dependencies(id, left);
inherit_expression_dependencies(id, right);

View File

@ -408,6 +408,9 @@ protected:
SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type,
uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type);
std::string to_ternary_expression(const SPIRType &result_type, uint32_t select, uint32_t true_value,
uint32_t false_value);
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
bool expression_is_forwarded(uint32_t id);
SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,