Finish implementing compute shaders, within #version 430, partly based on a submission.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27674 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
@@ -69,6 +69,7 @@ enum TStorageQualifier {
|
||||
EvqVaryingOut, // pipeline ouput, read/write
|
||||
EvqUniform, // read only, shader with app
|
||||
EvqBuffer, // read only, shader with app
|
||||
EvqShared, // compute shader's read/write 'shared' qualifier
|
||||
|
||||
// parameters
|
||||
EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
|
||||
@@ -109,6 +110,8 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q)
|
||||
case EvqVaryingIn: return "in"; break;
|
||||
case EvqVaryingOut: return "out"; break;
|
||||
case EvqUniform: return "uniform"; break;
|
||||
case EvqBuffer: return "buffer"; break;
|
||||
case EvqShared: return "shared"; break;
|
||||
case EvqIn: return "in"; break;
|
||||
case EvqOut: return "out"; break;
|
||||
case EvqInOut: return "inout"; break;
|
||||
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
|
||||
bool isMemory() const
|
||||
{
|
||||
return shared || coherent || volatil || restrict || readonly || writeonly;
|
||||
return coherent || volatil || restrict || readonly || writeonly;
|
||||
}
|
||||
bool isInterpolation() const
|
||||
{
|
||||
@@ -693,6 +693,7 @@ struct TShaderQualifiers {
|
||||
TVertexSpacing spacing;
|
||||
TVertexOrder order;
|
||||
bool pointMode;
|
||||
int localSize[3]; // compute shader
|
||||
bool earlyFragmentTests; // fragment input
|
||||
|
||||
void init()
|
||||
@@ -705,6 +706,9 @@ struct TShaderQualifiers {
|
||||
spacing = EvsNone;
|
||||
order = EvoNone;
|
||||
pointMode = false;
|
||||
localSize[0] = 1;
|
||||
localSize[1] = 1;
|
||||
localSize[2] = 1;
|
||||
earlyFragmentTests = false;
|
||||
}
|
||||
|
||||
@@ -728,6 +732,10 @@ struct TShaderQualifiers {
|
||||
order = src.order;
|
||||
if (src.pointMode)
|
||||
pointMode = true;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (src.localSize[i] > 1)
|
||||
localSize[i] = src.localSize[i];
|
||||
}
|
||||
if (src.earlyFragmentTests)
|
||||
earlyFragmentTests = true;
|
||||
}
|
||||
|
||||
@@ -1079,14 +1079,14 @@ void TBuiltIns::initialize(int version, EProfile profile)
|
||||
if (version >= 430) {
|
||||
stageBuiltins[EShLangCompute].append(
|
||||
"in uvec3 gl_NumWorkGroups;"
|
||||
// TODO: 4.3 functionality: compute shader: constant with no initializer "const uvec3 gl_WorkGroupSize;"
|
||||
"const uvec3 gl_WorkGroupSize = uvec3(1,1,1);"
|
||||
|
||||
"in uvec3 gl_WorkGroupID;"
|
||||
"in uvec3 gl_LocalInvocationID;"
|
||||
|
||||
"in uvec3 gl_GlobalInvocationID;"
|
||||
"in uint gl_LocalInvocationIndex;"
|
||||
|
||||
|
||||
"\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1969,6 +1969,8 @@ void TParseContext::globalQualifierCheck(TSourceLoc loc, const TQualifier& quali
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
if (! symbolTable.atBuiltInLevel())
|
||||
error(loc, "global storage input qualifier cannot be used in a compute shader", "in", "");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2002,9 +2004,10 @@ void TParseContext::globalQualifierCheck(TSourceLoc loc, const TQualifier& quali
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
error(loc, "global storage output qualifier cannot be used in a compute shader", "out", "");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -3178,6 +3181,18 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
if (id == "local_size_x") {
|
||||
publicType.shaderQualifiers.localSize[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y") {
|
||||
publicType.shaderQualifiers.localSize[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z") {
|
||||
publicType.shaderQualifiers.localSize[2] = value;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -3401,6 +3416,9 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
|
||||
// if there are blocks, atomic counters, variables, etc.
|
||||
void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& qualifier)
|
||||
{
|
||||
if (qualifier.storage == EvqShared && qualifier.hasLayout())
|
||||
error(loc, "cannot apply layout qualifiers to a shared variable", "shared", "");
|
||||
|
||||
// "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
|
||||
if (qualifier.layoutComponent != TQualifier::layoutComponentEnd && qualifier.layoutLocation == TQualifier::layoutLocationEnd)
|
||||
error(loc, "must specify 'location' to use 'component'", "component", "");
|
||||
@@ -3490,6 +3508,10 @@ void TParseContext::checkNoShaderLayouts(TSourceLoc loc, const TShaderQualifiers
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (shaderQualifiers.localSize[i] > 1)
|
||||
error(loc, message, "local_size", "");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -4561,6 +4583,34 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
|
||||
else
|
||||
error(loc, "can only apply to 'in'", "point_mode", "");
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (publicType.shaderQualifiers.localSize[i] > 1) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn) {
|
||||
if (! intermediate.setLocalSize(i, publicType.shaderQualifiers.localSize[i]))
|
||||
error(loc, "cannot change previously set size", "local_size", "");
|
||||
else {
|
||||
int max;
|
||||
switch (i) {
|
||||
case 0: max = resources.maxComputeWorkGroupSizeX; break;
|
||||
case 1: max = resources.maxComputeWorkGroupSizeY; break;
|
||||
case 2: max = resources.maxComputeWorkGroupSizeZ; break;
|
||||
default: break;
|
||||
}
|
||||
if (intermediate.getLocalSize(i) > (unsigned int)max)
|
||||
error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
|
||||
|
||||
// Fix the existing constant gl_WorkGroupSize with this new information.
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find("gl_WorkGroupSize", &builtIn);
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
TVariable* workGroupSize = symbol->getAsVariable();
|
||||
workGroupSize->getWritableConstArray()[i].setUConst(intermediate.getLocalSize(i));
|
||||
}
|
||||
} else
|
||||
error(loc, "can only apply to 'in'", "local_size", "");
|
||||
}
|
||||
}
|
||||
if (publicType.shaderQualifiers.earlyFragmentTests) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn)
|
||||
intermediate.setEarlyFragmentTests();
|
||||
|
||||
@@ -242,8 +242,7 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
||||
|
||||
if (! copyOf.unionArray.empty()) {
|
||||
assert(! copyOf.type.isStruct());
|
||||
TConstUnionArray newArray(1);
|
||||
newArray[0] = copyOf.unionArray[0];
|
||||
TConstUnionArray newArray(copyOf.unionArray, 0, copyOf.unionArray.size());
|
||||
unionArray = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ public:
|
||||
virtual TType& getWritableType() { assert(writable); return type; }
|
||||
virtual bool isUserType() const { return userType; }
|
||||
virtual const TConstUnionArray& getConstArray() const { return unionArray; }
|
||||
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return unionArray; }
|
||||
virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
@@ -1220,7 +1220,7 @@ storage_qualifier
|
||||
parseContext.profileRequires($1.loc, ECoreProfile, 430, 0, "shared");
|
||||
parseContext.requireStage($1.loc, EShLangCompute, "shared");
|
||||
$$.init($1.loc);
|
||||
$$.qualifier.shared = true;
|
||||
$$.qualifier.storage = EvqShared;
|
||||
}
|
||||
| COHERENT {
|
||||
$$.init($1.loc);
|
||||
|
||||
@@ -429,7 +429,7 @@ void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstU
|
||||
case EbtFloat:
|
||||
case EbtDouble:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%f", constUnion[i].getDConst());
|
||||
|
||||
@@ -438,7 +438,7 @@ void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstU
|
||||
break;
|
||||
case EbtInt:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int");
|
||||
|
||||
@@ -447,7 +447,7 @@ void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstU
|
||||
break;
|
||||
case EbtUint:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint");
|
||||
|
||||
@@ -616,9 +616,10 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,13 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
|
||||
if (unit.pointMode)
|
||||
pointMode = true;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (localSize[i] > 1)
|
||||
localSize[i] = unit.localSize[i];
|
||||
else if (localSize[i] != unit.localSize[i])
|
||||
error(infoSink, "Contradictory local size");
|
||||
}
|
||||
|
||||
if (unit.xfbMode)
|
||||
xfbMode = true;
|
||||
for (size_t b = 0; b < xfbBuffers.size(); ++b) {
|
||||
|
||||
@@ -114,6 +114,9 @@ public:
|
||||
invocations(0), vertices(0), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false),
|
||||
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), xfbMode(false)
|
||||
{
|
||||
localSize[0] = 1;
|
||||
localSize[1] = 1;
|
||||
localSize[2] = 1;
|
||||
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
|
||||
}
|
||||
void setLimits(const TBuiltInResource& r) { resources = r; }
|
||||
@@ -221,6 +224,16 @@ public:
|
||||
TVertexOrder getVertexOrder() const { return vertexOrder; }
|
||||
void setPointMode() { pointMode = true; }
|
||||
bool getPointMode() const { return pointMode; }
|
||||
|
||||
bool setLocalSize(int dim, int size)
|
||||
{
|
||||
if (localSize[dim] > 1)
|
||||
return size == localSize[dim];
|
||||
localSize[dim] = size;
|
||||
return true;
|
||||
}
|
||||
unsigned int getLocalSize(int dim) const { return localSize[dim]; }
|
||||
|
||||
void setXfbMode() { xfbMode = true; }
|
||||
bool getXfbMode() const { return xfbMode; }
|
||||
bool setOutputPrimitive(TLayoutGeometry p)
|
||||
@@ -289,6 +302,7 @@ protected:
|
||||
TVertexSpacing vertexSpacing;
|
||||
TVertexOrder vertexOrder;
|
||||
bool pointMode;
|
||||
int localSize[3];
|
||||
bool earlyFragmentTests;
|
||||
bool xfbMode;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user