Merge pull request #151 from Kode/fix

Transform more functions for HLSL
This commit is contained in:
Hans-Kristian Arntzen 2017-03-24 16:13:34 +01:00 коммит произвёл GitHub
Родитель 91a1d0a4fe cb637db5d6
Коммит f4749df09a
14 изменённых файлов: 475 добавлений и 18 удалений

Просмотреть файл

@ -0,0 +1,27 @@
static float2 value;
static float4 FragColor;
struct SPIRV_Cross_Input
{
float2 value : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 FragColor : SV_Target0;
};
void frag_main()
{
int i = asint(value.x);
FragColor = float4(1.0f, 0.0f, asfloat(i), 1.0f);
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
value = stage_input.value;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

Просмотреть файл

@ -5,14 +5,14 @@ static float4 vColor;
struct SPIRV_Cross_Input
{
float4 gl_FragCoord : SV_Position;
float4 vColor : TEXCOORD0;
float4 gl_FragCoord : SV_Position;
};
struct SPIRV_Cross_Output
{
float gl_FragDepth : SV_Depth;
float4 FragColor : SV_Target0;
float gl_FragDepth : SV_Depth;
};
void frag_main()

Просмотреть файл

@ -0,0 +1,29 @@
static float2 value;
static float4 FragColor;
struct SPIRV_Cross_Input
{
float2 value : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 FragColor : SV_Target0;
};
void frag_main()
{
bool2 _25 = bool2(value.x == 0.0f, value.y == 0.0f);
bool2 bools1 = bool2(!_25.x, !_25.y);
bool2 bools2 = bool2(value.x <= float2(1.5f, 0.5f).x, value.y <= float2(1.5f, 0.5f).y);
FragColor = float4(1.0f, 0.0f, float(bools1.x), float(bools2.x));
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
value = stage_input.value;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

Просмотреть файл

@ -0,0 +1,28 @@
static float2 interpolant;
static float4 FragColor;
struct SPIRV_Cross_Input
{
float2 interpolant : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float4 FragColor : SV_Target0;
};
void frag_main()
{
float4 color = float4(0.0f, 0.0f, 0.0f, EvaluateAttributeSnapped(interpolant, float2(0.100000001490116119384765625f, 0.100000001490116119384765625f)).x);
color += float4(0.0f, 0.0f, 0.0f, ddx_coarse(interpolant.x));
FragColor = color;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
interpolant = stage_input.interpolant;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

Просмотреть файл

@ -21,8 +21,8 @@ struct SPIRV_Cross_Input
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
float3 vNormal : TEXCOORD0;
float4 gl_Position : SV_Position;
};
void vert_main()

Просмотреть файл

@ -32,12 +32,12 @@ struct SPIRV_Cross_Input
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
float vLocation0 : TEXCOORD0;
float vLocation1 : TEXCOORD1;
float vLocation2[2] : TEXCOORD2;
Foo vLocation4 : TEXCOORD4;
float vLocation9 : TEXCOORD9;
float4 gl_Position : SV_Position;
};
void vert_main()

Просмотреть файл

@ -16,11 +16,11 @@ static Block vout;
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
nointerpolation float vFlat : TEXCOORD0;
centroid float vCentroid : TEXCOORD1;
sample float vSample : TEXCOORD2;
noperspective float vNoperspective : TEXCOORD3;
float4 gl_Position : SV_Position;
};
void vert_main()

Просмотреть файл

@ -0,0 +1,12 @@
#version 310 es
precision mediump float;
layout(location = 0) in vec2 value;
layout(location = 0) out vec4 FragColor;
void main()
{
int i = floatBitsToInt(value.x);
FragColor = vec4(1.0, 0.0, intBitsToFloat(i), 1.0);
}

Просмотреть файл

@ -0,0 +1,13 @@
#version 310 es
precision mediump float;
layout(location = 0) in vec2 value;
layout(location = 0) out vec4 FragColor;
void main()
{
bvec2 bools1 = not(bvec2(value.x == 0.0, value.y == 0.0));
bvec2 bools2 = lessThanEqual(value, vec2(1.5, 0.5));
FragColor = vec4(1.0, 0.0, bools1.x ? 1.0 : 0.0, bools2.x ? 1.0 : 0.0);
}

Просмотреть файл

@ -0,0 +1,17 @@
#version 450
in vec2 interpolant;
out vec4 FragColor;
void main()
{
vec4 color = vec4(0.0, 0.0, 0.0, interpolateAtOffset(interpolant, vec2(0.1, 0.1)));
// glslang's HLSL parser currently fails here
//color += vec4(0.0, 0.0, 0.0, interpolateAtSample(interpolant, gl_SampleID));
//color += vec4(0.0, 0.0, 0.0, interpolateAtCentroid(interpolant));
color += vec4(0.0, 0.0, 0.0, dFdxCoarse(interpolant.x));
FragColor = color;
}

Просмотреть файл

@ -2268,6 +2268,29 @@ void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint
inherit_expression_dependencies(result_id, op1);
}
void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
{
auto &type = get<SPIRType>(result_type);
auto expr = type_to_glsl_constructor(type);
expr += '(';
for (uint32_t i = 0; i < type.vecsize; i++)
{
// Make sure to call to_expression multiple times to ensure
// that these expressions are properly flushed to temporaries if needed.
expr += op;
expr += to_enclosed_expression(operand);
expr += '.';
expr += index_to_swizzle(i);
if (i + 1 < type.vecsize)
expr += ", ";
}
expr += ')';
emit_op(result_type, result_id, expr, should_forward(operand));
inherit_expression_dependencies(result_id, operand);
}
void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
const char *op)
{
@ -5032,6 +5055,46 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
require_extension("GL_OES_standard_derivatives");
break;
case OpDPdxFine:
UFOP(dFdxFine);
if (options.es)
{
SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
}
if (options.version < 450)
require_extension("GL_ARB_derivative_control");
break;
case OpDPdyFine:
UFOP(dFdyFine);
if (options.es)
{
SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
}
if (options.version < 450)
require_extension("GL_ARB_derivative_control");
break;
case OpDPdxCoarse:
if (options.es)
{
SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
}
UFOP(dFdxCoarse);
if (options.version < 450)
require_extension("GL_ARB_derivative_control");
break;
case OpDPdyCoarse:
UFOP(dFdyCoarse);
if (options.es)
{
SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
}
if (options.version < 450)
require_extension("GL_ARB_derivative_control");
break;
case OpFwidth:
UFOP(fwidth);
if (is_legacy_es())

Просмотреть файл

@ -309,6 +309,7 @@ protected:
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
void emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op);
void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
@ -371,7 +372,7 @@ protected:
uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags);
std::string bitcast_glsl(const SPIRType &result_type, uint32_t arg);
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type);
virtual std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type);
std::string build_composite_combiner(const uint32_t *elems, uint32_t length);
bool remove_duplicate_swizzle(std::string &op);
bool remove_unity_swizzle(uint32_t base, std::string &op);

Просмотреть файл

@ -22,6 +22,27 @@ using namespace spv;
using namespace spirv_cross;
using namespace std;
// Returns true if an arithmetic operation does not change behavior depending on signedness.
static bool opcode_is_sign_invariant(Op opcode)
{
switch (opcode)
{
case OpIEqual:
case OpINotEqual:
case OpISub:
case OpIAdd:
case OpIMul:
case OpShiftLeftLogical:
case OpBitwiseOr:
case OpBitwiseXor:
case OpBitwiseAnd:
return true;
default:
return false;
}
}
string CompilerHLSL::type_to_glsl(const SPIRType &type)
{
// Ignore the pointer type since GLSL doesn't have pointers.
@ -219,6 +240,13 @@ void CompilerHLSL::emit_builtin_inputs_in_struct()
semantic = "SV_InstanceID";
break;
case BuiltInSampleId:
if (legacy)
SPIRV_CROSS_THROW("Sample ID not supported in SM 3.0 or lower.");
type = "uint";
semantic = "SV_SampleIndex";
break;
default:
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
break;
@ -395,6 +423,7 @@ void CompilerHLSL::emit_builtin_variables()
case BuiltInVertexIndex:
case BuiltInInstanceIndex:
case BuiltInSampleId:
type = "int";
break;
@ -608,9 +637,9 @@ void CompilerHLSL::emit_resources()
begin_scope();
sort(input_variables.begin(), input_variables.end(), variable_compare);
emit_builtin_inputs_in_struct();
for (auto var : input_variables)
emit_interface_block_in_struct(*var, active_inputs);
emit_builtin_inputs_in_struct();
end_scope_decl();
statement("");
}
@ -623,9 +652,9 @@ void CompilerHLSL::emit_resources()
begin_scope();
// FIXME: Use locations properly if they exist.
sort(output_variables.begin(), output_variables.end(), variable_compare);
emit_builtin_outputs_in_struct();
for (auto var : output_variables)
emit_interface_block_in_struct(*var, active_outputs);
emit_builtin_outputs_in_struct();
end_scope_decl();
statement("");
}
@ -1213,6 +1242,36 @@ void CompilerHLSL::emit_uniform(const SPIRVariable &var)
statement(variable_decl(var), ";");
}
string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
{
if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
return "asuint";
else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
return "asint";
else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
return "asfloat";
else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
return "asfloat";
else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
SPIRV_CROSS_THROW("Double to Int64 is not supported in HLSL.");
else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
SPIRV_CROSS_THROW("Double to UInt64 is not supported in HLSL.");
else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
return "asdouble";
else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
return "asdouble";
else
return "";
}
void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t count)
{
GLSLstd450 op = static_cast<GLSLstd450>(eop);
@ -1220,26 +1279,36 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
switch (op)
{
case GLSLstd450InverseSqrt:
{
emit_unary_func_op(result_type, id, args[0], "rsqrt");
break;
}
case GLSLstd450Fract:
{
emit_unary_func_op(result_type, id, args[0], "frac");
break;
}
case GLSLstd450FMix:
case GLSLstd450IMix:
{
emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "lerp");
break;
}
case GLSLstd450Atan2:
{
emit_binary_func_op(result_type, id, args[1], args[0], "atan2");
break;
}
case GLSLstd450Fma:
emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mad");
break;
case GLSLstd450InterpolateAtCentroid:
emit_unary_func_op(result_type, id, args[0], "EvaluateAttributeAtCentroid");
break;
case GLSLstd450InterpolateAtSample:
emit_binary_func_op(result_type, id, args[0], args[1], "EvaluateAttributeAtSample");
break;
case GLSLstd450InterpolateAtOffset:
emit_binary_func_op(result_type, id, args[0], args[1], "EvaluateAttributeSnapped");
break;
default:
CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
break;
@ -1252,12 +1321,14 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
auto opcode = static_cast<Op>(instruction.op);
#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BOP_CAST(op, type, skip_cast) emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
#define BOP_CAST(op, type) \
emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
#define BFOP_CAST(op, type) \
emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
@ -1268,22 +1339,217 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
break;
}
case OpVectorTimesMatrix:
{
emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
break;
}
case OpMatrixTimesMatrix:
{
emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
break;
}
case OpFMod:
{
requires_op_fmod = true;
CompilerGLSL::emit_instruction(instruction);
break;
}
case OpDPdx:
UFOP(ddx);
break;
case OpDPdy:
UFOP(ddy);
break;
case OpDPdxFine:
UFOP(ddx_fine);
break;
case OpDPdyFine:
UFOP(ddy_fine);
break;
case OpDPdxCoarse:
UFOP(ddx_coarse);
break;
case OpDPdyCoarse:
UFOP(ddy_coarse);
break;
case OpLogicalNot:
{
auto result_type = ops[0];
auto id = ops[1];
auto &type = get<SPIRType>(result_type);
if (type.vecsize > 1)
emit_unrolled_unary_op(result_type, id, ops[2], "!");
else
UOP(!);
break;
}
case OpIEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==");
else
BOP_CAST(== , SPIRType::Int);
break;
}
case OpLogicalEqual:
case OpFOrdEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==");
else
BOP(== );
break;
}
case OpINotEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=");
else
BOP_CAST(!= , SPIRType::Int);
break;
}
case OpLogicalNotEqual:
case OpFOrdNotEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=");
else
BOP(!= );
break;
}
case OpUGreaterThan:
case OpSGreaterThan:
{
auto result_type = ops[0];
auto id = ops[1];
auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">");
else
BOP_CAST(>, type);
break;
}
case OpFOrdGreaterThan:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">");
else
BOP(>);
break;
}
case OpUGreaterThanEqual:
case OpSGreaterThanEqual:
{
auto result_type = ops[0];
auto id = ops[1];
auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=");
else
BOP_CAST(>= , type);
break;
}
case OpFOrdGreaterThanEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=");
else
BOP(>= );
break;
}
case OpULessThan:
case OpSLessThan:
{
auto result_type = ops[0];
auto id = ops[1];
auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<");
else
BOP_CAST(<, type);
break;
}
case OpFOrdLessThan:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<");
else
BOP(<);
break;
}
case OpULessThanEqual:
case OpSLessThanEqual:
{
auto result_type = ops[0];
auto id = ops[1];
auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=");
else
BOP_CAST(<= , type);
break;
}
case OpFOrdLessThanEqual:
{
auto result_type = ops[0];
auto id = ops[1];
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=");
else
BOP(<= );
break;
}
default:
CompilerGLSL::emit_instruction(instruction);
break;

Просмотреть файл

@ -69,6 +69,7 @@ private:
void emit_uniform(const SPIRVariable &var) override;
std::string layout_for_member(const SPIRType &type, uint32_t index) override;
std::string to_interpolation_qualifiers(uint64_t flags) override;
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;