GLSL/HLSL: Support packUint2x32 and unpackUint2x32

This commit is contained in:
Asuka 2020-04-17 22:46:06 +08:00 committed by Hans-Kristian Arntzen
parent 3fb86e4385
commit 55dfbead2f
6 changed files with 167 additions and 0 deletions

View File

@ -0,0 +1,34 @@
static float4 FragColor;
struct SPIRV_Cross_Output
{
float4 FragColor : COLOR0;
};
uint64_t SPIRV_Cross_packUint2x32(uint2 value)
{
return uint64_t(value.y) << 32 | uint64_t(value.x);
}
uint2 SPIRV_Cross_unpackUint2x32(uint64_t value)
{
uint2 Unpacked;
Unpacked.x = uint(value & 0xffffffff);
Unpacked.y = uint(value >> 32);
return Unpacked;
}
void frag_main()
{
uint64_t _packed = SPIRV_Cross_packUint2x32(uint2(18u, 52u));
uint2 unpacked = SPIRV_Cross_unpackUint2x32(_packed);
FragColor = float4(float(unpacked.x), float(unpacked.y), 1.0f, 1.0f);
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = float4(FragColor);
return stage_output;
}

View File

@ -0,0 +1,12 @@
#version 450
#extension GL_ARB_gpu_shader_int64 : require
layout(location = 0) out vec4 FragColor;
void main()
{
uint64_t _packed = packUint2x32(uvec2(18u, 52u));
uvec2 unpacked = unpackUint2x32(_packed);
FragColor = vec4(float(unpacked.x), float(unpacked.y), 1.0, 1.0);
}

View File

@ -0,0 +1,55 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 34
; Schema: 0
OpCapability Shader
OpCapability Int64
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_ARB_gpu_shader_int64"
OpName %main "main"
OpName %packed "packed"
OpName %unpacked "unpacked"
OpName %FragColor "FragColor"
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%ulong = OpTypeInt 64 0
%_ptr_Function_ulong = OpTypePointer Function %ulong
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%uint_18 = OpConstant %uint 18
%uint_52 = OpConstant %uint 52
%13 = OpConstantComposite %v2uint %uint_18 %uint_52
%_ptr_Function_v2uint = OpTypePointer Function %v2uint
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%FragColor = OpVariable %_ptr_Output_v4float Output
%uint_0 = OpConstant %uint 0
%_ptr_Function_uint = OpTypePointer Function %uint
%uint_1 = OpConstant %uint 1
%float_1 = OpConstant %float 1
%main = OpFunction %void None %3
%5 = OpLabel
%packed = OpVariable %_ptr_Function_ulong Function
%unpacked = OpVariable %_ptr_Function_v2uint Function
%14 = OpBitcast %ulong %13
OpStore %packed %14
%17 = OpLoad %ulong %packed
%18 = OpBitcast %v2uint %17
OpStore %unpacked %18
%25 = OpAccessChain %_ptr_Function_uint %unpacked %uint_0
%26 = OpLoad %uint %25
%27 = OpConvertUToF %float %26
%29 = OpAccessChain %_ptr_Function_uint %unpacked %uint_1
%30 = OpLoad %uint %29
%31 = OpConvertUToF %float %30
%33 = OpCompositeConstruct %v4float %27 %31 %float_1 %float_1
OpStore %FragColor %33
OpReturn
OpFunctionEnd

View File

@ -6683,6 +6683,8 @@ string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &i
// And finally, some even more special purpose casts.
if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
return "packUint2x32";
else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
return "unpackUint2x32";
else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
return "unpackFloat2x16";
else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)

View File

@ -1499,6 +1499,24 @@ void CompilerHLSL::emit_resources()
statement("");
}
if (requires_uint2_packing)
{
statement("uint64_t SPIRV_Cross_packUint2x32(uint2 value)");
begin_scope();
statement("return uint64_t(value.y) << 32 | uint64_t(value.x);");
end_scope();
statement("");
statement("uint2 SPIRV_Cross_unpackUint2x32(uint64_t value)");
begin_scope();
statement("uint2 Unpacked;");
statement("Unpacked.x = uint(value & 0xffffffff);");
statement("Unpacked.y = uint(value >> 32);");
statement("return Unpacked; ");
end_scope();
statement("");
}
if (requires_explicit_fp16_packing)
{
// HLSL does not pack into a single word sadly :(
@ -4372,6 +4390,27 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
emit_access_chain(instruction);
break;
}
case OpBitcast:
{
auto bitcast_type = get_bitcast_type(ops[0], ops[2]);
if (bitcast_type == CompilerHLSL::TypeNormal)
CompilerGLSL::emit_instruction(instruction);
else
{
if (!requires_uint2_packing)
{
requires_uint2_packing = true;
force_recompile();
}
if (bitcast_type == CompilerHLSL::TypePackUint2x32)
emit_unary_func_op(ops[0], ops[1], ops[2], "SPIRV_Cross_packUint2x32");
else
emit_unary_func_op(ops[0], ops[1], ops[2], "SPIRV_Cross_unpackUint2x32");
}
break;
}
case OpStore:
{
@ -5350,3 +5389,18 @@ bool CompilerHLSL::is_hlsl_resource_binding_used(ExecutionModel model, uint32_t
auto itr = resource_bindings.find(tuple);
return itr != end(resource_bindings) && itr->second.second;
}
CompilerHLSL::BitcastType CompilerHLSL::get_bitcast_type(uint32_t result_type, uint32_t op0)
{
auto &rslt_type = get<SPIRType>(result_type);
auto &expr_type = expression_type(op0);
if (rslt_type.basetype == SPIRType::BaseType::UInt64 && expr_type.basetype == SPIRType::BaseType::UInt &&
expr_type.vecsize == 2)
return BitcastType::TypePackUint2x32;
else if (rslt_type.basetype == SPIRType::BaseType::UInt && rslt_type.vecsize == 2 &&
expr_type.basetype == SPIRType::BaseType::UInt64)
return BitcastType::TypeUnpackUint64;
return BitcastType::TypeNormal;
}

View File

@ -249,6 +249,7 @@ private:
// TODO: Refactor this to be more similar to MSL, maybe have some common system in place?
bool requires_op_fmod = false;
bool requires_fp16_packing = false;
bool requires_uint2_packing = false;
bool requires_explicit_fp16_packing = false;
bool requires_unorm8_packing = false;
bool requires_snorm8_packing = false;
@ -288,6 +289,15 @@ private:
QueryTypeCount = 3
};
enum BitcastType
{
TypeNormal,
TypePackUint2x32,
TypeUnpackUint64
};
BitcastType get_bitcast_type(uint32_t result_type, uint32_t op0);
void emit_builtin_variables();
bool require_output = false;
bool require_input = false;