Add support for GL_EXT_buffer_reference2
This commit is contained in:
parent
86c72c9486
commit
758c93364c
12 changed files with 553 additions and 61 deletions
|
|
@ -119,6 +119,62 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
|
|||
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
|
||||
return nullptr;
|
||||
|
||||
// Convert "reference +/- int" and "reference - reference" to integer math
|
||||
if ((op == EOpAdd || op == EOpSub) && extensionRequested(E_GL_EXT_buffer_reference2)) {
|
||||
|
||||
// No addressing math on struct with unsized array.
|
||||
if ((left->getBasicType() == EbtReference && left->getType().getReferentType()->containsUnsizedArray()) ||
|
||||
(right->getBasicType() == EbtReference && right->getType().getReferentType()->containsUnsizedArray())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (left->getBasicType() == EbtReference && isTypeInt(right->getBasicType())) {
|
||||
const TType& referenceType = left->getType();
|
||||
TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
|
||||
left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
|
||||
|
||||
right = createConversion(EbtInt64, right);
|
||||
right = addBinaryMath(EOpMul, right, size, loc);
|
||||
|
||||
TIntermTyped *node = addBinaryMath(op, left, right, loc);
|
||||
node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (op == EOpAdd && right->getBasicType() == EbtReference && isTypeInt(left->getBasicType())) {
|
||||
const TType& referenceType = right->getType();
|
||||
TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true);
|
||||
right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
|
||||
|
||||
left = createConversion(EbtInt64, left);
|
||||
left = addBinaryMath(EOpMul, left, size, loc);
|
||||
|
||||
TIntermTyped *node = addBinaryMath(op, left, right, loc);
|
||||
node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (op == EOpSub && left->getBasicType() == EbtReference && right->getBasicType() == EbtReference) {
|
||||
TIntermConstantUnion* size = addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
|
||||
|
||||
left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
|
||||
right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
|
||||
|
||||
left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
|
||||
right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
|
||||
|
||||
left = addBinaryMath(EOpSub, left, right, loc);
|
||||
|
||||
TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc);
|
||||
return node;
|
||||
}
|
||||
|
||||
// No other math operators supported on references
|
||||
if (left->getBasicType() == EbtReference || right->getBasicType() == EbtReference) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Try converting the children's base types to compatible types.
|
||||
auto children = addConversion(op, left, right);
|
||||
left = std::get<0>(children);
|
||||
|
|
@ -231,6 +287,26 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm
|
|||
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
|
||||
return nullptr;
|
||||
|
||||
// Convert "reference += int" to "reference = reference + int". We need this because the
|
||||
// "reference + int" calculation involves a cast back to the original type, which makes it
|
||||
// not an lvalue.
|
||||
if ((op == EOpAddAssign || op == EOpSubAssign) && left->getBasicType() == EbtReference &&
|
||||
extensionRequested(E_GL_EXT_buffer_reference2)) {
|
||||
|
||||
if (!(right->getType().isScalar() && right->getType().isIntegerDomain()))
|
||||
return nullptr;
|
||||
|
||||
TIntermTyped* node = addBinaryMath(op == EOpAddAssign ? EOpAdd : EOpSub, left, right, loc);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
TIntermSymbol* symbol = left->getAsSymbolNode();
|
||||
left = addSymbol(*symbol);
|
||||
|
||||
node = addAssign(EOpAssign, left, node, loc);
|
||||
return node;
|
||||
}
|
||||
|
||||
//
|
||||
// Like adding binary math, except the conversion can only go
|
||||
// from right to left.
|
||||
|
|
|
|||
|
|
@ -377,7 +377,8 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||
// basic type checks...
|
||||
variableCheck(base);
|
||||
|
||||
if (! base->isArray() && ! base->isMatrix() && ! base->isVector() && ! base->getType().isCoopMat()) {
|
||||
if (! base->isArray() && ! base->isMatrix() && ! base->isVector() && ! base->getType().isCoopMat() &&
|
||||
base->getBasicType() != EbtReference) {
|
||||
if (base->getAsSymbolNode())
|
||||
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
|
||||
else
|
||||
|
|
@ -405,6 +406,14 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||
|
||||
// at least one of base and index is not a front-end constant variable...
|
||||
TIntermTyped* result = nullptr;
|
||||
|
||||
if (base->getBasicType() == EbtReference && ! base->isArray()) {
|
||||
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing");
|
||||
result = intermediate.addBinaryMath(EOpAdd, base, index, loc);
|
||||
result->setType(base->getType());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (index->getQualifier().isFrontEndConstant())
|
||||
checkIndex(loc, base->getType(), indexValue);
|
||||
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ void TParseVersions::initializeExtensionBehavior()
|
|||
extensionBehavior[E_GL_EXT_scalar_block_layout] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_fragment_invocation_density] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_buffer_reference] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_buffer_reference2] = EBhDisable;
|
||||
|
||||
extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable;
|
||||
|
|
@ -389,6 +390,7 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||
"#define GL_EXT_scalar_block_layout 1\n"
|
||||
"#define GL_EXT_fragment_invocation_density 1\n"
|
||||
"#define GL_EXT_buffer_reference 1\n"
|
||||
"#define GL_EXT_buffer_reference2 1\n"
|
||||
|
||||
// GL_KHR_shader_subgroup
|
||||
"#define GL_KHR_shader_subgroup_basic 1\n"
|
||||
|
|
@ -808,6 +810,8 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co
|
|||
else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0)
|
||||
updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
|
||||
#endif
|
||||
else if (strcmp(extension, "GL_EXT_buffer_reference2") == 0)
|
||||
updateExtensionBehavior(line, "GL_EXT_buffer_reference", behaviorString);
|
||||
}
|
||||
|
||||
void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
|
||||
|
|
|
|||
1
glslang/MachineIndependent/Versions.h
Executable file → Normal file
1
glslang/MachineIndependent/Versions.h
Executable file → Normal file
|
|
@ -171,6 +171,7 @@ const char* const E_GL_EXT_samplerless_texture_functions = "GL_EXT_samplerles
|
|||
const char* const E_GL_EXT_scalar_block_layout = "GL_EXT_scalar_block_layout";
|
||||
const char* const E_GL_EXT_fragment_invocation_density = "GL_EXT_fragment_invocation_density";
|
||||
const char* const E_GL_EXT_buffer_reference = "GL_EXT_buffer_reference";
|
||||
const char* const E_GL_EXT_buffer_reference2 = "GL_EXT_buffer_reference2";
|
||||
|
||||
// Arrays of extensions for the above viewportEXTs duplications
|
||||
|
||||
|
|
|
|||
70
glslang/MachineIndependent/linkValidate.cpp
Executable file → Normal file
70
glslang/MachineIndependent/linkValidate.cpp
Executable file → Normal file
|
|
@ -1683,4 +1683,74 @@ int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride,
|
|||
}
|
||||
}
|
||||
|
||||
// shared calculation by getOffset and getOffsets
|
||||
void TIntermediate::updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize)
|
||||
{
|
||||
int dummyStride;
|
||||
|
||||
// modify just the children's view of matrix layout, if there is one for this member
|
||||
TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix;
|
||||
int memberAlignment = getMemberAlignment(memberType, memberSize, dummyStride,
|
||||
parentType.getQualifier().layoutPacking,
|
||||
subMatrixLayout != ElmNone
|
||||
? subMatrixLayout == ElmRowMajor
|
||||
: parentType.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
RoundToPow2(offset, memberAlignment);
|
||||
}
|
||||
|
||||
// Lookup or calculate the offset of a block member, using the recursively
|
||||
// defined block offset rules.
|
||||
int TIntermediate::getOffset(const TType& type, int index)
|
||||
{
|
||||
const TTypeList& memberList = *type.getStruct();
|
||||
|
||||
// Don't calculate offset if one is present, it could be user supplied
|
||||
// and different than what would be calculated. That is, this is faster,
|
||||
// but not just an optimization.
|
||||
if (memberList[index].type->getQualifier().hasOffset())
|
||||
return memberList[index].type->getQualifier().layoutOffset;
|
||||
|
||||
int memberSize = 0;
|
||||
int offset = 0;
|
||||
for (int m = 0; m <= index; ++m) {
|
||||
updateOffset(type, *memberList[m].type, offset, memberSize);
|
||||
|
||||
if (m < index)
|
||||
offset += memberSize;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Calculate the block data size.
|
||||
// Block arrayness is not taken into account, each element is backed by a separate buffer.
|
||||
int TIntermediate::getBlockSize(const TType& blockType)
|
||||
{
|
||||
const TTypeList& memberList = *blockType.getStruct();
|
||||
int lastIndex = (int)memberList.size() - 1;
|
||||
int lastOffset = getOffset(blockType, lastIndex);
|
||||
|
||||
int lastMemberSize;
|
||||
int dummyStride;
|
||||
getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
|
||||
blockType.getQualifier().layoutPacking,
|
||||
blockType.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
|
||||
return lastOffset + lastMemberSize;
|
||||
}
|
||||
|
||||
int TIntermediate::computeBufferReferenceTypeSize(const TType& type)
|
||||
{
|
||||
assert(type.getBasicType() == EbtReference);
|
||||
int size = getBlockSize(*type.getReferentType());
|
||||
|
||||
int align = type.getBufferReferenceAlignment();
|
||||
|
||||
if (align) {
|
||||
size = (size + align - 1) & ~(align-1);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
|
|
|||
|
|
@ -696,6 +696,10 @@ public:
|
|||
static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
|
||||
static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
|
||||
static bool improperStraddle(const TType& type, int size, int offset);
|
||||
static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
|
||||
static int getOffset(const TType& type, int index);
|
||||
static int getBlockSize(const TType& blockType);
|
||||
static int computeBufferReferenceTypeSize(const TType&);
|
||||
bool promote(TIntermOperator*);
|
||||
|
||||
#ifdef NV_EXTENSIONS
|
||||
|
|
|
|||
|
|
@ -143,45 +143,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// shared calculation by getOffset and getOffsets
|
||||
void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize)
|
||||
{
|
||||
int dummyStride;
|
||||
|
||||
// modify just the children's view of matrix layout, if there is one for this member
|
||||
TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix;
|
||||
int memberAlignment = intermediate.getMemberAlignment(memberType, memberSize, dummyStride,
|
||||
parentType.getQualifier().layoutPacking,
|
||||
subMatrixLayout != ElmNone
|
||||
? subMatrixLayout == ElmRowMajor
|
||||
: parentType.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
RoundToPow2(offset, memberAlignment);
|
||||
}
|
||||
|
||||
// Lookup or calculate the offset of a block member, using the recursively
|
||||
// defined block offset rules.
|
||||
int getOffset(const TType& type, int index)
|
||||
{
|
||||
const TTypeList& memberList = *type.getStruct();
|
||||
|
||||
// Don't calculate offset if one is present, it could be user supplied
|
||||
// and different than what would be calculated. That is, this is faster,
|
||||
// but not just an optimization.
|
||||
if (memberList[index].type->getQualifier().hasOffset())
|
||||
return memberList[index].type->getQualifier().layoutOffset;
|
||||
|
||||
int memberSize = 0;
|
||||
int offset = 0;
|
||||
for (int m = 0; m <= index; ++m) {
|
||||
updateOffset(type, *memberList[m].type, offset, memberSize);
|
||||
|
||||
if (m < index)
|
||||
offset += memberSize;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Lookup or calculate the offset of all block members at once, using the recursively
|
||||
// defined block offset rules.
|
||||
void getOffsets(const TType& type, TVector<int>& offsets)
|
||||
|
|
@ -196,7 +157,7 @@ public:
|
|||
offset = memberList[m].type->getQualifier().layoutOffset;
|
||||
|
||||
// calculate the offset of the next member and align the current offset to this member
|
||||
updateOffset(type, *memberList[m].type, offset, memberSize);
|
||||
intermediate.updateOffset(type, *memberList[m].type, offset, memberSize);
|
||||
|
||||
// save the offset of this member
|
||||
offsets[m] = offset;
|
||||
|
|
@ -226,23 +187,6 @@ public:
|
|||
return stride;
|
||||
}
|
||||
|
||||
// Calculate the block data size.
|
||||
// Block arrayness is not taken into account, each element is backed by a separate buffer.
|
||||
int getBlockSize(const TType& blockType)
|
||||
{
|
||||
const TTypeList& memberList = *blockType.getStruct();
|
||||
int lastIndex = (int)memberList.size() - 1;
|
||||
int lastOffset = getOffset(blockType, lastIndex);
|
||||
|
||||
int lastMemberSize;
|
||||
int dummyStride;
|
||||
intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
|
||||
blockType.getQualifier().layoutPacking,
|
||||
blockType.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
|
||||
return lastOffset + lastMemberSize;
|
||||
}
|
||||
|
||||
// count the total number of leaf members from iterating out of a block type
|
||||
int countAggregateMembers(const TType& parentType)
|
||||
{
|
||||
|
|
@ -349,7 +293,7 @@ public:
|
|||
case EOpIndexDirectStruct:
|
||||
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (offset >= 0)
|
||||
offset += getOffset(visitNode->getLeft()->getType(), index);
|
||||
offset += intermediate.getOffset(visitNode->getLeft()->getType(), index);
|
||||
if (name.size() > 0)
|
||||
name.append(".");
|
||||
name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
|
||||
|
|
@ -592,10 +536,10 @@ public:
|
|||
assert(! anonymous);
|
||||
for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
|
||||
blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
|
||||
getBlockSize(base->getType()));
|
||||
intermediate.getBlockSize(base->getType()));
|
||||
baseName.append(TString("[0]"));
|
||||
} else
|
||||
blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
|
||||
blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType()));
|
||||
|
||||
if (reflection.options & EShReflectionAllBlockVariables) {
|
||||
// Use a degenerate (empty) set of dereferences to immediately put as at the end of
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue