Implement bitfield ops in HLSL.

This commit is contained in:
Hans-Kristian Arntzen 2017-11-29 11:33:44 +01:00
parent 7b73d135f7
commit 48f3fa4adb
5 changed files with 369 additions and 0 deletions

View File

@ -0,0 +1,113 @@
uint SPIRV_Cross_bitfieldInsert(uint Base, uint Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint2 SPIRV_Cross_bitfieldInsert(uint2 Base, uint2 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint3 SPIRV_Cross_bitfieldInsert(uint3 Base, uint3 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint4 SPIRV_Cross_bitfieldInsert(uint4 Base, uint4 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint SPIRV_Cross_bitfieldUExtract(uint Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint2 SPIRV_Cross_bitfieldUExtract(uint2 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint3 SPIRV_Cross_bitfieldUExtract(uint3 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint4 SPIRV_Cross_bitfieldUExtract(uint4 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
int SPIRV_Cross_bitfieldSExtract(int Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int2 SPIRV_Cross_bitfieldSExtract(int2 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int2 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int3 SPIRV_Cross_bitfieldSExtract(int3 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int3 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int4 SPIRV_Cross_bitfieldSExtract(int4 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int4 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
void comp_main()
{
int signed_value = 0;
uint unsigned_value = 0u;
int3 signed_values = int3(0, 0, 0);
uint3 unsigned_values = uint3(0u, 0u, 0u);
int s = SPIRV_Cross_bitfieldSExtract(signed_value, 5, 20);
uint u = SPIRV_Cross_bitfieldUExtract(unsigned_value, 6, 21);
s = int(SPIRV_Cross_bitfieldInsert(s, 40, 5, 4));
u = SPIRV_Cross_bitfieldInsert(u, 60u, 5, 4);
u = reversebits(u);
s = reversebits(s);
int v0 = countbits(u);
int v1 = countbits(s);
int v2 = firstbithigh(u);
int v3 = firstbitlow(s);
int3 s_1 = SPIRV_Cross_bitfieldSExtract(signed_values, 5, 20);
uint3 u_1 = SPIRV_Cross_bitfieldUExtract(unsigned_values, 6, 21);
s_1 = int3(SPIRV_Cross_bitfieldInsert(s_1, int3(40, 40, 40), 5, 4));
u_1 = SPIRV_Cross_bitfieldInsert(u_1, uint3(60u, 60u, 60u), 5, 4);
u_1 = reversebits(u_1);
s_1 = reversebits(s_1);
int3 v0_1 = countbits(u_1);
int3 v1_1 = countbits(s_1);
int3 v2_1 = firstbithigh(u_1);
int3 v3_1 = firstbitlow(s_1);
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,113 @@
uint SPIRV_Cross_bitfieldInsert(uint Base, uint Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint2 SPIRV_Cross_bitfieldInsert(uint2 Base, uint2 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint3 SPIRV_Cross_bitfieldInsert(uint3 Base, uint3 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint4 SPIRV_Cross_bitfieldInsert(uint4 Base, uint4 Insert, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));
return (Base & ~Mask) | ((Insert << Offset) & Mask);
}
uint SPIRV_Cross_bitfieldUExtract(uint Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint2 SPIRV_Cross_bitfieldUExtract(uint2 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint3 SPIRV_Cross_bitfieldUExtract(uint3 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
uint4 SPIRV_Cross_bitfieldUExtract(uint4 Base, uint Offset, uint Count)
{
uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);
return (Base >> Offset) & Mask;
}
int SPIRV_Cross_bitfieldSExtract(int Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int2 SPIRV_Cross_bitfieldSExtract(int2 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int2 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int3 SPIRV_Cross_bitfieldSExtract(int3 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int3 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
int4 SPIRV_Cross_bitfieldSExtract(int4 Base, int Offset, int Count)
{
int Mask = Count == 32 ? -1 : ((1 << Count) - 1);
int4 Masked = (Base >> Offset) & Mask;
int ExtendShift = (32 - Count) & 31;
return (Masked << ExtendShift) >> ExtendShift;
}
void comp_main()
{
int signed_value = 0;
uint unsigned_value = 0u;
int3 signed_values = int3(0, 0, 0);
uint3 unsigned_values = uint3(0u, 0u, 0u);
int s = SPIRV_Cross_bitfieldSExtract(signed_value, 5, 20);
uint u = SPIRV_Cross_bitfieldUExtract(unsigned_value, 6, 21);
s = int(SPIRV_Cross_bitfieldInsert(s, 40, 5, 4));
u = SPIRV_Cross_bitfieldInsert(u, 60u, 5, 4);
u = reversebits(u);
s = reversebits(s);
int v0 = countbits(u);
int v1 = countbits(s);
int v2 = firstbithigh(u);
int v3 = firstbitlow(s);
int3 s_1 = SPIRV_Cross_bitfieldSExtract(signed_values, 5, 20);
uint3 u_1 = SPIRV_Cross_bitfieldUExtract(unsigned_values, 6, 21);
s_1 = int3(SPIRV_Cross_bitfieldInsert(s_1, int3(40, 40, 40), 5, 4));
u_1 = SPIRV_Cross_bitfieldInsert(u_1, uint3(60u, 60u, 60u), 5, 4);
u_1 = reversebits(u_1);
s_1 = reversebits(s_1);
int3 v0_1 = countbits(u_1);
int3 v1_1 = countbits(s_1);
int3 v2_1 = firstbithigh(u_1);
int3 v3_1 = firstbitlow(s_1);
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,44 @@
#version 310 es
void main()
{
int signed_value = 0;
uint unsigned_value = 0u;
ivec3 signed_values = ivec3(0);
uvec3 unsigned_values = uvec3(0u);
{
int s = bitfieldExtract(signed_value, 5, 20);
uint u = bitfieldExtract(unsigned_value, 6, 21);
s = bitfieldInsert(s, 40, 5, 4);
u = bitfieldInsert(u, 60u, 5, 4);
u = bitfieldReverse(u);
s = bitfieldReverse(s);
int v0 = bitCount(u);
int v1 = bitCount(s);
int v2 = findMSB(u);
int v3 = findLSB(s);
}
{
ivec3 s = bitfieldExtract(signed_values, 5, 20);
uvec3 u = bitfieldExtract(unsigned_values, 6, 21);
s = bitfieldInsert(s, ivec3(40), 5, 4);
u = bitfieldInsert(u, uvec3(60u), 5, 4);
u = bitfieldReverse(u);
s = bitfieldReverse(s);
ivec3 v0 = bitCount(u);
ivec3 v1 = bitCount(s);
ivec3 v2 = findMSB(u);
ivec3 v3 = findLSB(s);
}
}

View File

@ -1271,6 +1271,48 @@ void CompilerHLSL::emit_resources()
end_scope();
statement("");
}
if (requires_bitfield_insert)
{
static const char *types[] = { "uint", "uint2", "uint3", "uint4" };
for (auto &type : types)
{
statement(type, " SPIRV_Cross_bitfieldInsert(", type, " Base, ", type, " Insert, uint Offset, uint Count)");
begin_scope();
statement("uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));");
statement("return (Base & ~Mask) | ((Insert << Offset) & Mask);");
end_scope();
statement("");
}
}
if (requires_bitfield_extract)
{
static const char *unsigned_types[] = { "uint", "uint2", "uint3", "uint4" };
for (auto &type : unsigned_types)
{
statement(type, " SPIRV_Cross_bitfieldUExtract(", type, " Base, uint Offset, uint Count)");
begin_scope();
statement("uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);");
statement("return (Base >> Offset) & Mask;");
end_scope();
statement("");
}
// In this overload, we will have to do sign-extension, which we will emulate by shifting up and down.
static const char *signed_types[] = { "int", "int2", "int3", "int4" };
for (auto &type : signed_types)
{
statement(type, " SPIRV_Cross_bitfieldSExtract(", type, " Base, int Offset, int Count)");
begin_scope();
statement("int Mask = Count == 32 ? -1 : ((1 << Count) - 1);");
statement(type, " Masked = (Base >> Offset) & Mask;");
statement("int ExtendShift = (32 - Count) & 31;");
statement("return (Masked << ExtendShift) >> ExtendShift;");
end_scope();
statement("");
}
}
}
string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index)
@ -2391,6 +2433,14 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
case GLSLstd450UnpackDouble2x32:
SPIRV_CROSS_THROW("packDouble2x32/unpackDouble2x32 not supported in HLSL.");
case GLSLstd450FindILsb:
emit_unary_func_op(result_type, id, args[0], "firstbitlow");
break;
case GLSLstd450FindSMsb:
case GLSLstd450FindUMsb:
emit_unary_func_op(result_type, id, args[0], "firstbithigh");
break;
default:
CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
break;
@ -3297,6 +3347,53 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
break;
}
case OpBitFieldInsert:
{
if (!requires_bitfield_insert)
{
requires_bitfield_insert = true;
force_recompile = true;
}
auto expr = join("SPIRV_Cross_bitfieldInsert(",
to_expression(ops[2]), ", ",
to_expression(ops[3]), ", ",
to_expression(ops[4]), ", ",
to_expression(ops[5]), ")");
bool forward = should_forward(ops[2]) && should_forward(ops[3]) &&
should_forward(ops[4]) && should_forward(ops[5]);
auto &restype = get<SPIRType>(ops[0]);
expr = bitcast_expression(restype, SPIRType::UInt, expr);
emit_op(ops[0], ops[1], expr, forward);
break;
}
case OpBitFieldSExtract:
case OpBitFieldUExtract:
{
if (!requires_bitfield_extract)
{
requires_bitfield_extract = true;
force_recompile = true;
}
if (opcode == OpBitFieldSExtract)
TFOP(SPIRV_Cross_bitfieldSExtract);
else
TFOP(SPIRV_Cross_bitfieldUExtract);
break;
}
case OpBitCount:
UFOP(countbits);
break;
case OpBitReverse:
UFOP(reversebits);
break;
default:
CompilerGLSL::emit_instruction(instruction);
break;

View File

@ -121,6 +121,8 @@ private:
bool requires_snorm8_packing = false;
bool requires_unorm16_packing = false;
bool requires_snorm16_packing = false;
bool requires_bitfield_insert = false;
bool requires_bitfield_extract = false;
uint64_t required_textureSizeVariants = 0;
void require_texture_query_variant(const SPIRType &type);