WIP: track declared builtin type [proposal]

Marking as WIP since it might deserve discussion or at least explicit consideration.

During type sanitization, the TQualifier's TBuiltInVariable type is lost.  However,
sometimes it's needed downstream.  There were already two methods in use to track
it through to places it was needed: one in the TParameter, and one in a map in the
HlslParseContext used for structured buffers.

The latter was going to be insufficient when SB types with counters are passed to
user functions, and it's proving awkward to track the data to where it's needed.
This PR holds a proposal: track the original declared builtin type in the TType,
so it's trivially available where needed.

This lets the other two mechanisms be removed (and they are in this PR).  There's a
side benefit of not losing certain types of information before the reflection interface.

This PR is only that proposal, so it changes no test results.  If it's acceptable,
I'll use it for the last piece of SB counter functionality.
This commit is contained in:
steve-lunarg 2017-04-23 19:44:28 -06:00
parent 1a010b8368
commit a4bfed129f
4 changed files with 21 additions and 35 deletions

View File

@ -400,6 +400,7 @@ public:
invariant = false; invariant = false;
noContraction = false; noContraction = false;
makeTemporary(); makeTemporary();
declaredBuiltIn = EbvNone;
} }
// drop qualifiers that don't belong in a temporary variable // drop qualifiers that don't belong in a temporary variable
@ -457,6 +458,7 @@ public:
const char* semanticName; const char* semanticName;
TStorageQualifier storage : 6; TStorageQualifier storage : 6;
TBuiltInVariable builtIn : 8; TBuiltInVariable builtIn : 8;
TBuiltInVariable declaredBuiltIn : 8;
TPrecisionQualifier precision : 3; TPrecisionQualifier precision : 3;
bool invariant : 1; // require canonical treatment for cross-shader invariance bool invariant : 1; // require canonical treatment for cross-shader invariance
bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects

View File

@ -198,7 +198,6 @@ struct TParameter {
TString *name; TString *name;
TType* type; TType* type;
TIntermTyped* defaultValue; TIntermTyped* defaultValue;
TBuiltInVariable declaredBuiltIn;
void copyParam(const TParameter& param) void copyParam(const TParameter& param)
{ {
if (param.name) if (param.name)
@ -207,8 +206,8 @@ struct TParameter {
name = 0; name = 0;
type = param.type->clone(); type = param.type->clone();
defaultValue = param.defaultValue; defaultValue = param.defaultValue;
declaredBuiltIn = param.declaredBuiltIn;
} }
TBuiltInVariable getDeclaredBuiltIn() const { return type->getQualifier().declaredBuiltIn; }
}; };
// //
@ -241,7 +240,6 @@ public:
virtual void addParameter(TParameter& p) virtual void addParameter(TParameter& p)
{ {
assert(writable); assert(writable);
p.declaredBuiltIn = p.type->getQualifier().builtIn;
parameters.push_back(p); parameters.push_back(p);
p.type->appendMangledName(mangledName); p.type->appendMangledName(mangledName);

View File

@ -1985,7 +1985,7 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
// GS outputs are via emit, so we do not copy them here. // GS outputs are via emit, so we do not copy them here.
if (param.type->getQualifier().isParamOutput()) { if (param.type->getQualifier().isParamOutput()) {
if (param.declaredBuiltIn == EbvGsOutputStream) { if (param.getDeclaredBuiltIn() == EbvGsOutputStream) {
// GS output stream does not assign outputs here: it's the Append() method // GS output stream does not assign outputs here: it's the Append() method
// which writes to the output, probably multiple times separated by Emit. // which writes to the output, probably multiple times separated by Emit.
// We merely remember the output to use, here. // We merely remember the output to use, here.
@ -2092,7 +2092,7 @@ void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& return
TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingIn); TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingIn);
inputs.push_back(argAsGlobal); inputs.push_back(argAsGlobal);
if (function[i].declaredBuiltIn == EbvInputPatch) if (function[i].getDeclaredBuiltIn() == EbvInputPatch)
inputPatch = argAsGlobal; inputPatch = argAsGlobal;
} }
if (paramType.getQualifier().isParamOutput()) { if (paramType.getQualifier().isParamOutput()) {
@ -2481,13 +2481,9 @@ TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc
} }
// Return true if this a buffer type that has an associated counter buffer. // Return true if this a buffer type that has an associated counter buffer.
bool HlslParseContext::hasStructBuffCounter(const TString& name) const bool HlslParseContext::hasStructBuffCounter(const TType& type) const
{ {
const auto bivIt = structBufferBuiltIn.find(name); switch (type.getQualifier().declaredBuiltIn) {
if (bivIt == structBufferBuiltIn.end())
return false;
switch (bivIt->second) {
case EbvAppendConsume: // fall through... case EbvAppendConsume: // fall through...
case EbvRWStructuredBuffer: // ... case EbvRWStructuredBuffer: // ...
return true; return true;
@ -2503,7 +2499,7 @@ void HlslParseContext::declareStructBufferCounter(const TSourceLoc& loc, const T
if (! isStructBufferType(bufferType)) if (! isStructBufferType(bufferType))
return; return;
if (! hasStructBuffCounter(name)) if (! hasStructBuffCounter(bufferType))
return; return;
// Counter type // Counter type
@ -2574,8 +2570,6 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte
if (bufferObj == nullptr || bufferObj->getAsSymbolNode() == nullptr) if (bufferObj == nullptr || bufferObj->getAsSymbolNode() == nullptr)
return; return;
const TString bufferName(bufferObj->getAsSymbolNode()->getName());
// Some methods require a hidden internal counter, obtained via getStructBufferCounter(). // Some methods require a hidden internal counter, obtained via getStructBufferCounter().
// This lambda adds something to it and returns the old value. // This lambda adds something to it and returns the old value.
const auto incDecCounter = [&](int incval) -> TIntermTyped* { const auto incDecCounter = [&](int incval) -> TIntermTyped* {
@ -2604,20 +2598,14 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte
{ {
TIntermTyped* argIndex = makeIntegerIndex(argAggregate->getSequence()[1]->getAsTyped()); // index TIntermTyped* argIndex = makeIntegerIndex(argAggregate->getSequence()[1]->getAsTyped()); // index
const auto bivIt = structBufferBuiltIn.find(bufferName);
const TBuiltInVariable builtInType = (bivIt != structBufferBuiltIn.end()) ? bivIt->second : EbvNone;
const TType& bufferType = bufferObj->getType(); const TType& bufferType = bufferObj->getType();
const TBuiltInVariable builtInType = bufferType.getQualifier().declaredBuiltIn;
// Byte address buffers index in bytes (only multiples of 4 permitted... not so much a byte address // Byte address buffers index in bytes (only multiples of 4 permitted... not so much a byte address
// buffer then, but that's what it calls itself. // buffer then, but that's what it calls itself.
// TODO: it would be easier to track the declared (pre-sanitized) builtInType in the TType.
// If/when that happens, this should be simplified to look *only* at the builtin type.
const bool isByteAddressBuffer = (builtInType == EbvByteAddressBuffer || const bool isByteAddressBuffer = (builtInType == EbvByteAddressBuffer ||
builtInType == EbvRWByteAddressBuffer || builtInType == EbvRWByteAddressBuffer);
(builtInType == EbvNone && !bufferType.isVector() &&
bufferType.getBasicType() == EbtUint));
if (isByteAddressBuffer) if (isByteAddressBuffer)
@ -7234,10 +7222,6 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TType& type, const TS
switch (type.getQualifier().storage) { switch (type.getQualifier().storage) {
case EvqUniform: case EvqUniform:
case EvqBuffer: case EvqBuffer:
// remember pre-sanitized builtin type
if (type.getQualifier().storage == EvqBuffer && instanceName != nullptr)
structBufferBuiltIn[*instanceName] = type.getQualifier().builtIn;
correctUniform(type.getQualifier()); correctUniform(type.getQualifier());
break; break;
case EvqVaryingIn: case EvqVaryingIn:
@ -8043,6 +8027,9 @@ void HlslParseContext::correctOutput(TQualifier& qualifier)
// Make the IO decorations etc. be appropriate only for uniform type interfaces. // Make the IO decorations etc. be appropriate only for uniform type interfaces.
void HlslParseContext::correctUniform(TQualifier& qualifier) void HlslParseContext::correctUniform(TQualifier& qualifier)
{ {
if (qualifier.declaredBuiltIn == EbvNone)
qualifier.declaredBuiltIn = qualifier.builtIn;
qualifier.builtIn = EbvNone; qualifier.builtIn = EbvNone;
qualifier.clearInterstage(); qualifier.clearInterstage();
qualifier.clearInterstageLayout(); qualifier.clearInterstageLayout();
@ -8111,8 +8098,8 @@ void HlslParseContext::addPatchConstantInvocation()
if (storage == EvqConstReadOnly) // treated identically to input if (storage == EvqConstReadOnly) // treated identically to input
storage = EvqIn; storage = EvqIn;
if (function[p].declaredBuiltIn != EbvNone) if (function[p].getDeclaredBuiltIn() != EbvNone)
builtIns.insert(HlslParseContext::tInterstageIoData(function[p].declaredBuiltIn, storage)); builtIns.insert(HlslParseContext::tInterstageIoData(function[p].getDeclaredBuiltIn(), storage));
else else
builtIns.insert(HlslParseContext::tInterstageIoData(function[p].type->getQualifier().builtIn, storage)); builtIns.insert(HlslParseContext::tInterstageIoData(function[p].type->getQualifier().builtIn, storage));
} }
@ -8142,7 +8129,7 @@ void HlslParseContext::addPatchConstantInvocation()
const auto isOutputPatch = [this](TFunction& patchConstantFunction, int param) { const auto isOutputPatch = [this](TFunction& patchConstantFunction, int param) {
const TType& type = *patchConstantFunction[param].type; const TType& type = *patchConstantFunction[param].type;
const TBuiltInVariable biType = patchConstantFunction[param].declaredBuiltIn; const TBuiltInVariable biType = patchConstantFunction[param].getDeclaredBuiltIn();
return type.isArray() && !type.isRuntimeSizedArray() && biType == EbvOutputPatch; return type.isArray() && !type.isRuntimeSizedArray() && biType == EbvOutputPatch;
}; };
@ -8198,7 +8185,7 @@ void HlslParseContext::addPatchConstantInvocation()
// Now we'll add those to the entry and to the linkage. // Now we'll add those to the entry and to the linkage.
for (int p=0; p<pcfParamCount; ++p) { for (int p=0; p<pcfParamCount; ++p) {
const TBuiltInVariable biType = patchConstantFunction[p].declaredBuiltIn; const TBuiltInVariable biType = patchConstantFunction[p].getDeclaredBuiltIn();
TStorageQualifier storage = patchConstantFunction[p].type->getQualifier().storage; TStorageQualifier storage = patchConstantFunction[p].type->getQualifier().storage;
// Track whether there is an output patch param // Track whether there is an output patch param
@ -8264,7 +8251,7 @@ void HlslParseContext::addPatchConstantInvocation()
inputArg = intermediate.addSymbol(*perCtrlPtVar, loc); inputArg = intermediate.addSymbol(*perCtrlPtVar, loc);
} else { } else {
// find which builtin it is // find which builtin it is
const TBuiltInVariable biType = patchConstantFunction[p].declaredBuiltIn; const TBuiltInVariable biType = patchConstantFunction[p].getDeclaredBuiltIn();
inputArg = findLinkageSymbol(biType); inputArg = findLinkageSymbol(biType);
@ -8345,7 +8332,7 @@ void HlslParseContext::addPatchConstantInvocation()
if (paramType.getQualifier().isParamInput()) { if (paramType.getQualifier().isParamInput()) {
TIntermTyped* arg = nullptr; TIntermTyped* arg = nullptr;
if ((*entryPointFunction)[i].declaredBuiltIn == EbvInvocationId) { if ((*entryPointFunction)[i].getDeclaredBuiltIn() == EbvInvocationId) {
// substitute invocation ID with the array element ID // substitute invocation ID with the array element ID
arg = intermediate.addConstantUnion(cpt, loc); arg = intermediate.addConstantUnion(cpt, loc);
} else { } else {

View File

@ -289,7 +289,7 @@ protected:
bool isReference(const TType& type) const { return isStructBufferType(type); } bool isReference(const TType& type) const { return isStructBufferType(type); }
// Return true if this a buffer type that has an associated counter buffer. // Return true if this a buffer type that has an associated counter buffer.
bool hasStructBuffCounter(const TString& name) const; bool hasStructBuffCounter(const TType&) const;
// Finalization step: remove unused buffer blocks from linkage (we don't know until the // Finalization step: remove unused buffer blocks from linkage (we don't know until the
// shader is entirely compiled) // shader is entirely compiled)
@ -383,7 +383,6 @@ protected:
// Structuredbuffer shared types. Typically there are only a few. // Structuredbuffer shared types. Typically there are only a few.
TVector<TType*> structBufferTypes; TVector<TType*> structBufferTypes;
TMap<TString, TBuiltInVariable> structBufferBuiltIn;
TMap<TString, bool> structBufferCounter; TMap<TString, bool> structBufferCounter;
// The builtin interstage IO map considers e.g, EvqPosition on input and output separately, so that we // The builtin interstage IO map considers e.g, EvqPosition on input and output separately, so that we