GL_EXT_buffer_reference
This commit is contained in:
parent
6eab476e5a
commit
9f2aec49e9
55 changed files with 3093 additions and 103 deletions
|
|
@ -354,6 +354,11 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
|
|||
if (variable->getType().getQualifier().isIo())
|
||||
intermediate.addIoAccessed(*string);
|
||||
|
||||
if (variable->getType().getBasicType() == EbtReference &&
|
||||
variable->getType().getQualifier().isMemory()) {
|
||||
intermediate.setUseVulkanMemoryModel();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
@ -811,8 +816,12 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||
if (base->getType().getQualifier().isSpecConstant())
|
||||
result->getWritableType().getQualifier().makeSpecConstant();
|
||||
}
|
||||
} else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
|
||||
const TTypeList* fields = base->getType().getStruct();
|
||||
} else if (base->getBasicType() == EbtStruct ||
|
||||
base->getBasicType() == EbtBlock ||
|
||||
base->getBasicType() == EbtReference) {
|
||||
const TTypeList* fields = base->getBasicType() == EbtReference ?
|
||||
base->getType().getReferentType()->getStruct() :
|
||||
base->getType().getStruct();
|
||||
bool fieldFound = false;
|
||||
int member;
|
||||
for (member = 0; member < (int)fields->size(); ++member) {
|
||||
|
|
@ -2386,6 +2395,10 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
|
|||
}
|
||||
}
|
||||
|
||||
if (binaryNode && binaryNode->getOp() == EOpIndexDirectStruct &&
|
||||
binaryNode->getLeft()->getBasicType() == EbtReference)
|
||||
return false;
|
||||
|
||||
// Let the base class check errors
|
||||
if (TParseContextBase::lValueErrorCheck(loc, op, node))
|
||||
return true;
|
||||
|
|
@ -3096,13 +3109,17 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
|
|||
if (! symbolTable.atGlobalLevel())
|
||||
return;
|
||||
|
||||
if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
|
||||
error(loc, "memory qualifiers cannot be used on this type", "", "");
|
||||
} else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
|
||||
error(loc, "memory qualifiers cannot be used on this type", "", "");
|
||||
if (!(publicType.userDef && publicType.userDef->getBasicType() == EbtReference)) {
|
||||
if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
|
||||
error(loc, "memory qualifiers cannot be used on this type", "", "");
|
||||
} else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
|
||||
error(loc, "memory qualifiers cannot be used on this type", "", "");
|
||||
}
|
||||
}
|
||||
|
||||
if (qualifier.storage == EvqBuffer && publicType.basicType != EbtBlock)
|
||||
if (qualifier.storage == EvqBuffer &&
|
||||
publicType.basicType != EbtBlock &&
|
||||
!qualifier.layoutBufferReference)
|
||||
error(loc, "buffers can be declared only as blocks", "buffer", "");
|
||||
|
||||
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
|
||||
|
|
@ -3760,6 +3777,21 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType
|
|||
if (isRuntimeLength(base))
|
||||
return;
|
||||
|
||||
// Check for last member of a bufferreference type, which is runtime sizeable
|
||||
// but doesn't support runtime length
|
||||
if (base.getType().getQualifier().storage == EvqBuffer) {
|
||||
const TIntermBinary* binary = base.getAsBinaryNode();
|
||||
if (binary != nullptr &&
|
||||
binary->getOp() == EOpIndexDirectStruct &&
|
||||
binary->getLeft()->getBasicType() == EbtReference) {
|
||||
|
||||
const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
const int memberCount = (int)binary->getLeft()->getType().getReferentType()->getStruct()->size();
|
||||
if (index == memberCount - 1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check for additional things allowed by GL_EXT_nonuniform_qualifier
|
||||
if (base.getBasicType() == EbtSampler ||
|
||||
(base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer()))
|
||||
|
|
@ -3777,6 +3809,10 @@ bool TParseContext::isRuntimeLength(const TIntermTyped& base) const
|
|||
if (binary != nullptr && binary->getOp() == EOpIndexDirectStruct) {
|
||||
// is it the last member?
|
||||
const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
|
||||
if (binary->getLeft()->getBasicType() == EbtReference)
|
||||
return false;
|
||||
|
||||
const int memberCount = (int)binary->getLeft()->getType().getStruct()->size();
|
||||
if (index == memberCount - 1)
|
||||
return true;
|
||||
|
|
@ -4655,6 +4691,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
publicType.qualifier.layoutPushConstant = true;
|
||||
return;
|
||||
}
|
||||
if (id == "buffer_reference") {
|
||||
requireVulkan(loc, "buffer_reference");
|
||||
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference");
|
||||
publicType.qualifier.layoutBufferReference = true;
|
||||
intermediate.setUseStorageBuffer();
|
||||
intermediate.setUsePhysicalStorageBuffer();
|
||||
return;
|
||||
}
|
||||
if (language == EShLangGeometry || language == EShLangTessEvaluation
|
||||
#ifdef NV_EXTENSIONS
|
||||
|| language == EShLangMeshNV
|
||||
|
|
@ -5013,6 +5057,15 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
}
|
||||
#endif
|
||||
|
||||
if (id == "buffer_reference_align") {
|
||||
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference_align");
|
||||
if (! IsPow2(value))
|
||||
error(loc, "must be a power of 2", "buffer_reference_align", "");
|
||||
else
|
||||
publicType.qualifier.layoutBufferReferenceAlign = std::log2(value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (language) {
|
||||
case EShLangVertex:
|
||||
break;
|
||||
|
|
@ -5177,6 +5230,9 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
|
|||
if (src.hasAlign())
|
||||
dst.layoutAlign = src.layoutAlign;
|
||||
|
||||
if (src.hasBufferReferenceAlign())
|
||||
dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign;
|
||||
|
||||
if (! inheritOnly) {
|
||||
if (src.hasLocation())
|
||||
dst.layoutLocation = src.layoutLocation;
|
||||
|
|
@ -5205,6 +5261,9 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
|
|||
if (src.layoutPushConstant)
|
||||
dst.layoutPushConstant = true;
|
||||
|
||||
if (src.layoutBufferReference)
|
||||
dst.layoutBufferReference = true;
|
||||
|
||||
#ifdef NV_EXTENSIONS
|
||||
if (src.layoutPassthrough)
|
||||
dst.layoutPassthrough = true;
|
||||
|
|
@ -5452,7 +5511,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
#ifdef NV_EXTENSIONS
|
||||
!qualifier.layoutShaderRecordNV &&
|
||||
#endif
|
||||
!qualifier.layoutAttachment)
|
||||
!qualifier.layoutAttachment &&
|
||||
!qualifier.layoutBufferReference)
|
||||
error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", "");
|
||||
else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler)
|
||||
error(loc, "sampler/texture/image requires layout(binding=X)", "binding", "");
|
||||
|
|
@ -5504,6 +5564,9 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
|
||||
error(loc, "can only be used with a block", "push_constant", "");
|
||||
|
||||
if (qualifier.layoutBufferReference && type.getBasicType() != EbtBlock)
|
||||
error(loc, "can only be used with a block", "buffer_reference", "");
|
||||
|
||||
#ifdef NV_EXTENSIONS
|
||||
if (qualifier.layoutShaderRecordNV && type.getBasicType() != EbtBlock)
|
||||
error(loc, "can only be used with a block", "shaderRecordNV", "");
|
||||
|
|
@ -5644,6 +5707,10 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|||
if (qualifier.hasSet())
|
||||
error(loc, "cannot be used with push_constant", "set", "");
|
||||
}
|
||||
if (qualifier.layoutBufferReference) {
|
||||
if (qualifier.storage != EvqBuffer)
|
||||
error(loc, "can only be used with buffer", "buffer_reference", "");
|
||||
}
|
||||
#ifdef NV_EXTENSIONS
|
||||
if (qualifier.layoutShaderRecordNV) {
|
||||
if (qualifier.storage != EvqBuffer)
|
||||
|
|
@ -6051,7 +6118,7 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType
|
|||
return;
|
||||
}
|
||||
|
||||
if (publicType.qualifier.hasLayout())
|
||||
if (publicType.qualifier.hasLayout() && !publicType.qualifier.layoutBufferReference)
|
||||
warn(loc, "useless application of layout qualifier", "layout", "");
|
||||
}
|
||||
|
||||
|
|
@ -6659,10 +6726,15 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
|
|||
basicOp = EOpConstructInt64;
|
||||
break;
|
||||
|
||||
case EOpConstructUint64:
|
||||
if (type.isScalar() && node->getType().getBasicType() == EbtReference) {
|
||||
TIntermUnary* newNode = intermediate.addUnaryNode(EOpConvPtrToUint64, node, node->getLoc(), type);
|
||||
return newNode;
|
||||
}
|
||||
// fall through
|
||||
case EOpConstructU64Vec2:
|
||||
case EOpConstructU64Vec3:
|
||||
case EOpConstructU64Vec4:
|
||||
case EOpConstructUint64:
|
||||
basicOp = EOpConstructUint64;
|
||||
break;
|
||||
|
||||
|
|
@ -6678,6 +6750,19 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
|
|||
return node;
|
||||
break;
|
||||
|
||||
case EOpConstructReference:
|
||||
// construct reference from reference
|
||||
if (node->getType().getBasicType() == EbtReference) {
|
||||
newNode = intermediate.addUnaryNode(EOpConstructReference, node, node->getLoc(), type);
|
||||
return newNode;
|
||||
// construct reference from uint64
|
||||
} else if (node->getType().isScalar() && node->getType().getBasicType() == EbtUint64) {
|
||||
TIntermUnary* newNode = intermediate.addUnaryNode(EOpConvUint64ToPtr, node, node->getLoc(), type);
|
||||
return newNode;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
default:
|
||||
error(loc, "unsupported construction", "", "");
|
||||
|
||||
|
|
@ -6922,31 +7007,57 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
else
|
||||
ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
|
||||
|
||||
//
|
||||
// Don't make a user-defined type out of block name; that will cause an error
|
||||
// if the same block name gets reused in a different interface.
|
||||
//
|
||||
// "Block names have no other use within a shader
|
||||
// beyond interface matching; it is a compile-time error to use a block name at global scope for anything
|
||||
// other than as a block name (e.g., use of a block name for a global variable name or function name is
|
||||
// currently reserved)."
|
||||
//
|
||||
// Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
|
||||
// whose type is EbtBlock, but without all the structure; that will come from the type
|
||||
// the instances point to.
|
||||
//
|
||||
TType blockNameType(EbtBlock, blockType.getQualifier().storage);
|
||||
TVariable* blockNameVar = new TVariable(blockName, blockNameType);
|
||||
if (! symbolTable.insert(*blockNameVar)) {
|
||||
TSymbol* existingName = symbolTable.find(*blockName);
|
||||
if (existingName->getType().getBasicType() == EbtBlock) {
|
||||
if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
|
||||
error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
|
||||
if (currentBlockQualifier.layoutBufferReference) {
|
||||
|
||||
if (currentBlockQualifier.storage != EvqBuffer)
|
||||
error(loc, "can only be used with buffer", "buffer_reference", "");
|
||||
|
||||
// Create the block reference type. If it was forward-declared, detect that
|
||||
// as a referent struct type with no members. Replace the referent type with
|
||||
// blockType.
|
||||
TType blockNameType(EbtReference, blockType, *blockName);
|
||||
TVariable* blockNameVar = new TVariable(blockName, blockNameType, true);
|
||||
if (! symbolTable.insert(*blockNameVar)) {
|
||||
TSymbol* existingName = symbolTable.find(*blockName);
|
||||
if (existingName->getType().getBasicType() == EbtReference &&
|
||||
existingName->getType().getReferentType()->getStruct() &&
|
||||
existingName->getType().getReferentType()->getStruct()->size() == 0 &&
|
||||
existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
|
||||
existingName->getType().getReferentType()->deepCopy(blockType);
|
||||
} else {
|
||||
error(loc, "block name cannot be redefined", blockName->c_str(), "");
|
||||
}
|
||||
}
|
||||
if (!instanceName) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Don't make a user-defined type out of block name; that will cause an error
|
||||
// if the same block name gets reused in a different interface.
|
||||
//
|
||||
// "Block names have no other use within a shader
|
||||
// beyond interface matching; it is a compile-time error to use a block name at global scope for anything
|
||||
// other than as a block name (e.g., use of a block name for a global variable name or function name is
|
||||
// currently reserved)."
|
||||
//
|
||||
// Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
|
||||
// whose type is EbtBlock, but without all the structure; that will come from the type
|
||||
// the instances point to.
|
||||
//
|
||||
TType blockNameType(EbtBlock, blockType.getQualifier().storage);
|
||||
TVariable* blockNameVar = new TVariable(blockName, blockNameType);
|
||||
if (! symbolTable.insert(*blockNameVar)) {
|
||||
TSymbol* existingName = symbolTable.find(*blockName);
|
||||
if (existingName->getType().getBasicType() == EbtBlock) {
|
||||
if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
|
||||
error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7246,6 +7357,22 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ
|
|||
void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier)
|
||||
{
|
||||
TSymbol* symbol = symbolTable.find(identifier);
|
||||
|
||||
// A forward declaration of a block reference looks to the grammar like adding
|
||||
// a qualifier to an existing symbol. Detect this and create the block reference
|
||||
// type with an empty type list, which will be filled in later in
|
||||
// TParseContext::declareBlock.
|
||||
if (!symbol && qualifier.layoutBufferReference) {
|
||||
TTypeList typeList;
|
||||
TType blockType(&typeList, identifier, qualifier);;
|
||||
TType blockNameType(EbtReference, blockType, identifier);
|
||||
TVariable* blockNameVar = new TVariable(&identifier, blockNameType, true);
|
||||
if (! symbolTable.insert(*blockNameVar)) {
|
||||
error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (! symbol) {
|
||||
error(loc, "identifier not previously declared", identifier.c_str(), "");
|
||||
return;
|
||||
|
|
@ -7580,6 +7707,8 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
|
||||
if (qualifier.layoutPushConstant)
|
||||
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
|
||||
if (qualifier.layoutBufferReference)
|
||||
error(loc, "cannot declare a default, can only be used on a block", "buffer_reference", "");
|
||||
if (qualifier.hasSpecConstantId())
|
||||
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
|
||||
#ifdef NV_EXTENSIONS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue