Implement atomic counter offset semantics.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27760 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
aa657c117e
commit
d78ca6297d
10 changed files with 207 additions and 66 deletions
|
|
@ -54,7 +54,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
|
|||
contextPragma(true, false), loopNestingLevel(0), controlFlowNestingLevel(0), structNestingLevel(0),
|
||||
tokensBeforeEOF(false), limits(resources.limits), currentScanner(0),
|
||||
numErrors(0), parsingBuiltins(pb), afterEOF(false),
|
||||
anyIndexLimits(false)
|
||||
atomicUintOffsets(0), anyIndexLimits(false)
|
||||
{
|
||||
// ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
|
||||
linkage = new TIntermAggregate;
|
||||
|
|
@ -103,7 +103,6 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
|
|||
globalBufferDefaults.layoutPacking = ElpShared;
|
||||
|
||||
globalInputDefaults.clear();
|
||||
|
||||
globalOutputDefaults.clear();
|
||||
|
||||
// "Shaders in the transform
|
||||
|
|
@ -119,6 +118,11 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
|
|||
globalOutputDefaults.layoutStream = 0;
|
||||
}
|
||||
|
||||
TParseContext::~TParseContext()
|
||||
{
|
||||
delete [] atomicUintOffsets;
|
||||
}
|
||||
|
||||
void TParseContext::setLimits(const TBuiltInResource& r)
|
||||
{
|
||||
resources = r;
|
||||
|
|
@ -131,6 +135,13 @@ void TParseContext::setLimits(const TBuiltInResource& r)
|
|||
! limits.generalVaryingIndexing;
|
||||
|
||||
intermediate.setLimits(resources);
|
||||
|
||||
// "Each binding point tracks its own current default offset for
|
||||
// inheritance of subsequent variables using the same binding. The initial state of compilation is that all
|
||||
// binding points have an offset of 0."
|
||||
atomicUintOffsets = new int[resources.maxAtomicCounterBindings];
|
||||
for (int b = 0; b < resources.maxAtomicCounterBindings; ++b)
|
||||
atomicUintOffsets[b] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -3388,10 +3399,6 @@ void TParseContext::layoutObjectCheck(TSourceLoc loc, const TSymbol& symbol)
|
|||
// "The offset qualifier can only be used on block members of blocks..."
|
||||
if (qualifier.hasOffset() && type.getBasicType() != EbtAtomicUint)
|
||||
error(loc, "cannot specify on a variable declaration", "offset", "");
|
||||
if (qualifier.hasOffset() && ! qualifier.hasBinding() && type.getBasicType() == EbtAtomicUint)
|
||||
error(loc, "a binding is required", "offset", "");
|
||||
if (qualifier.hasBinding() && (int)qualifier.layoutBinding >= resources.maxAtomicCounterBindings && type.getBasicType() == EbtAtomicUint)
|
||||
error(loc, "cannot be greater-than-or-equal to gl_MaxAtomicCounterBindings", "binding", "");
|
||||
// "The align qualifier can only be used on blocks or block members..."
|
||||
if (qualifier.hasAlign())
|
||||
error(loc, "cannot specify on a variable declaration", "align", "");
|
||||
|
|
@ -3492,6 +3499,18 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
|
|||
if (lastBinding >= resources.maxCombinedTextureImageUnits)
|
||||
error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
|
||||
}
|
||||
if (type.getBasicType() == EbtAtomicUint) {
|
||||
if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
|
||||
error(loc, "atomic_uint binding is too large; see gl_MaxAtomicCounterBindings", "binding", "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// atomic_uint
|
||||
if (type.getBasicType() == EbtAtomicUint) {
|
||||
if (! type.getQualifier().hasBinding())
|
||||
error(loc, "layout(binding=X) is required", "atomic_uint", "");
|
||||
}
|
||||
|
||||
// "The offset qualifier can only be used on block members of blocks..."
|
||||
|
|
@ -3633,6 +3652,35 @@ void TParseContext::checkNoShaderLayouts(TSourceLoc loc, const TShaderQualifiers
|
|||
}
|
||||
}
|
||||
|
||||
// Correct and/or advance an object's offset layout qualifier.
|
||||
void TParseContext::fixOffset(TSourceLoc loc, TSymbol& symbol)
|
||||
{
|
||||
const TQualifier& qualifier = symbol.getType().getQualifier();
|
||||
if (symbol.getType().getBasicType() == EbtAtomicUint) {
|
||||
if (qualifier.hasBinding() && (int)qualifier.layoutBinding < resources.maxAtomicCounterBindings) {
|
||||
|
||||
// Set the offset
|
||||
int offset;
|
||||
if (qualifier.hasOffset())
|
||||
offset = qualifier.layoutOffset;
|
||||
else
|
||||
offset = atomicUintOffsets[qualifier.layoutBinding];
|
||||
symbol.getWritableType().getQualifier().layoutOffset = offset;
|
||||
|
||||
// Check for overlap
|
||||
int numOffsets = 4;
|
||||
if (symbol.getType().isArray())
|
||||
numOffsets *= symbol.getType().getArraySize();
|
||||
int repeated = intermediate.addUsedOffsets(qualifier.layoutBinding, offset, numOffsets);
|
||||
if (repeated >= 0)
|
||||
error(loc, "atomic counters sharing the same offset:", "offset", "%d", repeated);
|
||||
|
||||
// Bump the default offset
|
||||
atomicUintOffsets[qualifier.layoutBinding] = offset + numOffsets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Look up a function name in the symbol table, and make sure it is a function.
|
||||
//
|
||||
|
|
@ -3748,6 +3796,23 @@ const TFunction* TParseContext::findFunction400(TSourceLoc loc, const TFunction&
|
|||
return findFunction120(loc, call, builtIn);
|
||||
}
|
||||
|
||||
// When a declaration includes a type, but not a variable name, it can be
|
||||
// to establish defaults.
|
||||
void TParseContext::declareTypeDefaults(TSourceLoc loc, const TPublicType& publicType)
|
||||
{
|
||||
if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding() && publicType.qualifier.hasOffset()) {
|
||||
if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
|
||||
error(loc, "atomic_uint binding is too large", "binding", "");
|
||||
return;
|
||||
}
|
||||
atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
|
||||
return;
|
||||
}
|
||||
|
||||
if (publicType.qualifier.hasLayout())
|
||||
warn(loc, "useless application of layout qualifier", "layout", "");
|
||||
}
|
||||
|
||||
//
|
||||
// Do everything necessary to handle a variable (non-block) declaration.
|
||||
// Either redeclaring a variable, or making a new one, updating the symbol
|
||||
|
|
@ -3826,8 +3891,9 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
|
|||
initNode = executeInitializer(loc, identifier, initializer, variable);
|
||||
}
|
||||
|
||||
// look for errors/adjustments in layout qualifier use
|
||||
// look for errors in layout qualifier use
|
||||
layoutObjectCheck(loc, *symbol);
|
||||
fixOffset(loc, *symbol);
|
||||
|
||||
// see if it's a linker-level object to track
|
||||
if (newDeclaration && symbolTable.atGlobalLevel())
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class TParseContext {
|
|||
public:
|
||||
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, EShLanguage, TInfoSink&,
|
||||
bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
|
||||
virtual ~TParseContext();
|
||||
|
||||
void setLimits(const TBuiltInResource&);
|
||||
bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
|
||||
|
|
@ -159,11 +160,13 @@ public:
|
|||
void layoutTypeCheck(TSourceLoc, const TType&);
|
||||
void layoutQualifierCheck(TSourceLoc, const TQualifier&);
|
||||
void checkNoShaderLayouts(TSourceLoc, const TShaderQualifiers&);
|
||||
void fixOffset(TSourceLoc, TSymbol&);
|
||||
|
||||
const TFunction* findFunction(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunctionExact(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction120(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction400(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
void declareTypeDefaults(TSourceLoc, const TPublicType&);
|
||||
TIntermNode* declareVariable(TSourceLoc, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
|
||||
TIntermTyped* addConstructor(TSourceLoc, TIntermNode*, const TType&, TOperator);
|
||||
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
||||
|
|
@ -265,6 +268,7 @@ protected:
|
|||
TQualifier globalUniformDefaults;
|
||||
TQualifier globalInputDefaults;
|
||||
TQualifier globalOutputDefaults;
|
||||
int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point
|
||||
TString currentCaller;
|
||||
TIdSetType inductiveLoopIds;
|
||||
bool anyIndexLimits;
|
||||
|
|
|
|||
|
|
@ -966,8 +966,7 @@ single_declaration
|
|||
: fully_specified_type {
|
||||
$$.type = $1;
|
||||
$$.intermNode = 0;
|
||||
if ($$.type.qualifier.hasLayout())
|
||||
parseContext.warn($1.loc, "useless application of layout qualifier", "layout", "");
|
||||
parseContext.declareTypeDefaults($$.loc, $$.type);
|
||||
}
|
||||
| fully_specified_type IDENTIFIER {
|
||||
$$.type = $1;
|
||||
|
|
|
|||
|
|
@ -321,7 +321,8 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
|
|||
symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation ||
|
||||
symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent ||
|
||||
symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex ||
|
||||
symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding) {
|
||||
symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding ||
|
||||
(symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset))) {
|
||||
error(infoSink, "Layout qualification must match:");
|
||||
writeTypeComparison = true;
|
||||
}
|
||||
|
|
@ -661,6 +662,30 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
|
|||
return -1; // no collision
|
||||
}
|
||||
|
||||
// Accumulate locations used for inputs, outputs, and uniforms, and check for collisions
|
||||
// as the accumulation is done.
|
||||
//
|
||||
// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
|
||||
//
|
||||
int TIntermediate::addUsedOffsets(int binding, int offset, int numOffsets)
|
||||
{
|
||||
TRange bindingRange(binding, binding);
|
||||
TRange offsetRange(offset, offset + numOffsets - 1);
|
||||
TOffsetRange range(bindingRange, offsetRange);
|
||||
|
||||
// check for collisions, except for vertex inputs on desktop
|
||||
for (size_t r = 0; r < usedAtomics.size(); ++r) {
|
||||
if (range.overlap(usedAtomics[r])) {
|
||||
// there is a collision; pick one
|
||||
return std::max(offset, usedAtomics[r].offset.start);
|
||||
}
|
||||
}
|
||||
|
||||
usedAtomics.push_back(range);
|
||||
|
||||
return -1; // no collision
|
||||
}
|
||||
|
||||
// Recursively figure out how many locations are used up by an input or output type.
|
||||
// Return the size of type, as measured by "locations".
|
||||
int TIntermediate::computeTypeLocationSize(const TType& type) const
|
||||
|
|
|
|||
|
|
@ -93,6 +93,19 @@ struct TIoRange {
|
|||
int index;
|
||||
};
|
||||
|
||||
// An IO range is a 2-D rectangle; the set of (binding, offset) pairs all lying
|
||||
// within the same binding and offset range.
|
||||
struct TOffsetRange {
|
||||
TOffsetRange(TRange binding, TRange offset)
|
||||
: binding(binding), offset(offset) { }
|
||||
bool overlap(const TOffsetRange& rhs) const
|
||||
{
|
||||
return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
|
||||
}
|
||||
TRange binding;
|
||||
TRange offset;
|
||||
};
|
||||
|
||||
// Things that need to be tracked per xfb buffer.
|
||||
struct TXfbBuffer {
|
||||
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
|
||||
|
|
@ -269,6 +282,7 @@ public:
|
|||
bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
|
||||
|
||||
int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
|
||||
int addUsedOffsets(int binding, int offset, int numOffsets);
|
||||
int computeTypeLocationSize(const TType&) const;
|
||||
|
||||
bool setXfbBufferStride(int buffer, int stride)
|
||||
|
|
@ -320,9 +334,10 @@ protected:
|
|||
typedef std::list<TCall> TGraph;
|
||||
TGraph callGraph;
|
||||
|
||||
std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking
|
||||
std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform and buffers
|
||||
std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
|
||||
std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking
|
||||
std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
|
||||
std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters
|
||||
std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
|
||||
|
||||
private:
|
||||
void operator=(TIntermediate&); // prevent assignments
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue