Add 8-bit/16-bit transform feedback support for future use

This commit is contained in:
Rex Xu 2019-01-21 16:50:17 +08:00
parent dc2d5673a1
commit eaf31ab98c
8 changed files with 288 additions and 9 deletions

View File

@ -39,9 +39,9 @@ ERROR: 0:131: 'xfb_stride' : all stride settings must match for xfb buffer 3
ERROR: 0:152: 'xfb_offset' : overlapping offsets at offset 64 in buffer 0
ERROR: 0:157: 'xfb_buffer' : buffer is too large: gl_MaxTransformFeedbackBuffers is 4
ERROR: 0:158: 'xfb_offset' : must be a multiple of size of first component
ERROR: 0:159: 'xfb_offset' : type contains double; xfb_offset must be a multiple of 8
ERROR: 0:159: 'xfb_offset' : type contains double or 64-bit integer; xfb_offset must be a multiple of 8
ERROR: 0:161: 'xfb_offset' : must be a multiple of size of first component
ERROR: 0:162: 'xfb_offset' : type contains double; xfb_offset must be a multiple of 8
ERROR: 0:162: 'xfb_offset' : type contains double or 64-bit integer; xfb_offset must be a multiple of 8
ERROR: 0:166: 'xfb_buffer' : buffer is too large: gl_MaxTransformFeedbackBuffers is 4
ERROR: 0:169: 'xfb_buffer' : buffer is too large: gl_MaxTransformFeedbackBuffers is 4
ERROR: 0:169: 'xfb_stride' : 1/4 stride is too large: gl_MaxTransformFeedbackInterleavedComponents is 64

View File

@ -0,0 +1,120 @@
spv.16bitxfb.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 59
Capability Shader
Capability Float16
Capability Int16
Capability TransformFeedback
Capability StorageInputOutput16
Extension "SPV_KHR_16bit_storage"
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 9 12 18 36 39 46 49
ExecutionMode 4 Xfb
Source GLSL 450
SourceExtension "GL_AMD_gpu_shader_half_float"
SourceExtension "GL_AMD_gpu_shader_int16"
Name 4 "main"
Name 9 "of16v3"
Name 12 "if16v4"
Name 16 "F16Out"
MemberName 16(F16Out) 0 "of16"
MemberName 16(F16Out) 1 "of16v2"
Name 18 ""
Name 36 "oi16v3"
Name 39 "ii16v4"
Name 44 "I16Out"
MemberName 44(I16Out) 0 "ou16"
MemberName 44(I16Out) 1 "ou16v2"
Name 46 ""
Name 49 "iu16v4"
Decorate 9(of16v3) Location 0
Decorate 9(of16v3) XfbBuffer 0
Decorate 9(of16v3) XfbStride 6
Decorate 9(of16v3) Offset 0
Decorate 12(if16v4) Location 0
MemberDecorate 16(F16Out) 0 Offset 0
MemberDecorate 16(F16Out) 1 Offset 2
Decorate 16(F16Out) Block
Decorate 18 Location 1
Decorate 18 XfbBuffer 1
Decorate 18 XfbStride 6
Decorate 36(oi16v3) Location 5
Decorate 36(oi16v3) XfbBuffer 2
Decorate 36(oi16v3) XfbStride 6
Decorate 36(oi16v3) Offset 0
Decorate 39(ii16v4) Location 1
MemberDecorate 44(I16Out) 0 Offset 0
MemberDecorate 44(I16Out) 1 Offset 2
Decorate 44(I16Out) Block
Decorate 46 Location 6
Decorate 46 XfbBuffer 3
Decorate 46 XfbStride 6
Decorate 49(iu16v4) Location 2
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 16
7: TypeVector 6(float16_t) 3
8: TypePointer Output 7(f16vec3)
9(of16v3): 8(ptr) Variable Output
10: TypeVector 6(float16_t) 4
11: TypePointer Input 10(f16vec4)
12(if16v4): 11(ptr) Variable Input
15: TypeVector 6(float16_t) 2
16(F16Out): TypeStruct 6(float16_t) 15(f16vec2)
17: TypePointer Output 16(F16Out)
18: 17(ptr) Variable Output
19: TypeInt 32 1
20: 19(int) Constant 0
21: TypeInt 32 0
22: 21(int) Constant 0
23: TypePointer Input 6(float16_t)
26: TypePointer Output 6(float16_t)
28: 19(int) Constant 1
31: TypePointer Output 15(f16vec2)
33: TypeInt 16 1
34: TypeVector 33(int16_t) 3
35: TypePointer Output 34(i16vec3)
36(oi16v3): 35(ptr) Variable Output
37: TypeVector 33(int16_t) 4
38: TypePointer Input 37(i16vec4)
39(ii16v4): 38(ptr) Variable Input
42: TypeInt 16 0
43: TypeVector 42(int16_t) 2
44(I16Out): TypeStruct 42(int16_t) 43(i16vec2)
45: TypePointer Output 44(I16Out)
46: 45(ptr) Variable Output
47: TypeVector 42(int16_t) 4
48: TypePointer Input 47(i16vec4)
49(iu16v4): 48(ptr) Variable Input
50: TypePointer Input 42(int16_t)
53: TypePointer Output 42(int16_t)
57: TypePointer Output 43(i16vec2)
4(main): 2 Function None 3
5: Label
13: 10(f16vec4) Load 12(if16v4)
14: 7(f16vec3) VectorShuffle 13 13 0 1 2
Store 9(of16v3) 14
24: 23(ptr) AccessChain 12(if16v4) 22
25:6(float16_t) Load 24
27: 26(ptr) AccessChain 18 20
Store 27 25
29: 10(f16vec4) Load 12(if16v4)
30: 15(f16vec2) VectorShuffle 29 29 0 1
32: 31(ptr) AccessChain 18 28
Store 32 30
40: 37(i16vec4) Load 39(ii16v4)
41: 34(i16vec3) VectorShuffle 40 40 0 1 2
Store 36(oi16v3) 41
51: 50(ptr) AccessChain 49(iu16v4) 22
52: 42(int16_t) Load 51
54: 53(ptr) AccessChain 46 20
Store 54 52
55: 47(i16vec4) Load 49(iu16v4)
56: 43(i16vec2) VectorShuffle 55 55 0 1
58: 57(ptr) AccessChain 46 28
Store 58 56
Return
FunctionEnd

33
Test/spv.16bitxfb.vert Normal file
View File

@ -0,0 +1,33 @@
#version 450 core
#extension GL_AMD_gpu_shader_half_float: enable
#extension GL_AMD_gpu_shader_int16: enable
layout(location = 0) in f16vec4 if16v4;
layout(location = 1) in i16vec4 ii16v4;
layout(location = 2) in u16vec4 iu16v4;
layout(location = 0, xfb_buffer = 0, xfb_stride = 6, xfb_offset = 0) out f16vec3 of16v3;
layout(location = 1, xfb_buffer = 1, xfb_stride = 6, xfb_offset = 0) out F16Out
{
float16_t of16;
f16vec2 of16v2;
};
layout(location = 5, xfb_buffer = 2, xfb_stride = 6, xfb_offset = 0) out i16vec3 oi16v3;
layout(location = 6, xfb_buffer = 3, xfb_stride = 6, xfb_offset = 0) out I16Out
{
uint16_t ou16;
u16vec2 ou16v2;
};
void main()
{
of16v3 = if16v4.xyz;
of16 = if16v4.x;
of16v2 = if16v4.xy;
oi16v3 = ii16v4.xyz;
ou16 = iu16v4.x;
ou16v2 = iu16v4.xy;
}

View File

@ -5463,14 +5463,23 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
// "The offset must be a multiple of the size of the first component of the first
// qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate
// containing a double, the offset must also be a multiple of 8..."
if (type.containsBasicType(EbtDouble) && ! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8))
error(loc, "type contains double; xfb_offset must be a multiple of 8", "xfb_offset", "");
// ..., if applied to an aggregate containing a float16_t, the offset must also be a multiple of 2..."
else if (type.containsBasicType(EbtFloat16) && !IsMultipleOfPow2(qualifier.layoutXfbOffset, 2))
error(loc, "type contains half float; xfb_offset must be a multiple of 2", "xfb_offset", "");
// containing a double or 64-bit integer, the offset must also be a multiple of 8..."
if ((type.containsBasicType(EbtDouble) || type.containsBasicType(EbtInt64) || type.containsBasicType(EbtUint64)) &&
! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8))
error(loc, "type contains double or 64-bit integer; xfb_offset must be a multiple of 8", "xfb_offset", "");
#ifdef AMD_EXTENSIONS
else if ((type.containsBasicType(EbtBool) || type.containsBasicType(EbtFloat) ||
type.containsBasicType(EbtInt) || type.containsBasicType(EbtUint)) &&
! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
error(loc, "must be a multiple of size of first component", "xfb_offset", "");
// ..., if applied to an aggregate containing a half float or 16-bit integer, the offset must also be a multiple of 2..."
else if ((type.containsBasicType(EbtFloat16) || type.containsBasicType(EbtInt16) || type.containsBasicType(EbtUint16)) &&
!IsMultipleOfPow2(qualifier.layoutXfbOffset, 2))
error(loc, "type contains half float or 16-bit integer; xfb_offset must be a multiple of 2", "xfb_offset", "");
#else
else if (! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
error(loc, "must be a multiple of size of first component", "xfb_offset", "");
#endif
}
if (qualifier.hasXfbStride() && qualifier.hasXfbBuffer()) {
@ -7287,12 +7296,24 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
for (unsigned int member = 0; member < typeList.size(); ++member) {
TQualifier& memberQualifier = typeList[member].type->getQualifier();
bool contains64BitType = false;
#ifdef AMD_EXTENSIONS
bool contains32BitType = false;
bool contains16BitType = false;
int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType, contains32BitType, contains16BitType);
#else
int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType);
#endif
// see if we need to auto-assign an offset to this member
if (! memberQualifier.hasXfbOffset()) {
// "if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8"
if (contains64BitType)
RoundToPow2(nextOffset, 8);
#ifdef AMD_EXTENSIONS
else if (contains32BitType)
RoundToPow2(nextOffset, 4);
else if (contains16BitType)
RoundToPow2(nextOffset, 2);
#endif
memberQualifier.layoutXfbOffset = nextOffset;
} else
nextOffset = memberQualifier.layoutXfbOffset;

View File

@ -224,6 +224,12 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
if (unit.xfbBuffers[b].contains64BitType)
xfbBuffers[b].contains64BitType = true;
#ifdef AMD_EXTENSIONS
if (unit.xfbBuffers[b].contains32BitType)
xfbBuffers[b].contains32BitType = true;
if (unit.xfbBuffers[b].contains16BitType)
xfbBuffers[b].contains16BitType = true;
#endif
// TODO: 4.4 link: enhanced layouts: compare ranges
}
@ -636,6 +642,12 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
for (size_t b = 0; b < xfbBuffers.size(); ++b) {
if (xfbBuffers[b].contains64BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 8);
#ifdef AMD_EXTENSIONS
else if (xfbBuffers[b].contains32BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 4);
else if (xfbBuffers[b].contains16BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 2);
#endif
// "It is a compile-time or link-time error to have
// any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or
@ -656,12 +668,25 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double or 64-bit integer:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
#ifdef AMD_EXTENSIONS
} else if (xfbBuffers[b].contains32BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
#else
} else if (! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
#endif
error(infoSink, "xfb_stride must be multiple of 4:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
}
#ifdef AMD_EXTENSIONS
// "If the buffer is capturing any
// outputs with half-precision or 16-bit integer components, the stride must be a multiple of 2"
else if (xfbBuffers[b].contains16BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 2)) {
error(infoSink, "xfb_stride must be multiple of 2 for buffer holding a half float or 16-bit integer:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
}
#endif
// "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
// implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) {
@ -1260,7 +1285,11 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer];
// compute the range
#ifdef AMD_EXTENSIONS
unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType, buffer.contains32BitType, buffer.contains16BitType);
#else
unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType);
#endif
buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size);
TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1);
@ -1279,9 +1308,16 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
// Recursively figure out how many bytes of xfb buffer are used by the given type.
// Return the size of type, in bytes.
// Sets contains64BitType to true if the type contains a double.
// Sets contains64BitType to true if the type contains a 64-bit data type.
#ifdef AMD_EXTENSIONS
// Sets contains32BitType to true if the type contains a 32-bit data type.
// Sets contains16BitType to true if the type contains a 16-bit data type.
// N.B. Caller must set contains64BitType, contains32BitType, and contains16BitType to false before calling.
unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const
#else
// N.B. Caller must set contains64BitType to false before calling.
unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType) const
#endif
{
// "...if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
// and the space taken in the buffer will be a multiple of 8.
@ -1294,22 +1330,44 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
// TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
assert(type.isSizedArray());
TType elementType(type, 0);
#ifdef AMD_EXTENSIONS
return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType, contains16BitType, contains16BitType);
#else
return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType);
#endif
}
if (type.isStruct()) {
unsigned int size = 0;
bool structContains64BitType = false;
#ifdef AMD_EXTENSIONS
bool structContains32BitType = false;
bool structContains16BitType = false;
#endif
for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
TType memberType(type, member);
// "... if applied to
// an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
// and the space taken in the buffer will be a multiple of 8."
bool memberContains64BitType = false;
#ifdef AMD_EXTENSIONS
bool memberContains32BitType = false;
bool memberContains16BitType = false;
int memberSize = computeTypeXfbSize(memberType, memberContains64BitType, memberContains32BitType, memberContains16BitType);
#else
int memberSize = computeTypeXfbSize(memberType, memberContains64BitType);
#endif
if (memberContains64BitType) {
structContains64BitType = true;
RoundToPow2(size, 8);
#ifdef AMD_EXTENSIONS
} else if (memberContains32BitType) {
structContains32BitType = true;
RoundToPow2(size, 4);
} else if (memberContains16BitType) {
structContains16BitType = true;
RoundToPow2(size, 2);
#endif
}
size += memberSize;
}
@ -1317,6 +1375,14 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
if (structContains64BitType) {
contains64BitType = true;
RoundToPow2(size, 8);
#ifdef AMD_EXTENSIONS
} else if (structContains32BitType) {
contains32BitType = true;
RoundToPow2(size, 4);
} else if (structContains16BitType) {
contains16BitType = true;
RoundToPow2(size, 2);
#endif
}
return size;
}
@ -1336,8 +1402,20 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
if (type.getBasicType() == EbtDouble || type.getBasicType() == EbtInt64 || type.getBasicType() == EbtUint64) {
contains64BitType = true;
return 8 * numComponents;
#ifdef AMD_EXTENSIONS
} else if (type.getBasicType() == EbtFloat16 || type.getBasicType() == EbtInt16 || type.getBasicType() == EbtUint16) {
contains16BitType = true;
return 2 * numComponents;
} else if (type.getBasicType() == EbtInt8 || type.getBasicType() == EbtUint8)
return numComponents;
else {
contains32BitType = true;
return 4 * numComponents;
}
#else
} else
return 4 * numComponents;
#endif
}
const int baseAlignmentVec4Std140 = 16;

View File

@ -149,11 +149,20 @@ struct TOffsetRange {
// Things that need to be tracked per xfb buffer.
struct TXfbBuffer {
#ifdef AMD_EXTENSIONS
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false),
contains32BitType(false), contains16BitType(false) { }
#else
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false) { }
#endif
std::vector<TRange> ranges; // byte offsets that have already been assigned
unsigned int stride;
unsigned int implicitStride;
bool contains64BitType;
#ifdef AMD_EXTENSIONS
bool contains32BitType;
bool contains16BitType;
#endif
};
// Track a set of strings describing how the module was processed.
@ -669,7 +678,11 @@ public:
}
unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
int addXfbBufferOffset(const TType&);
#ifdef AMD_EXTENSIONS
unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
#else
unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
#endif
static int getBaseAlignmentScalar(const TType&, int& size);
static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);

View File

@ -528,6 +528,7 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
Glsl, CompileVulkanToSpirvTestAMD,
::testing::ValuesIn(std::vector<std::string>({
"spv.16bitxfb.vert",
"spv.float16.frag",
"spv.float16Fetch.frag",
"spv.imageLoadStoreLod.frag",

View File

@ -8695,12 +8695,25 @@ void HlslParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
for (unsigned int member = 0; member < typeList.size(); ++member) {
TQualifier& memberQualifier = typeList[member].type->getQualifier();
bool contains64BitType = false;
#ifdef AMD_EXTENSIONS
bool contains32BitType = false;
bool contains16BitType = false;
int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType, contains32BitType, contains16BitType);
#else
int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType);
#endif
// see if we need to auto-assign an offset to this member
if (! memberQualifier.hasXfbOffset()) {
// "if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8"
if (contains64BitType)
RoundToPow2(nextOffset, 8);
#ifdef AMD_EXTENSIONS
else if (contains32BitType)
RoundToPow2(nextOffset, 4);
// "if applied to an aggregate containing a half float or 16-bit integer, the offset must also be a multiple of 2"
else if (contains16BitType)
RoundToPow2(nextOffset, 2);
#endif
memberQualifier.layoutXfbOffset = nextOffset;
} else
nextOffset = memberQualifier.layoutXfbOffset;