GL_EXT_buffer_reference
This commit is contained in:
@@ -40,5 +40,6 @@ static const char* const E_SPV_KHR_8bit_storage = "SPV_KHR_8bit_
|
||||
static const char* const E_SPV_KHR_storage_buffer_storage_class = "SPV_KHR_storage_buffer_storage_class";
|
||||
static const char* const E_SPV_KHR_post_depth_coverage = "SPV_KHR_post_depth_coverage";
|
||||
static const char* const E_SPV_KHR_vulkan_memory_model = "SPV_KHR_vulkan_memory_model";
|
||||
static const char* const E_SPV_EXT_physical_storage_buffer = "SPV_EXT_physical_storage_buffer";
|
||||
|
||||
#endif // #ifndef GLSLextKHR_H
|
||||
|
||||
@@ -145,9 +145,9 @@ protected:
|
||||
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
|
||||
spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
|
||||
void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
|
||||
spv::Id convertGlslangToSpvType(const glslang::TType& type);
|
||||
spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
|
||||
spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
|
||||
bool lastBufferBlockMember);
|
||||
bool lastBufferBlockMember, bool forwardReferenceOnly = false);
|
||||
bool filterMember(const glslang::TType& member);
|
||||
spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
|
||||
glslang::TLayoutPacking, const glslang::TQualifier&);
|
||||
@@ -211,6 +211,15 @@ protected:
|
||||
builder.addExtension(ext);
|
||||
}
|
||||
|
||||
unsigned int getBufferReferenceAlignment(const glslang::TType &type) const {
|
||||
if (type.getBasicType() == glslang::EbtReference) {
|
||||
return type.getReferentType()->getQualifier().hasBufferReferenceAlign() ?
|
||||
(1u << type.getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
glslang::SpvOptions& options;
|
||||
spv::Function* shaderEntry;
|
||||
spv::Function* currentFunction;
|
||||
@@ -237,6 +246,8 @@ protected:
|
||||
std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper;
|
||||
std::stack<bool> breakForLoop; // false means break for switch
|
||||
std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
|
||||
// Map pointee types for EbtReference to their forward pointers
|
||||
std::map<const glslang::TType *, spv::Id> forwardPointers;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -1303,12 +1314,22 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
|
||||
builder.addInclude(iItr->first, iItr->second);
|
||||
}
|
||||
stdBuiltins = builder.import("GLSL.std.450");
|
||||
|
||||
spv::AddressingModel addressingModel = spv::AddressingModelLogical;
|
||||
spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;
|
||||
|
||||
if (glslangIntermediate->usingPhysicalStorageBuffer()) {
|
||||
addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
|
||||
builder.addExtension(spv::E_SPV_EXT_physical_storage_buffer);
|
||||
builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
|
||||
};
|
||||
if (glslangIntermediate->usingVulkanMemoryModel()) {
|
||||
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelVulkanKHR);
|
||||
memoryModel = spv::MemoryModelVulkanKHR;
|
||||
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
||||
builder.addExtension(spv::E_SPV_KHR_vulkan_memory_model);
|
||||
} else {
|
||||
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
}
|
||||
builder.setMemoryModel(addressingModel, memoryModel);
|
||||
|
||||
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
|
||||
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
|
||||
|
||||
@@ -1681,8 +1702,24 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
// so short circuit the access-chain stuff with a swizzle.
|
||||
std::vector<unsigned> swizzle;
|
||||
swizzle.push_back(glslangIndex);
|
||||
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
|
||||
int dummySize;
|
||||
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
|
||||
TranslateCoherent(node->getLeft()->getType()),
|
||||
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
||||
} else {
|
||||
|
||||
// Load through a block reference is performed with a dot operator that
|
||||
// is mapped to EOpIndexDirectStruct. When we get to the actual reference,
|
||||
// do a load and reset the access chain.
|
||||
if (node->getLeft()->getBasicType() == glslang::EbtReference &&
|
||||
!node->getLeft()->getType().isArray() &&
|
||||
node->getOp() == glslang::EOpIndexDirectStruct)
|
||||
{
|
||||
spv::Id left = accessChainLoad(node->getLeft()->getType());
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainLValue(left);
|
||||
}
|
||||
|
||||
int spvIndex = glslangIndex;
|
||||
if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
|
||||
node->getOp() == glslang::EOpIndexDirectStruct)
|
||||
@@ -1695,7 +1732,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
}
|
||||
|
||||
// normal case for indexing array or structure or block
|
||||
builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()));
|
||||
builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()), getBufferReferenceAlignment(node->getLeft()->getType()));
|
||||
|
||||
// Add capabilities here for accessing PointSize and clip/cull distance.
|
||||
// We have deferred generation of associated capabilities until now.
|
||||
@@ -1728,10 +1765,13 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
// restore the saved access chain
|
||||
builder.setAccessChain(partial);
|
||||
|
||||
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
|
||||
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()));
|
||||
else
|
||||
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()));
|
||||
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
|
||||
int dummySize;
|
||||
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
|
||||
TranslateCoherent(node->getLeft()->getType()),
|
||||
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
||||
} else
|
||||
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()), getBufferReferenceAlignment(node->getLeft()->getType()));
|
||||
}
|
||||
return false;
|
||||
case glslang::EOpVectorSwizzle:
|
||||
@@ -1739,7 +1779,10 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
node->getLeft()->traverse(this);
|
||||
std::vector<unsigned> swizzle;
|
||||
convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
|
||||
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
|
||||
int dummySize;
|
||||
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
|
||||
TranslateCoherent(node->getLeft()->getType()),
|
||||
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
||||
}
|
||||
return false;
|
||||
case glslang::EOpMatrixSwizzle:
|
||||
@@ -2178,6 +2221,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
case glslang::EOpConstructU64Vec4:
|
||||
case glslang::EOpConstructStruct:
|
||||
case glslang::EOpConstructTextureSampler:
|
||||
case glslang::EOpConstructReference:
|
||||
{
|
||||
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
||||
std::vector<spv::Id> arguments;
|
||||
@@ -2829,6 +2873,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
||||
builder.addCapability(spv::CapabilityStorageUniform16);
|
||||
break;
|
||||
case spv::StorageClassStorageBuffer:
|
||||
case spv::StorageClassPhysicalStorageBufferEXT:
|
||||
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
|
||||
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
|
||||
break;
|
||||
@@ -2910,16 +2955,17 @@ void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& nod
|
||||
// Convert from a glslang type to an SPV type, by calling into a
|
||||
// recursive version of this function. This establishes the inherited
|
||||
// layout state rooted from the top-level type.
|
||||
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
|
||||
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
|
||||
{
|
||||
return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false);
|
||||
return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
|
||||
}
|
||||
|
||||
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
|
||||
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
|
||||
// Mutually recursive with convertGlslangStructToSpvType().
|
||||
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
|
||||
glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier, bool lastBufferBlockMember)
|
||||
glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
|
||||
bool lastBufferBlockMember, bool forwardReferenceOnly)
|
||||
{
|
||||
spv::Id spvType = spv::NoResult;
|
||||
|
||||
@@ -3014,6 +3060,23 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
|
||||
}
|
||||
break;
|
||||
case glslang::EbtReference:
|
||||
{
|
||||
// Make the forward pointer, then recurse to convert the structure type, then
|
||||
// patch up the forward pointer with a real pointer type.
|
||||
if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
|
||||
spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);
|
||||
forwardPointers[type.getReferentType()] = forwardId;
|
||||
}
|
||||
spvType = forwardPointers[type.getReferentType()];
|
||||
if (!forwardReferenceOnly) {
|
||||
spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
|
||||
builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,
|
||||
forwardPointers[type.getReferentType()],
|
||||
referentType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
@@ -3121,6 +3184,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
||||
// Create a vector of struct types for SPIR-V to consume
|
||||
std::vector<spv::Id> spvMembers;
|
||||
int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
|
||||
std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
|
||||
for (int i = 0; i < (int)glslangMembers->size(); i++) {
|
||||
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
|
||||
if (glslangMember.hiddenMember()) {
|
||||
@@ -3144,8 +3208,19 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
||||
// recurse
|
||||
bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
|
||||
i == (int)glslangMembers->size() - 1;
|
||||
spvMembers.push_back(
|
||||
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember));
|
||||
|
||||
// Make forward pointers for any pointer members, and create a list of members to
|
||||
// convert to spirv types after creating the struct.
|
||||
if (glslangMember.getBasicType() == glslang::EbtReference) {
|
||||
if (forwardPointers.find(glslangMember.getReferentType()) == forwardPointers.end()) {
|
||||
deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier));
|
||||
}
|
||||
spvMembers.push_back(
|
||||
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, true));
|
||||
} else {
|
||||
spvMembers.push_back(
|
||||
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3157,6 +3232,11 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
||||
// Decorate it
|
||||
decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType);
|
||||
|
||||
for (int i = 0; i < deferredForwardPointers.size(); ++i) {
|
||||
auto it = deferredForwardPointers[i];
|
||||
convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
|
||||
}
|
||||
|
||||
return spvType;
|
||||
}
|
||||
|
||||
@@ -3320,11 +3400,15 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
|
||||
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
|
||||
coherentFlags |= TranslateCoherent(type);
|
||||
|
||||
unsigned int alignment = builder.getAccessChain().alignment;
|
||||
alignment |= getBufferReferenceAlignment(type);
|
||||
|
||||
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
|
||||
TranslateNonUniformDecoration(type.getQualifier()),
|
||||
nominalTypeId,
|
||||
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
|
||||
TranslateMemoryScope(coherentFlags));
|
||||
TranslateMemoryScope(coherentFlags),
|
||||
alignment);
|
||||
|
||||
// Need to convert to abstract types when necessary
|
||||
if (type.getBasicType() == glslang::EbtBool) {
|
||||
@@ -3383,9 +3467,12 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I
|
||||
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
|
||||
coherentFlags |= TranslateCoherent(type);
|
||||
|
||||
unsigned int alignment = builder.getAccessChain().alignment;
|
||||
alignment |= getBufferReferenceAlignment(type);
|
||||
|
||||
builder.accessChainStore(rvalue,
|
||||
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerVisibleKHRMask),
|
||||
TranslateMemoryScope(coherentFlags));
|
||||
TranslateMemoryScope(coherentFlags), alignment);
|
||||
}
|
||||
|
||||
// For storing when types match at the glslang level, but not might match at the
|
||||
@@ -3431,7 +3518,7 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id
|
||||
// set up the target storage
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainLValue(lValue);
|
||||
builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type));
|
||||
builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), getBufferReferenceAlignment(type));
|
||||
|
||||
// store the member
|
||||
multiTypeStore(glslangElementType, elementRValue);
|
||||
@@ -3451,7 +3538,7 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id
|
||||
// set up the target storage
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainLValue(lValue);
|
||||
builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type));
|
||||
builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), getBufferReferenceAlignment(type));
|
||||
|
||||
// store the member
|
||||
multiTypeStore(glslangMemberType, memberRValue);
|
||||
@@ -3638,11 +3725,22 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier,
|
||||
// Make all the functions, skeletally, without actually visiting their bodies.
|
||||
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
|
||||
{
|
||||
const auto getParamDecorations = [](std::vector<spv::Decoration>& decorations, const glslang::TType& type, bool useVulkanMemoryModel) {
|
||||
const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type, bool useVulkanMemoryModel) {
|
||||
spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
|
||||
if (paramPrecision != spv::NoPrecision)
|
||||
decorations.push_back(paramPrecision);
|
||||
TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
|
||||
if (type.getBasicType() == glslang::EbtReference) {
|
||||
// Original and non-writable params pass the pointer directly and
|
||||
// use restrict/aliased, others are stored to a pointer in Function
|
||||
// memory and use RestrictPointer/AliasedPointer.
|
||||
if (originalParam(type.getQualifier().storage, type, false) ||
|
||||
!writableParam(type.getQualifier().storage)) {
|
||||
decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrict : spv::DecorationAliased);
|
||||
} else {
|
||||
decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
|
||||
@@ -4459,7 +4557,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
spv::Builder::AccessChain::CoherentFlags flags;
|
||||
flags.clear();
|
||||
|
||||
builder.accessChainPush(builder.makeIntConstant(i), flags);
|
||||
builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
|
||||
builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1));
|
||||
}
|
||||
return builder.createCompositeExtract(res, resultType(), 0);
|
||||
@@ -5330,6 +5428,9 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
||||
unaryOp = spv::OpGroupNonUniformPartitionNV;
|
||||
break;
|
||||
#endif
|
||||
case glslang::EOpConstructReference:
|
||||
unaryOp = spv::OpBitcast;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -5782,6 +5883,12 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora
|
||||
// For normal run-time conversion instruction, use OpBitcast.
|
||||
convOp = spv::OpBitcast;
|
||||
break;
|
||||
case glslang::EOpConvUint64ToPtr:
|
||||
convOp = spv::OpConvertUToPtr;
|
||||
break;
|
||||
case glslang::EOpConvPtrToUint64:
|
||||
convOp = spv::OpConvertPtrToU;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -7247,6 +7354,10 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
|
||||
symbol->getType().getQualifier().semanticName);
|
||||
}
|
||||
|
||||
if (symbol->getBasicType() == glslang::EbtReference) {
|
||||
builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -7375,7 +7486,7 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla
|
||||
glslang::TType vectorType(glslangType, 0);
|
||||
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
||||
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
|
||||
} else if (glslangType.getStruct()) {
|
||||
} else if (glslangType.isStruct()) {
|
||||
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
||||
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
||||
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
|
||||
|
||||
@@ -194,6 +194,40 @@ Id Builder::makePointer(StorageClass storageClass, Id pointee)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeForwardPointer(StorageClass storageClass)
|
||||
{
|
||||
// Caching/uniquifying doesn't work here, because we don't know the
|
||||
// pointee type and there can be multiple forward pointers of the same
|
||||
// storage type. Somebody higher up in the stack must keep track.
|
||||
Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
|
||||
type->addImmediateOperand(storageClass);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
|
||||
type = groupedTypes[OpTypePointer][t];
|
||||
if (type->getImmediateOperand(0) == (unsigned)storageClass &&
|
||||
type->getIdOperand(1) == pointee)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
type = new Instruction(forwardPointerType, NoType, OpTypePointer);
|
||||
type->addImmediateOperand(storageClass);
|
||||
type->addIdOperand(pointee);
|
||||
groupedTypes[OpTypePointer].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeIntegerType(int width, bool hasSign)
|
||||
{
|
||||
// try to find it
|
||||
@@ -576,6 +610,7 @@ int Builder::getNumTypeConstituents(Id typeId) const
|
||||
case OpTypeBool:
|
||||
case OpTypeInt:
|
||||
case OpTypeFloat:
|
||||
case OpTypePointer:
|
||||
return 1;
|
||||
case OpTypeVector:
|
||||
case OpTypeMatrix:
|
||||
@@ -669,17 +704,36 @@ bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case OpTypePointer:
|
||||
return false;
|
||||
case OpTypeVector:
|
||||
case OpTypeMatrix:
|
||||
case OpTypeArray:
|
||||
case OpTypeRuntimeArray:
|
||||
case OpTypePointer:
|
||||
return containsType(getContainedTypeId(typeId), typeOp, width);
|
||||
default:
|
||||
return typeClass == typeOp;
|
||||
}
|
||||
}
|
||||
|
||||
// return true if the type is a pointer to PhysicalStorageBufferEXT or an
|
||||
// array of such pointers. These require restrict/aliased decorations.
|
||||
bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
|
||||
{
|
||||
const Instruction& instr = *module.getInstruction(typeId);
|
||||
|
||||
Op typeClass = instr.getOpCode();
|
||||
switch (typeClass)
|
||||
{
|
||||
case OpTypePointer:
|
||||
return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
|
||||
case OpTypeArray:
|
||||
return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// See if a scalar constant of this type has already been created, so it
|
||||
// can be reused rather than duplicated. (Required by the specification).
|
||||
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
|
||||
@@ -1252,15 +1306,39 @@ Id Builder::createUndefined(Id type)
|
||||
return inst->getResultId();
|
||||
}
|
||||
|
||||
// av/vis/nonprivate are unnecessary and illegal for some storage classes.
|
||||
spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const
|
||||
{
|
||||
switch (sc) {
|
||||
case spv::StorageClassUniform:
|
||||
case spv::StorageClassWorkgroup:
|
||||
case spv::StorageClassStorageBuffer:
|
||||
case spv::StorageClassPhysicalStorageBufferEXT:
|
||||
break;
|
||||
default:
|
||||
memoryAccess = spv::MemoryAccessMask(memoryAccess &
|
||||
~(spv::MemoryAccessMakePointerAvailableKHRMask |
|
||||
spv::MemoryAccessMakePointerVisibleKHRMask |
|
||||
spv::MemoryAccessNonPrivatePointerKHRMask));
|
||||
break;
|
||||
}
|
||||
return memoryAccess;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
|
||||
void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
|
||||
{
|
||||
Instruction* store = new Instruction(OpStore);
|
||||
store->addIdOperand(lValue);
|
||||
store->addIdOperand(rValue);
|
||||
|
||||
memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
|
||||
|
||||
if (memoryAccess != MemoryAccessMaskNone) {
|
||||
store->addImmediateOperand(memoryAccess);
|
||||
if (memoryAccess & spv::MemoryAccessAlignedMask) {
|
||||
store->addImmediateOperand(alignment);
|
||||
}
|
||||
if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
|
||||
store->addIdOperand(makeUintConstant(scope));
|
||||
}
|
||||
@@ -1270,13 +1348,18 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
|
||||
Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
|
||||
{
|
||||
Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
|
||||
load->addIdOperand(lValue);
|
||||
|
||||
memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
|
||||
|
||||
if (memoryAccess != MemoryAccessMaskNone) {
|
||||
load->addImmediateOperand(memoryAccess);
|
||||
if (memoryAccess & spv::MemoryAccessAlignedMask) {
|
||||
load->addImmediateOperand(alignment);
|
||||
}
|
||||
if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
|
||||
load->addIdOperand(makeUintConstant(scope));
|
||||
}
|
||||
@@ -2118,7 +2201,8 @@ Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sourc
|
||||
// Go through the source arguments, each one could have either
|
||||
// a single or multiple components to contribute.
|
||||
for (unsigned int i = 0; i < sources.size(); ++i) {
|
||||
if (isScalar(sources[i]))
|
||||
|
||||
if (isScalar(sources[i]) || isPointer(sources[i]))
|
||||
latchResult(sources[i]);
|
||||
else if (isVector(sources[i]))
|
||||
accumulateVectorConstituents(sources[i]);
|
||||
@@ -2433,11 +2517,15 @@ void Builder::clearAccessChain()
|
||||
accessChain.preSwizzleBaseType = NoType;
|
||||
accessChain.isRValue = false;
|
||||
accessChain.coherentFlags.clear();
|
||||
accessChain.alignment = 0;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
|
||||
void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
|
||||
{
|
||||
accessChain.coherentFlags |= coherentFlags;
|
||||
accessChain.alignment |= alignment;
|
||||
|
||||
// swizzles can be stacked in GLSL, but simplified to a single
|
||||
// one here; the base type doesn't change
|
||||
if (accessChain.preSwizzleBaseType == NoType)
|
||||
@@ -2459,7 +2547,7 @@ void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizz
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
|
||||
void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
|
||||
{
|
||||
assert(accessChain.isRValue == false);
|
||||
|
||||
@@ -2477,11 +2565,17 @@ void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, sp
|
||||
source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
|
||||
}
|
||||
|
||||
createStore(source, base, memoryAccess, scope);
|
||||
// take LSB of alignment
|
||||
alignment = alignment & ~(alignment & (alignment-1));
|
||||
if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
|
||||
memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
|
||||
}
|
||||
|
||||
createStore(source, base, memoryAccess, scope, alignment);
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
|
||||
Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
|
||||
{
|
||||
Id id;
|
||||
|
||||
@@ -2524,8 +2618,15 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu
|
||||
id = accessChain.base; // no precision, it was set when this was defined
|
||||
} else {
|
||||
transferAccessChainSwizzle(true);
|
||||
|
||||
// take LSB of alignment
|
||||
alignment = alignment & ~(alignment & (alignment-1));
|
||||
if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
|
||||
memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
|
||||
}
|
||||
|
||||
// load through the access chain
|
||||
id = createLoad(collapseAccessChain(), memoryAccess, scope);
|
||||
id = createLoad(collapseAccessChain(), memoryAccess, scope, alignment);
|
||||
setPrecision(id, precision);
|
||||
addDecoration(id, nonUniform);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,9 @@ public:
|
||||
// For creating new types (will return old type if the requested one was already made).
|
||||
Id makeVoidType();
|
||||
Id makeBoolType();
|
||||
Id makePointer(StorageClass, Id type);
|
||||
Id makePointer(StorageClass, Id pointee);
|
||||
Id makeForwardPointer(StorageClass);
|
||||
Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
|
||||
Id makeIntegerType(int width, bool hasSign); // generic
|
||||
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||
@@ -194,6 +196,7 @@ public:
|
||||
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
|
||||
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
|
||||
bool containsType(Id typeId, Op typeOp, unsigned int width) const;
|
||||
bool containsPhysicalStorageBufferOrArray(Id typeId) const;
|
||||
|
||||
bool isConstantOpCode(Op opcode) const;
|
||||
bool isSpecConstantOpCode(Op opcode) const;
|
||||
@@ -300,10 +303,10 @@ public:
|
||||
Id createUndefined(Id type);
|
||||
|
||||
// Store into an Id and return the l-value
|
||||
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
|
||||
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// Load from an Id and return it
|
||||
Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
|
||||
Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// Create an OpAccessChain instruction
|
||||
Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
|
||||
@@ -535,6 +538,7 @@ public:
|
||||
Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
|
||||
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
|
||||
bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
|
||||
unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment. Only tracks base and (optional) component selection alignment.
|
||||
|
||||
// Accumulate whether anything in the chain of structures has coherent decorations.
|
||||
struct CoherentFlags {
|
||||
@@ -601,31 +605,34 @@ public:
|
||||
}
|
||||
|
||||
// push offset onto the end of the chain
|
||||
void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags)
|
||||
void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
|
||||
{
|
||||
accessChain.indexChain.push_back(offset);
|
||||
accessChain.coherentFlags |= coherentFlags;
|
||||
accessChain.alignment |= alignment;
|
||||
}
|
||||
|
||||
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
|
||||
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
|
||||
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
|
||||
|
||||
// push a dynamic component selection onto the access chain, only applicable with a
|
||||
// non-trivial swizzle or no swizzle
|
||||
void accessChainPushComponent(Id component, Id preSwizzleBaseType)
|
||||
void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
|
||||
{
|
||||
if (accessChain.swizzle.size() != 1) {
|
||||
accessChain.component = component;
|
||||
if (accessChain.preSwizzleBaseType == NoType)
|
||||
accessChain.preSwizzleBaseType = preSwizzleBaseType;
|
||||
}
|
||||
accessChain.coherentFlags |= coherentFlags;
|
||||
accessChain.alignment |= alignment;
|
||||
}
|
||||
|
||||
// use accessChain and swizzle to store value
|
||||
void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
|
||||
void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// use accessChain and swizzle to load an r-value
|
||||
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
|
||||
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// get the direct pointer for an l-value
|
||||
Id accessChainGetLValue();
|
||||
@@ -639,7 +646,7 @@ public:
|
||||
void postProcess();
|
||||
|
||||
// Hook to visit each instruction in a block in a function
|
||||
void postProcess(const Instruction&);
|
||||
void postProcess(Instruction&);
|
||||
// Hook to visit each instruction in a reachable block in a function.
|
||||
void postProcessReachable(const Instruction&);
|
||||
// Hook to visit each non-32-bit sized float/int operation in a block.
|
||||
@@ -675,6 +682,7 @@ public:
|
||||
void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
|
||||
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
|
||||
void dumpModuleProcesses(std::vector<unsigned int>&) const;
|
||||
spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const;
|
||||
|
||||
unsigned int spvVersion; // the version of SPIR-V to emit in the header
|
||||
SourceLanguage source;
|
||||
|
||||
@@ -87,6 +87,7 @@ void Builder::postProcessType(const Instruction& inst, Id typeId)
|
||||
StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
|
||||
if (width == 8) {
|
||||
switch (storageClass) {
|
||||
case StorageClassPhysicalStorageBufferEXT:
|
||||
case StorageClassUniform:
|
||||
case StorageClassStorageBuffer:
|
||||
case StorageClassPushConstant:
|
||||
@@ -97,6 +98,7 @@ void Builder::postProcessType(const Instruction& inst, Id typeId)
|
||||
}
|
||||
} else if (width == 16) {
|
||||
switch (storageClass) {
|
||||
case StorageClassPhysicalStorageBufferEXT:
|
||||
case StorageClassUniform:
|
||||
case StorageClassStorageBuffer:
|
||||
case StorageClassPushConstant:
|
||||
@@ -151,7 +153,7 @@ void Builder::postProcessType(const Instruction& inst, Id typeId)
|
||||
}
|
||||
|
||||
// Called for each instruction that resides in a block.
|
||||
void Builder::postProcess(const Instruction& inst)
|
||||
void Builder::postProcess(Instruction& inst)
|
||||
{
|
||||
// Add capabilities based simply on the opcode.
|
||||
switch (inst.getOpCode()) {
|
||||
@@ -190,6 +192,88 @@ void Builder::postProcess(const Instruction& inst)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case OpLoad:
|
||||
case OpStore:
|
||||
{
|
||||
// For any load/store to a PhysicalStorageBufferEXT, walk the accesschain
|
||||
// index list to compute the misalignment. The pre-existing alignment value
|
||||
// (set via Builder::AccessChain::alignment) only accounts for the base of
|
||||
// the reference type and any scalar component selection in the accesschain,
|
||||
// and this function computes the rest from the SPIR-V Offset decorations.
|
||||
Instruction *accessChain = module.getInstruction(inst.getIdOperand(0));
|
||||
if (accessChain->getOpCode() == OpAccessChain) {
|
||||
Instruction *base = module.getInstruction(accessChain->getIdOperand(0));
|
||||
// Get the type of the base of the access chain. It must be a pointer type.
|
||||
Id typeId = base->getTypeId();
|
||||
Instruction *type = module.getInstruction(typeId);
|
||||
assert(type->getOpCode() == OpTypePointer);
|
||||
if (type->getImmediateOperand(0) != StorageClassPhysicalStorageBufferEXT) {
|
||||
break;
|
||||
}
|
||||
// Get the pointee type.
|
||||
typeId = type->getIdOperand(1);
|
||||
type = module.getInstruction(typeId);
|
||||
// Walk the index list for the access chain. For each index, find any
|
||||
// misalignment that can apply when accessing the member/element via
|
||||
// Offset/ArrayStride/MatrixStride decorations, and bitwise OR them all
|
||||
// together.
|
||||
int alignment = 0;
|
||||
for (int i = 1; i < accessChain->getNumOperands(); ++i) {
|
||||
Instruction *idx = module.getInstruction(accessChain->getIdOperand(i));
|
||||
if (type->getOpCode() == OpTypeStruct) {
|
||||
assert(idx->getOpCode() == OpConstant);
|
||||
int c = idx->getImmediateOperand(0);
|
||||
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getOpCode() == OpMemberDecorate &&
|
||||
decoration.get()->getIdOperand(0) == typeId &&
|
||||
decoration.get()->getImmediateOperand(1) == c &&
|
||||
(decoration.get()->getImmediateOperand(2) == DecorationOffset ||
|
||||
decoration.get()->getImmediateOperand(2) == DecorationMatrixStride)) {
|
||||
alignment |= decoration.get()->getImmediateOperand(3);
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
// get the next member type
|
||||
typeId = type->getIdOperand(c);
|
||||
type = module.getInstruction(typeId);
|
||||
} else if (type->getOpCode() == OpTypeArray ||
|
||||
type->getOpCode() == OpTypeRuntimeArray) {
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getOpCode() == OpDecorate &&
|
||||
decoration.get()->getIdOperand(0) == typeId &&
|
||||
decoration.get()->getImmediateOperand(1) == DecorationArrayStride) {
|
||||
alignment |= decoration.get()->getImmediateOperand(2);
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
// Get the element type
|
||||
typeId = type->getIdOperand(0);
|
||||
type = module.getInstruction(typeId);
|
||||
} else {
|
||||
// Once we get to any non-aggregate type, we're done.
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(inst.getNumOperands() >= 3);
|
||||
unsigned int memoryAccess = inst.getImmediateOperand((inst.getOpCode() == OpStore) ? 2 : 1);
|
||||
assert(memoryAccess & MemoryAccessAlignedMask);
|
||||
// Compute the index of the alignment operand.
|
||||
int alignmentIdx = 2;
|
||||
if (memoryAccess & MemoryAccessVolatileMask)
|
||||
alignmentIdx++;
|
||||
if (inst.getOpCode() == OpStore)
|
||||
alignmentIdx++;
|
||||
// Merge new and old (mis)alignment
|
||||
alignment |= inst.getImmediateOperand(alignmentIdx);
|
||||
// Pick the LSB
|
||||
alignment = alignment & ~(alignment & (alignment-1));
|
||||
// update the Aligned operand
|
||||
inst.setImmediateOperand(alignmentIdx, alignment);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -258,6 +342,47 @@ void Builder::postProcess()
|
||||
Block* b = *bi;
|
||||
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
|
||||
postProcess(*ii->get());
|
||||
|
||||
// For all local variables that contain pointers to PhysicalStorageBufferEXT, check whether
|
||||
// there is an existing restrict/aliased decoration. If we don't find one, add Aliased as the
|
||||
// default.
|
||||
for (auto vi = b->getLocalVariables().cbegin(); vi != b->getLocalVariables().cend(); vi++) {
|
||||
const Instruction& inst = *vi->get();
|
||||
Id resultId = inst.getResultId();
|
||||
if (containsPhysicalStorageBufferOrArray(getDerefTypeId(resultId))) {
|
||||
bool foundDecoration = false;
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getIdOperand(0) == resultId &&
|
||||
decoration.get()->getOpCode() == OpDecorate &&
|
||||
(decoration.get()->getImmediateOperand(1) == spv::DecorationAliasedPointerEXT ||
|
||||
decoration.get()->getImmediateOperand(1) == spv::DecorationRestrictPointerEXT)) {
|
||||
foundDecoration = true;
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
if (!foundDecoration) {
|
||||
addDecoration(resultId, spv::DecorationAliasedPointerEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for any 8/16 bit type in physical storage buffer class, and set the
|
||||
// appropriate capability. This happens in createSpvVariable for other storage
|
||||
// classes, but there isn't always a variable for physical storage buffer.
|
||||
for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
|
||||
Instruction* type = groupedTypes[OpTypePointer][t];
|
||||
if (type->getImmediateOperand(0) == (unsigned)StorageClassPhysicalStorageBufferEXT) {
|
||||
if (containsType(type->getIdOperand(1), OpTypeInt, 8)) {
|
||||
addExtension(spv::E_SPV_KHR_8bit_storage);
|
||||
addCapability(spv::CapabilityStorageBuffer8BitAccess);
|
||||
}
|
||||
if (containsType(type->getIdOperand(1), OpTypeInt, 16) ||
|
||||
containsType(type->getIdOperand(1), OpTypeFloat, 16)) {
|
||||
addExtension(spv::E_SPV_KHR_16bit_storage);
|
||||
addCapability(spv::CapabilityStorageBuffer16BitAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,6 +540,14 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
case OperandMemoryAccess:
|
||||
outputMask(OperandMemoryAccess, stream[word++]);
|
||||
--numOperands;
|
||||
// Aligned is the only memory access operand that uses an immediate
|
||||
// value, and it is also the first operand that uses a value at all.
|
||||
if (stream[word-1] & MemoryAccessAlignedMask) {
|
||||
disassembleImmediates(1);
|
||||
numOperands--;
|
||||
if (numOperands)
|
||||
out << " ";
|
||||
}
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -124,6 +124,8 @@ const char* AddressingString(int addr)
|
||||
case 1: return "Physical32";
|
||||
case 2: return "Physical64";
|
||||
|
||||
case AddressingModelPhysicalStorageBuffer64EXT: return "PhysicalStorageBuffer64EXT";
|
||||
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
@@ -220,6 +222,8 @@ const char* StorageClassString(int StorageClass)
|
||||
case StorageClassIncomingCallableDataNV: return "IncomingCallableDataNV";
|
||||
#endif
|
||||
|
||||
case StorageClassPhysicalStorageBufferEXT: return "PhysicalStorageBufferEXT";
|
||||
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
@@ -295,6 +299,8 @@ const char* DecorationString(int decoration)
|
||||
case DecorationNonUniformEXT: return "DecorationNonUniformEXT";
|
||||
case DecorationHlslCounterBufferGOOGLE: return "DecorationHlslCounterBufferGOOGLE";
|
||||
case DecorationHlslSemanticGOOGLE: return "DecorationHlslSemanticGOOGLE";
|
||||
case DecorationRestrictPointerEXT: return "DecorationRestrictPointerEXT";
|
||||
case DecorationAliasedPointerEXT: return "DecorationAliasedPointerEXT";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -922,6 +928,8 @@ const char* CapabilityString(int info)
|
||||
case CapabilityVulkanMemoryModelKHR: return "CapabilityVulkanMemoryModelKHR";
|
||||
case CapabilityVulkanMemoryModelDeviceScopeKHR: return "CapabilityVulkanMemoryModelDeviceScopeKHR";
|
||||
|
||||
case CapabilityPhysicalStorageBufferAddressesEXT: return "CapabilityPhysicalStorageBufferAddressesEXT";
|
||||
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2018 The Khronos Group Inc.
|
||||
// Copyright (c) 2014-2019 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and/or associated documentation files (the "Materials"),
|
||||
@@ -26,14 +26,16 @@
|
||||
// the Binary Section of the SPIR-V specification.
|
||||
|
||||
// Enumeration tokens for SPIR-V, in various styles:
|
||||
// C, C++, C++11, JSON, Lua, Python, C#
|
||||
// C, C++, C++11, JSON, Lua, Python, C#, D
|
||||
//
|
||||
// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
|
||||
// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
|
||||
// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
|
||||
// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
|
||||
// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
|
||||
// - C# will use enum classes in the Specification class located in the "Spv" namespace, e.g.: Spv.Specification.SourceLanguage.GLSL
|
||||
// - C# will use enum classes in the Specification class located in the "Spv" namespace,
|
||||
// e.g.: Spv.Specification.SourceLanguage.GLSL
|
||||
// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL
|
||||
//
|
||||
// Some tokens act like mask values, which can be OR'd together,
|
||||
// while others are mutually exclusive. The mask-like ones have
|
||||
@@ -48,11 +50,11 @@ namespace spv {
|
||||
typedef unsigned int Id;
|
||||
|
||||
#define SPV_VERSION 0x10300
|
||||
#define SPV_REVISION 1
|
||||
#define SPV_REVISION 6
|
||||
|
||||
static const unsigned int MagicNumber = 0x07230203;
|
||||
static const unsigned int Version = 0x00010300;
|
||||
static const unsigned int Revision = 1;
|
||||
static const unsigned int Revision = 6;
|
||||
static const unsigned int OpCodeMask = 0xffff;
|
||||
static const unsigned int WordCountShift = 16;
|
||||
|
||||
@@ -89,6 +91,7 @@ enum AddressingModel {
|
||||
AddressingModelLogical = 0,
|
||||
AddressingModelPhysical32 = 1,
|
||||
AddressingModelPhysical64 = 2,
|
||||
AddressingModelPhysicalStorageBuffer64EXT = 5348,
|
||||
AddressingModelMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
@@ -140,6 +143,11 @@ enum ExecutionMode {
|
||||
ExecutionModeLocalSizeId = 38,
|
||||
ExecutionModeLocalSizeHintId = 39,
|
||||
ExecutionModePostDepthCoverage = 4446,
|
||||
ExecutionModeDenormPreserve = 4459,
|
||||
ExecutionModeDenormFlushToZero = 4460,
|
||||
ExecutionModeSignedZeroInfNanPreserve = 4461,
|
||||
ExecutionModeRoundingModeRTE = 4462,
|
||||
ExecutionModeRoundingModeRTZ = 4463,
|
||||
ExecutionModeStencilRefReplacingEXT = 5027,
|
||||
ExecutionModeOutputLinesNV = 5269,
|
||||
ExecutionModeOutputPrimitivesNV = 5270,
|
||||
@@ -169,6 +177,7 @@ enum StorageClass {
|
||||
StorageClassHitAttributeNV = 5339,
|
||||
StorageClassIncomingRayPayloadNV = 5342,
|
||||
StorageClassShaderRecordBufferNV = 5343,
|
||||
StorageClassPhysicalStorageBufferEXT = 5349,
|
||||
StorageClassMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
@@ -417,6 +426,8 @@ enum Decoration {
|
||||
DecorationMaxByteOffset = 45,
|
||||
DecorationAlignmentId = 46,
|
||||
DecorationMaxByteOffsetId = 47,
|
||||
DecorationNoSignedWrap = 4469,
|
||||
DecorationNoUnsignedWrap = 4470,
|
||||
DecorationExplicitInterpAMD = 4999,
|
||||
DecorationOverrideCoverageNV = 5248,
|
||||
DecorationPassthroughNV = 5250,
|
||||
@@ -427,6 +438,8 @@ enum Decoration {
|
||||
DecorationPerTaskNV = 5273,
|
||||
DecorationPerVertexNV = 5285,
|
||||
DecorationNonUniformEXT = 5300,
|
||||
DecorationRestrictPointerEXT = 5355,
|
||||
DecorationAliasedPointerEXT = 5356,
|
||||
DecorationHlslCounterBufferGOOGLE = 5634,
|
||||
DecorationHlslSemanticGOOGLE = 5635,
|
||||
DecorationMax = 0x7fffffff,
|
||||
@@ -756,6 +769,11 @@ enum Capability {
|
||||
CapabilityStorageBuffer8BitAccess = 4448,
|
||||
CapabilityUniformAndStorageBuffer8BitAccess = 4449,
|
||||
CapabilityStoragePushConstant8 = 4450,
|
||||
CapabilityDenormPreserve = 4464,
|
||||
CapabilityDenormFlushToZero = 4465,
|
||||
CapabilitySignedZeroInfNanPreserve = 4466,
|
||||
CapabilityRoundingModeRTE = 4467,
|
||||
CapabilityRoundingModeRTZ = 4468,
|
||||
CapabilityFloat16ImageAMD = 5008,
|
||||
CapabilityImageGatherBiasLodAMD = 5009,
|
||||
CapabilityFragmentMaskAMD = 5010,
|
||||
@@ -791,6 +809,7 @@ enum Capability {
|
||||
CapabilityRayTracingNV = 5340,
|
||||
CapabilityVulkanMemoryModelKHR = 5345,
|
||||
CapabilityVulkanMemoryModelDeviceScopeKHR = 5346,
|
||||
CapabilityPhysicalStorageBufferAddressesEXT = 5347,
|
||||
CapabilityComputeDerivativeGroupLinearNV = 5350,
|
||||
CapabilitySubgroupShuffleINTEL = 5568,
|
||||
CapabilitySubgroupBufferBlockIOINTEL = 5569,
|
||||
|
||||
@@ -102,6 +102,11 @@ public:
|
||||
operands.push_back(immediate);
|
||||
idOperand.push_back(false);
|
||||
}
|
||||
void setImmediateOperand(unsigned idx, unsigned int immediate) {
|
||||
assert(!idOperand[idx]);
|
||||
operands[idx] = immediate;
|
||||
}
|
||||
|
||||
void addStringOperand(const char* str)
|
||||
{
|
||||
unsigned int word;
|
||||
@@ -203,6 +208,7 @@ public:
|
||||
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
|
||||
return instructions;
|
||||
}
|
||||
const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
|
||||
void setUnreachable() { unreachable = true; }
|
||||
bool isUnreachable() const { return unreachable; }
|
||||
// Returns the block's merge instruction, if one exists (otherwise null).
|
||||
|
||||
Reference in New Issue
Block a user