Commit 2cc85b3b by Martin Radev Committed by Commit Bot

Add support for images in the compiler

The patch adds support for GLSL ES 3.1 image types. Internal format layout qualifiers for images are added. Support for the readonly and writeonly qualifiers are added. The other memory qualifiers are omitted as to make the patch simpler. Tests are added which check for correct and incorrect usage of images, internal format layout and memory qualifiers. BUG=angleproject:1442 TEST=angle_unittests TEST=angle_end2end_tests Change-Id: Ie4d3acb2a195de11b405ad54110a04c4c1de0b7e Reviewed-on: https://chromium-review.googlesource.com/378855Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 2a3dc0f0
...@@ -247,7 +247,19 @@ int VariableRowCount(GLenum type) ...@@ -247,7 +247,19 @@ int VariableRowCount(GLenum type)
case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_2D_SHADOW:
case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_CUBE_SHADOW:
case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW:
return 1; case GL_IMAGE_2D:
case GL_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_2D:
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
case GL_IMAGE_3D:
case GL_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_3D:
case GL_IMAGE_CUBE:
case GL_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_CUBE:
return 1;
case GL_FLOAT_MAT2: case GL_FLOAT_MAT2:
case GL_FLOAT_MAT3x2: case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT4x2: case GL_FLOAT_MAT4x2:
......
...@@ -76,19 +76,98 @@ enum TBasicType ...@@ -76,19 +76,98 @@ enum TBasicType
EbtSampler2DShadow, EbtSampler2DShadow,
EbtSamplerCubeShadow, EbtSamplerCubeShadow,
EbtSampler2DArrayShadow, EbtSampler2DArrayShadow,
EbtGuardSamplerEnd, // non type: see implementation of IsSampler() EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D
EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D
EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube
EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and usampler2DArray EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and
// usampler2DArray
// images
EbtGuardImageBegin,
EbtImage2D,
EbtIImage2D,
EbtUImage2D,
EbtImage3D,
EbtIImage3D,
EbtUImage3D,
EbtImage2DArray,
EbtIImage2DArray,
EbtUImage2DArray,
EbtImageCube,
EbtIImageCube,
EbtUImageCube,
EbtGuardImageEnd,
EbtGuardGImageBegin,
EbtGImage2D, // non type: represents image2D, uimage2D, iimage2D
EbtGImage3D, // non type: represents image3D, uimage3D, iimage3D
EbtGImage2DArray, // non type: represents image2DArray, uimage2DArray, iimage2DArray
EbtGImageCube, // non type: represents imageCube, uimageCube, iimageCube
EbtGuardGImageEnd,
EbtStruct, EbtStruct,
EbtInterfaceBlock, EbtInterfaceBlock,
EbtAddress, // should be deprecated?? EbtAddress, // should be deprecated??
// end of list // end of list
EbtLast EbtLast
}; };
inline TBasicType convertGImageToFloatImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtImage2D;
case EbtGImage3D:
return EbtImage3D;
case EbtGImage2DArray:
return EbtImage2DArray;
case EbtGImageCube:
return EbtImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
inline TBasicType convertGImageToIntImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtIImage2D;
case EbtGImage3D:
return EbtIImage3D;
case EbtGImage2DArray:
return EbtIImage2DArray;
case EbtGImageCube:
return EbtIImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
inline TBasicType convertGImageToUnsignedImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtUImage2D;
case EbtGImage3D:
return EbtUImage3D;
case EbtGImage2DArray:
return EbtUImage2DArray;
case EbtGImageCube:
return EbtUImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
const char* getBasicString(TBasicType t); const char* getBasicString(TBasicType t);
inline bool IsSampler(TBasicType type) inline bool IsSampler(TBasicType type)
...@@ -96,6 +175,22 @@ inline bool IsSampler(TBasicType type) ...@@ -96,6 +175,22 @@ inline bool IsSampler(TBasicType type)
return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
} }
inline bool IsImage(TBasicType type)
{
return type > EbtGuardImageBegin && type < EbtGuardImageEnd;
}
inline bool IsGImage(TBasicType type)
{
return type > EbtGuardGImageBegin && type < EbtGuardGImageEnd;
}
inline bool IsOpaqueType(TBasicType type)
{
// TODO (mradev): add atomic types as opaque.
return IsSampler(type) || IsImage(type);
}
inline bool IsIntegerSampler(TBasicType type) inline bool IsIntegerSampler(TBasicType type)
{ {
switch (type) switch (type)
...@@ -126,6 +221,56 @@ inline bool IsIntegerSampler(TBasicType type) ...@@ -126,6 +221,56 @@ inline bool IsIntegerSampler(TBasicType type)
return false; return false;
} }
inline bool IsFloatImage(TBasicType type)
{
switch (type)
{
case EbtImage2D:
case EbtImage3D:
case EbtImage2DArray:
case EbtImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsIntegerImage(TBasicType type)
{
switch (type)
{
case EbtIImage2D:
case EbtIImage3D:
case EbtIImage2DArray:
case EbtIImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsUnsignedImage(TBasicType type)
{
switch (type)
{
case EbtUImage2D:
case EbtUImage3D:
case EbtUImage2DArray:
case EbtUImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsSampler2D(TBasicType type) inline bool IsSampler2D(TBasicType type)
{ {
switch (type) switch (type)
...@@ -283,7 +428,7 @@ inline bool IsInteger(TBasicType type) ...@@ -283,7 +428,7 @@ inline bool IsInteger(TBasicType type)
inline bool SupportsPrecision(TBasicType type) inline bool SupportsPrecision(TBasicType type)
{ {
return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); return type == EbtFloat || type == EbtInt || type == EbtUInt || IsOpaqueType(type);
} }
// //
...@@ -360,6 +505,10 @@ enum TQualifier ...@@ -360,6 +505,10 @@ enum TQualifier
EvqGlobalInvocationID, EvqGlobalInvocationID,
EvqLocalInvocationIndex, EvqLocalInvocationIndex,
// GLSL ES 3.1 memory qualifiers
EvqReadOnly,
EvqWriteOnly,
// end of list // end of list
EvqLast EvqLast
}; };
...@@ -369,6 +518,24 @@ inline bool IsQualifierUnspecified(TQualifier qualifier) ...@@ -369,6 +518,24 @@ inline bool IsQualifierUnspecified(TQualifier qualifier)
return (qualifier == EvqTemporary || qualifier == EvqGlobal); return (qualifier == EvqTemporary || qualifier == EvqGlobal);
} }
enum TLayoutImageInternalFormat
{
EiifUnspecified,
EiifRGBA32F,
EiifRGBA16F,
EiifR32F,
EiifRGBA32UI,
EiifRGBA16UI,
EiifRGBA8UI,
EiifR32UI,
EiifRGBA32I,
EiifRGBA16I,
EiifRGBA8I,
EiifR32I,
EiifRGBA8,
EiifRGBA8_SNORM
};
enum TLayoutMatrixPacking enum TLayoutMatrixPacking
{ {
EmpUnspecified, EmpUnspecified,
...@@ -394,6 +561,9 @@ struct TLayoutQualifier ...@@ -394,6 +561,9 @@ struct TLayoutQualifier
// Compute shader layout qualifiers. // Compute shader layout qualifiers.
sh::WorkGroupSize localSize; sh::WorkGroupSize localSize;
// Image format layout qualifier
TLayoutImageInternalFormat imageInternalFormat;
static TLayoutQualifier create() static TLayoutQualifier create()
{ {
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
...@@ -405,20 +575,23 @@ struct TLayoutQualifier ...@@ -405,20 +575,23 @@ struct TLayoutQualifier
layoutQualifier.localSize.fill(-1); layoutQualifier.localSize.fill(-1);
layoutQualifier.imageInternalFormat = EiifUnspecified;
return layoutQualifier; return layoutQualifier;
} }
bool isEmpty() const bool isEmpty() const
{ {
return location == -1 && matrixPacking == EmpUnspecified && return location == -1 && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && !localSize.isAnyValueSet(); blockStorage == EbsUnspecified && !localSize.isAnyValueSet() &&
imageInternalFormat == EiifUnspecified;
} }
bool isCombinationValid() const bool isCombinationValid() const
{ {
bool workSizeSpecified = localSize.isAnyValueSet(); bool workSizeSpecified = localSize.isAnyValueSet();
bool otherLayoutQualifiersSpecified = bool otherLayoutQualifiersSpecified =
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified); (location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified ||
imageInternalFormat != EiifUnspecified);
// we can have either the work group size specified, or the other layout qualifiers // we can have either the work group size specified, or the other layout qualifiers
return !(workSizeSpecified && otherLayoutQualifiersSpecified); return !(workSizeSpecified && otherLayoutQualifiersSpecified);
...@@ -430,6 +603,26 @@ struct TLayoutQualifier ...@@ -430,6 +603,26 @@ struct TLayoutQualifier
} }
}; };
struct TMemoryQualifier
{
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
// An image can be qualified as both readonly and writeonly. It still can be can be used with
// imageSize().
bool readonly;
bool writeonly;
static TMemoryQualifier create()
{
TMemoryQualifier memoryQualifier;
memoryQualifier.readonly = false;
memoryQualifier.writeonly = false;
return memoryQualifier;
}
bool isEmpty() { return !readonly && !writeonly; }
};
inline const char *getWorkGroupSizeString(size_t dimension) inline const char *getWorkGroupSizeString(size_t dimension)
{ {
switch (dimension) switch (dimension)
...@@ -500,6 +693,8 @@ inline const char* getQualifierString(TQualifier q) ...@@ -500,6 +693,8 @@ inline const char* getQualifierString(TQualifier q)
case EvqLocalInvocationID: return "LocalInvocationID"; case EvqLocalInvocationID: return "LocalInvocationID";
case EvqGlobalInvocationID: return "GlobalInvocationID"; case EvqGlobalInvocationID: return "GlobalInvocationID";
case EvqLocalInvocationIndex: return "LocalInvocationIndex"; case EvqLocalInvocationIndex: return "LocalInvocationIndex";
case EvqReadOnly: return "readonly";
case EvqWriteOnly: return "writeonly";
default: UNREACHABLE(); return "unknown qualifier"; default: UNREACHABLE(); return "unknown qualifier";
} }
// clang-format on // clang-format on
...@@ -528,4 +723,40 @@ inline const char* getBlockStorageString(TLayoutBlockStorage bsq) ...@@ -528,4 +723,40 @@ inline const char* getBlockStorageString(TLayoutBlockStorage bsq)
} }
} }
inline const char *getImageInternalFormatString(TLayoutImageInternalFormat iifq)
{
switch (iifq)
{
case EiifRGBA32F:
return "rgba32f";
case EiifRGBA16F:
return "rgba16f";
case EiifR32F:
return "r32f";
case EiifRGBA32UI:
return "rgba32ui";
case EiifRGBA16UI:
return "rgba16ui";
case EiifRGBA8UI:
return "rgba8ui";
case EiifR32UI:
return "r32ui";
case EiifRGBA32I:
return "rgba32i";
case EiifRGBA16I:
return "rgba16i";
case EiifRGBA8I:
return "rgba8i";
case EiifR32I:
return "r32i";
case EiifRGBA8:
return "rgba8";
case EiifRGBA8_SNORM:
return "rgba8_snorm";
default:
UNREACHABLE();
return "unknown internal image format";
}
}
#endif // COMPILER_TRANSLATOR_BASETYPES_H_ #endif // COMPILER_TRANSLATOR_BASETYPES_H_
...@@ -517,14 +517,10 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) ...@@ -517,14 +517,10 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.push(); // ESSL3_1_BUILTINS symbolTable.push(); // ESSL3_1_BUILTINS
TPublicType integer; TPublicType integer;
integer.setBasicType(EbtInt); integer.initializeBasicType(EbtInt);
integer.initializeSizeForScalarTypes();
integer.array = false;
TPublicType floatingPoint; TPublicType floatingPoint;
floatingPoint.setBasicType(EbtFloat); floatingPoint.initializeBasicType(EbtFloat);
floatingPoint.initializeSizeForScalarTypes();
floatingPoint.array = false;
switch(shaderType) switch(shaderType)
{ {
...@@ -563,9 +559,7 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType) ...@@ -563,9 +559,7 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
{ {
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd); ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
TPublicType sampler; TPublicType sampler;
sampler.initializeSizeForScalarTypes(); sampler.initializeBasicType(samplerType);
sampler.setBasicType(samplerType);
sampler.array = false;
symbolTable.setDefaultPrecision(sampler, EbpLow); symbolTable.setDefaultPrecision(sampler, EbpLow);
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
{ {
const TType *voidType = TCache::getType(EbtVoid);
const TType *float1 = TCache::getType(EbtFloat); const TType *float1 = TCache::getType(EbtFloat);
const TType *float2 = TCache::getType(EbtFloat, 2); const TType *float2 = TCache::getType(EbtFloat, 2);
const TType *float3 = TCache::getType(EbtFloat, 3); const TType *float3 = TCache::getType(EbtFloat, 3);
...@@ -469,6 +470,26 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR ...@@ -469,6 +470,26 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2);
const TType *gimage2D = TCache::getType(EbtGImage2D);
const TType *gimage3D = TCache::getType(EbtGImage3D);
const TType *gimage2DArray = TCache::getType(EbtGImage2DArray);
const TType *gimageCube = TCache::getType(EbtGImageCube);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2D, int2, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage3D, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2DArray, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimageCube, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2D, int2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage3D, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2DArray, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimageCube, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int2, "imageSize", gimage2D);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage3D);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage2DArray);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimageCube);
// //
// Depth range in window coordinates // Depth range in window coordinates
// //
......
...@@ -150,6 +150,7 @@ class TIntermTyped : public TIntermNode ...@@ -150,6 +150,7 @@ class TIntermTyped : public TIntermNode
TBasicType getBasicType() const { return mType.getBasicType(); } TBasicType getBasicType() const { return mType.getBasicType(); }
TQualifier getQualifier() const { return mType.getQualifier(); } TQualifier getQualifier() const { return mType.getQualifier(); }
TPrecision getPrecision() const { return mType.getPrecision(); } TPrecision getPrecision() const { return mType.getPrecision(); }
TMemoryQualifier getMemoryQualifier() const { return mType.getMemoryQualifier(); }
int getCols() const { return mType.getCols(); } int getCols() const { return mType.getCols(); }
int getRows() const { return mType.getRows(); } int getRows() const { return mType.getRows(); }
int getNominalSize() const { return mType.getNominalSize(); } int getNominalSize() const { return mType.getNominalSize(); }
......
...@@ -49,6 +49,32 @@ bool isSingleStatement(TIntermNode *node) ...@@ -49,6 +49,32 @@ bool isSingleStatement(TIntermNode *node)
return true; return true;
} }
// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
// variables with specified layout qualifiers are copied. Additional checks are needed against the
// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
// NeedsToWriteLayoutQualifier.
bool NeedsToWriteLayoutQualifier(const TType &type)
{
if (type.getBasicType() == EbtInterfaceBlock)
{
return false;
}
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
layoutQualifier.location >= 0)
{
return true;
}
if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
{
return true;
}
return false;
}
} // namespace } // namespace
TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
...@@ -92,15 +118,30 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet( ...@@ -92,15 +118,30 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet(
void TOutputGLSLBase::writeLayoutQualifier(const TType &type) void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
{ {
if (!NeedsToWriteLayoutQualifier(type))
{
return;
}
TInfoSinkBase &out = objSink();
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
out << "layout(";
if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
{ {
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if (layoutQualifier.location >= 0) if (layoutQualifier.location >= 0)
{ {
TInfoSinkBase &out = objSink(); out << "location = " << layoutQualifier.location;
out << "layout(location = " << layoutQualifier.location << ") ";
} }
} }
if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
{
ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
}
out << ") ";
} }
void TOutputGLSLBase::writeVariableType(const TType &type) void TOutputGLSLBase::writeVariableType(const TType &type)
...@@ -141,6 +182,20 @@ void TOutputGLSLBase::writeVariableType(const TType &type) ...@@ -141,6 +182,20 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
out << type.getQualifierString() << " "; out << type.getQualifierString() << " ";
} }
} }
const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
if (memoryQualifier.readonly)
{
ASSERT(IsImage(type.getBasicType()));
out << "readonly ";
}
if (memoryQualifier.writeonly)
{
ASSERT(IsImage(type.getBasicType()));
out << "writeonly ";
}
// Declare the struct if we have not done so already. // Declare the struct if we have not done so already.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
{ {
......
...@@ -162,12 +162,12 @@ class TParseContext : angle::NonCopyable ...@@ -162,12 +162,12 @@ class TParseContext : angle::NonCopyable
bool checkIsNotSampler(const TSourceLoc &line, bool checkIsNotSampler(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType, const TTypeSpecifierNonArray &pType,
const char *reason); const char *reason);
bool checkIsNotImage(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType,
const char *reason);
void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType); void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
void checkLocationIsNotSpecified(const TSourceLoc &location, void checkLocationIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier); const TLayoutQualifier &layoutQualifier);
void checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkIsParameterQualifierValid(const TSourceLoc &line, void checkIsParameterQualifierValid(const TSourceLoc &line,
const TTypeQualifierBuilder &typeQualifierBuilder, const TTypeQualifierBuilder &typeQualifierBuilder,
TType *type); TType *type);
...@@ -179,7 +179,8 @@ class TParseContext : angle::NonCopyable ...@@ -179,7 +179,8 @@ class TParseContext : angle::NonCopyable
int versionRequired); int versionRequired);
bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier); const TLayoutQualifier &layoutQualifier);
bool checkInternalFormatIsNotSpecified(const TSourceLoc &location,
TLayoutImageInternalFormat internalFormat);
void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
void checkInvariantVariableQualifier(bool invariant, void checkInvariantVariableQualifier(bool invariant,
const TQualifier qualifier, const TQualifier qualifier,
...@@ -187,7 +188,7 @@ class TParseContext : angle::NonCopyable ...@@ -187,7 +188,7 @@ class TParseContext : angle::NonCopyable
void checkInputOutputTypeIsValidES3(const TQualifier qualifier, void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TPublicType &type, const TPublicType &type,
const TSourceLoc &qualifierLocation); const TSourceLoc &qualifierLocation);
void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier);
const TPragma &pragma() const { return mDirectiveHandler.pragma(); } const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); } const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
bool supportsExtension(const char *extension); bool supportsExtension(const char *extension);
...@@ -195,7 +196,6 @@ class TParseContext : angle::NonCopyable ...@@ -195,7 +196,6 @@ class TParseContext : angle::NonCopyable
void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior); void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl); void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl);
bool containsSampler(const TType &type);
const TFunction* findFunction( const TFunction* findFunction(
const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0); const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line, bool executeInitializer(const TSourceLoc &line,
...@@ -356,6 +356,9 @@ class TParseContext : angle::NonCopyable ...@@ -356,6 +356,9 @@ class TParseContext : angle::NonCopyable
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
void checkTextureOffsetConst(TIntermAggregate *functionCall); void checkTextureOffsetConst(TIntermAggregate *functionCall);
void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
const TIntermAggregate *functionCall);
TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall,
TIntermNode *paramNode, TIntermNode *paramNode,
TIntermNode *thisNode, TIntermNode *thisNode,
...@@ -392,6 +395,18 @@ class TParseContext : angle::NonCopyable ...@@ -392,6 +395,18 @@ class TParseContext : angle::NonCopyable
// Assumes that multiplication op has already been set based on the types. // Assumes that multiplication op has already been set based on the types.
bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right); bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
bool checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &memoryQualifier,
const TSourceLoc &location);
void checkOutParameterIsNotImage(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
TIntermTyped *addBinaryMathInternal( TIntermTyped *addBinaryMathInternal(
TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *createAssign( TIntermTyped *createAssign(
......
...@@ -48,6 +48,11 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, ...@@ -48,6 +48,11 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
} }
} }
if (rightQualifier.imageInternalFormat != EiifUnspecified)
{
joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
}
return joinedQualifier; return joinedQualifier;
} }
} // namespace sh } // namespace sh
...@@ -191,6 +196,31 @@ bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qual ...@@ -191,6 +196,31 @@ bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qual
} }
break; break;
} }
case QtMemory:
{
// Go over all of the memory qualifiers up until the current one and check for
// repetitions.
// Having both readonly and writeonly in a sequence is valid.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TQualifier currentQualifier =
static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
for (size_t j = 1; j < i; ++j)
{
if (qualifiers[j]->getType() == QtMemory)
{
const TMemoryQualifierWrapper *previousQualifierWrapper =
static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
if (currentQualifier == previousQualifier)
{
*errorMessage = previousQualifierWrapper->getQualifierString().c_str();
*errorMessage += " specified multiple times";
return true;
}
}
}
break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -263,6 +293,13 @@ bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualif ...@@ -263,6 +293,13 @@ bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualif
} }
foundStorage = true; foundStorage = true;
break; break;
case QtMemory:
if (foundPrecision)
{
*errorMessage = "Precision qualifiers have to be after memory qualifiers.";
return false;
}
break;
case QtPrecision: case QtPrecision:
foundPrecision = true; foundPrecision = true;
break; break;
...@@ -392,6 +429,22 @@ bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier stora ...@@ -392,6 +429,22 @@ bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier stora
return true; return true;
} }
bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
{
switch (memoryQualifier)
{
case EvqReadOnly:
joinedMemoryQualifier->readonly = true;
break;
case EvqWriteOnly:
joinedMemoryQualifier->writeonly = true;
break;
default:
UNREACHABLE();
}
return true;
}
TTypeQualifier GetVariableTypeQualifierFromSortedSequence( TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
const TTypeQualifierBuilder::QualifierSequence &sortedSequence, const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
TDiagnostics *diagnostics) TDiagnostics *diagnostics)
...@@ -445,6 +498,11 @@ TTypeQualifier GetVariableTypeQualifierFromSortedSequence( ...@@ -445,6 +498,11 @@ TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier(); static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
ASSERT(typeQualifier.precision != EbpUndefined); ASSERT(typeQualifier.precision != EbpUndefined);
break; break;
case QtMemory:
isQualifierValid = JoinMemoryQualifier(
&typeQualifier.memoryQualifier,
static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -474,6 +532,11 @@ TTypeQualifier GetParameterTypeQualifierFromSortedSequence( ...@@ -474,6 +532,11 @@ TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
case QtInterpolation: case QtInterpolation:
case QtLayout: case QtLayout:
break; break;
case QtMemory:
isQualifierValid = JoinMemoryQualifier(
&typeQualifier.memoryQualifier,
static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
break;
case QtStorage: case QtStorage:
isQualifierValid = JoinParameterStorageQualifier( isQualifierValid = JoinParameterStorageQualifier(
&typeQualifier.qualifier, &typeQualifier.qualifier,
...@@ -548,6 +611,11 @@ unsigned int TStorageQualifierWrapper::getRank() const ...@@ -548,6 +611,11 @@ unsigned int TStorageQualifierWrapper::getRank() const
} }
} }
unsigned int TMemoryQualifierWrapper::getRank() const
{
return 4u;
}
unsigned int TPrecisionQualifierWrapper::getRank() const unsigned int TPrecisionQualifierWrapper::getRank() const
{ {
return 5u; return 5u;
...@@ -555,6 +623,7 @@ unsigned int TPrecisionQualifierWrapper::getRank() const ...@@ -555,6 +623,7 @@ unsigned int TPrecisionQualifierWrapper::getRank() const
TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc) TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
: layoutQualifier(TLayoutQualifier::create()), : layoutQualifier(TLayoutQualifier::create()),
memoryQualifier(TMemoryQualifier::create()),
precision(EbpUndefined), precision(EbpUndefined),
qualifier(scope), qualifier(scope),
invariant(false), invariant(false),
......
...@@ -27,7 +27,8 @@ enum TQualifierType ...@@ -27,7 +27,8 @@ enum TQualifierType
QtInterpolation, QtInterpolation,
QtLayout, QtLayout,
QtStorage, QtStorage,
QtPrecision QtPrecision,
QtMemory
}; };
class TQualifierWrapperBase : angle::NonCopyable class TQualifierWrapperBase : angle::NonCopyable
...@@ -127,6 +128,24 @@ class TPrecisionQualifierWrapper final : public TQualifierWrapperBase ...@@ -127,6 +128,24 @@ class TPrecisionQualifierWrapper final : public TQualifierWrapperBase
TPrecision mPrecisionQualifier; TPrecision mPrecisionQualifier;
}; };
class TMemoryQualifierWrapper final : public TQualifierWrapperBase
{
public:
TMemoryQualifierWrapper(TQualifier memoryQualifier, const TSourceLoc &line)
: TQualifierWrapperBase(line), mMemoryQualifier(memoryQualifier)
{
}
~TMemoryQualifierWrapper() {}
TQualifierType getType() const { return QtMemory; }
TString getQualifierString() const { return ::getQualifierString(mMemoryQualifier); }
TQualifier getQualifier() const { return mMemoryQualifier; }
unsigned int getRank() const;
private:
TQualifier mMemoryQualifier;
};
// TTypeQualifier tightly covers type_qualifier from the grammar // TTypeQualifier tightly covers type_qualifier from the grammar
struct TTypeQualifier struct TTypeQualifier
{ {
...@@ -134,6 +153,7 @@ struct TTypeQualifier ...@@ -134,6 +153,7 @@ struct TTypeQualifier
TTypeQualifier(TQualifier scope, const TSourceLoc &loc); TTypeQualifier(TQualifier scope, const TSourceLoc &loc);
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
TMemoryQualifier memoryQualifier;
TPrecision precision; TPrecision precision;
TQualifier qualifier; TQualifier qualifier;
bool invariant; bool invariant;
......
...@@ -249,6 +249,43 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e ...@@ -249,6 +249,43 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
} }
else if (IsGImage(ptype1->getBasicType()))
{
insertUnmangledBuiltIn(name);
const TType *floatType = TCache::getType(EbtFloat, 4);
const TType *intType = TCache::getType(EbtInt, 4);
const TType *unsignedType = TCache::getType(EbtUInt, 4);
const TType *floatImage =
TCache::getType(convertGImageToFloatImage(ptype1->getBasicType()));
const TType *intImage = TCache::getType(convertGImageToIntImage(ptype1->getBasicType()));
const TType *unsignedImage =
TCache::getType(convertGImageToUnsignedImage(ptype1->getBasicType()));
// GLSL ES 3.10, Revision 4, 8.12 Image Functions
if (rvalue->getBasicType() == EbtGVec4)
{
// imageLoad
insertBuiltIn(level, floatType, name, floatImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, intType, name, intImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, unsignedType, name, unsignedImage, ptype2, ptype3, ptype4, ptype5);
}
else if (rvalue->getBasicType() == EbtVoid)
{
// imageStore
insertBuiltIn(level, rvalue, name, floatImage, ptype2, floatType, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, intImage, ptype2, intType, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, unsignedType, ptype4, ptype5);
}
else
{
// imageSize
insertBuiltIn(level, rvalue, name, floatImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, intImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, ptype3, ptype4, ptype5);
}
}
else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3)) else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
{ {
ASSERT(!ptype4 && !ptype5); ASSERT(!ptype4 && !ptype5);
......
...@@ -44,6 +44,30 @@ const char* getBasicString(TBasicType t) ...@@ -44,6 +44,30 @@ const char* getBasicString(TBasicType t)
case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; case EbtSampler2DArrayShadow: return "sampler2DArrayShadow";
case EbtStruct: return "structure"; case EbtStruct: return "structure";
case EbtInterfaceBlock: return "interface block"; case EbtInterfaceBlock: return "interface block";
case EbtImage2D:
return "image2D";
case EbtIImage2D:
return "iimage2D";
case EbtUImage2D:
return "uimage2D";
case EbtImage3D:
return "image3D";
case EbtIImage3D:
return "iimage3D";
case EbtUImage3D:
return "uimage3D";
case EbtImage2DArray:
return "image2DArray";
case EbtIImage2DArray:
return "iimage2DArray";
case EbtUImage2DArray:
return "uimage2DArray";
case EbtImageCube:
return "imageCube";
case EbtIImageCube:
return "iimageCube";
case EbtUImageCube:
return "uimageCube";
default: UNREACHABLE(); return "unknown type"; default: UNREACHABLE(); return "unknown type";
} }
} }
...@@ -53,6 +77,7 @@ TType::TType(const TPublicType &p) ...@@ -53,6 +77,7 @@ TType::TType(const TPublicType &p)
precision(p.precision), precision(p.precision),
qualifier(p.qualifier), qualifier(p.qualifier),
invariant(p.invariant), invariant(p.invariant),
memoryQualifier(p.memoryQualifier),
layoutQualifier(p.layoutQualifier), layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()), primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()), secondarySize(p.getSecondarySize()),
...@@ -283,6 +308,42 @@ TString TType::buildMangledName() const ...@@ -283,6 +308,42 @@ TString TType::buildMangledName() const
case EbtSampler2DArrayShadow: case EbtSampler2DArrayShadow:
mangledName += "s2as"; mangledName += "s2as";
break; break;
case EbtImage2D:
mangledName += "im2";
break;
case EbtIImage2D:
mangledName += "iim2";
break;
case EbtUImage2D:
mangledName += "uim2";
break;
case EbtImage3D:
mangledName += "im3";
break;
case EbtIImage3D:
mangledName += "iim3";
break;
case EbtUImage3D:
mangledName += "uim3";
break;
case EbtImage2DArray:
mangledName += "im2a";
break;
case EbtIImage2DArray:
mangledName += "iim2a";
break;
case EbtUImage2DArray:
mangledName += "uim2a";
break;
case EbtImageCube:
mangledName += "imc";
break;
case EbtIImageCube:
mangledName += "iimc";
break;
case EbtUImageCube:
mangledName += "uimc";
break;
case EbtStruct: case EbtStruct:
mangledName += structure->mangledName(); mangledName += structure->mangledName();
break; break;
...@@ -381,6 +442,17 @@ bool TStructure::containsSamplers() const ...@@ -381,6 +442,17 @@ bool TStructure::containsSamplers() const
return false; return false;
} }
bool TStructure::containsImages() const
{
for (size_t i = 0; i < mFields->size(); ++i)
{
const TType *fieldType = (*mFields)[i]->type();
if (IsImage(fieldType->getBasicType()) || fieldType->isStructureContainingImages())
return true;
}
return false;
}
void TStructure::createSamplerSymbols(const TString &structName, void TStructure::createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
const unsigned int arrayOfStructsSize, const unsigned int arrayOfStructsSize,
......
...@@ -114,6 +114,7 @@ class TStructure : public TFieldListCollection ...@@ -114,6 +114,7 @@ class TStructure : public TFieldListCollection
bool containsArrays() const; bool containsArrays() const;
bool containsType(TBasicType t) const; bool containsType(TBasicType t) const;
bool containsSamplers() const; bool containsSamplers() const;
bool containsImages() const;
void createSamplerSymbols(const TString &structName, void createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
...@@ -229,10 +230,18 @@ class TType ...@@ -229,10 +230,18 @@ class TType
public: public:
POOL_ALLOCATOR_NEW_DELETE(); POOL_ALLOCATOR_NEW_DELETE();
TType() TType()
: type(EbtVoid), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false), : type(EbtVoid),
precision(EbpUndefined),
qualifier(EvqGlobal),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(0), secondarySize(0), array(false), arraySize(0), primarySize(0),
interfaceBlock(nullptr), structure(nullptr) secondarySize(0),
array(false),
arraySize(0),
interfaceBlock(nullptr),
structure(nullptr)
{ {
} }
explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1) explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1)
...@@ -240,6 +249,7 @@ class TType ...@@ -240,6 +249,7 @@ class TType
precision(EbpUndefined), precision(EbpUndefined),
qualifier(EvqGlobal), qualifier(EvqGlobal),
invariant(false), invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), primarySize(ps),
secondarySize(ss), secondarySize(ss),
...@@ -249,12 +259,24 @@ class TType ...@@ -249,12 +259,24 @@ class TType
structure(0) structure(0)
{ {
} }
TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, TType(TBasicType t,
unsigned char ps = 1, unsigned char ss = 1, bool a = false) TPrecision p,
: type(t), precision(p), qualifier(q), invariant(false), TQualifier q = EvqTemporary,
unsigned char ps = 1,
unsigned char ss = 1,
bool a = false)
: type(t),
precision(p),
qualifier(q),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), secondarySize(ss), array(a), arraySize(0), primarySize(ps),
interfaceBlock(0), structure(0) secondarySize(ss),
array(a),
arraySize(0),
interfaceBlock(0),
structure(0)
{ {
} }
explicit TType(const TPublicType &p); explicit TType(const TPublicType &p);
...@@ -263,6 +285,7 @@ class TType ...@@ -263,6 +285,7 @@ class TType
precision(p), precision(p),
qualifier(EvqTemporary), qualifier(EvqTemporary),
invariant(false), invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(1), primarySize(1),
secondarySize(1), secondarySize(1),
...@@ -272,12 +295,22 @@ class TType ...@@ -272,12 +295,22 @@ class TType
structure(userDef) structure(userDef)
{ {
} }
TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn, TType(TInterfaceBlock *interfaceBlockIn,
TLayoutQualifier layoutQualifierIn, int arraySizeIn) TQualifier qualifierIn,
: type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn), TLayoutQualifier layoutQualifierIn,
invariant(false), layoutQualifier(layoutQualifierIn), int arraySizeIn)
primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), : type(EbtInterfaceBlock),
interfaceBlock(interfaceBlockIn), structure(0) precision(EbpUndefined),
qualifier(qualifierIn),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(layoutQualifierIn),
primarySize(1),
secondarySize(1),
array(arraySizeIn > 0),
arraySize(arraySizeIn),
interfaceBlock(interfaceBlockIn),
structure(0)
{ {
} }
...@@ -322,6 +355,9 @@ class TType ...@@ -322,6 +355,9 @@ class TType
void setInvariant(bool i) { invariant = i; } void setInvariant(bool i) { invariant = i; }
TMemoryQualifier getMemoryQualifier() const { return memoryQualifier; }
void setMemoryQualifier(const TMemoryQualifier &mq) { memoryQualifier = mq; }
TLayoutQualifier getLayoutQualifier() const TLayoutQualifier getLayoutQualifier() const
{ {
return layoutQualifier; return layoutQualifier;
...@@ -547,6 +583,11 @@ class TType ...@@ -547,6 +583,11 @@ class TType
return structure ? structure->containsSamplers() : false; return structure ? structure->containsSamplers() : false;
} }
bool isStructureContainingImages() const
{
return structure ? structure->containsImages() : false;
}
void createSamplerSymbols(const TString &structName, void createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
const unsigned int arrayOfStructsSize, const unsigned int arrayOfStructsSize,
...@@ -573,6 +614,7 @@ class TType ...@@ -573,6 +614,7 @@ class TType
TPrecision precision; TPrecision precision;
TQualifier qualifier; TQualifier qualifier;
bool invariant; bool invariant;
TMemoryQualifier memoryQualifier;
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix unsigned char primarySize; // size of vector or cols matrix
unsigned char secondarySize; // rows of a matrix unsigned char secondarySize; // rows of a matrix
...@@ -641,6 +683,7 @@ struct TPublicType ...@@ -641,6 +683,7 @@ struct TPublicType
{ {
TTypeSpecifierNonArray typeSpecifierNonArray; TTypeSpecifierNonArray typeSpecifierNonArray;
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
TMemoryQualifier memoryQualifier;
TQualifier qualifier; TQualifier qualifier;
bool invariant; bool invariant;
TPrecision precision; TPrecision precision;
...@@ -651,6 +694,7 @@ struct TPublicType ...@@ -651,6 +694,7 @@ struct TPublicType
{ {
typeSpecifierNonArray = typeSpecifier; typeSpecifierNonArray = typeSpecifier;
layoutQualifier = TLayoutQualifier::create(); layoutQualifier = TLayoutQualifier::create();
memoryQualifier = TMemoryQualifier::create();
qualifier = q; qualifier = q;
invariant = false; invariant = false;
precision = EbpUndefined; precision = EbpUndefined;
...@@ -658,16 +702,25 @@ struct TPublicType ...@@ -658,16 +702,25 @@ struct TPublicType
arraySize = 0; arraySize = 0;
} }
void initializeBasicType(TBasicType basicType)
{
typeSpecifierNonArray.type = basicType;
typeSpecifierNonArray.primarySize = 1;
typeSpecifierNonArray.secondarySize = 1;
layoutQualifier = TLayoutQualifier::create();
memoryQualifier = TMemoryQualifier::create();
qualifier = EvqTemporary;
invariant = false;
precision = EbpUndefined;
array = false;
arraySize = 0;
}
TBasicType getBasicType() const { return typeSpecifierNonArray.type; } TBasicType getBasicType() const { return typeSpecifierNonArray.type; }
void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; } void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; }
unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; } unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; }
unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; } unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; }
void initializeSizeForScalarTypes()
{
typeSpecifierNonArray.primarySize = 1;
typeSpecifierNonArray.secondarySize = 1;
}
const TType *getUserDef() const { return typeSpecifierNonArray.userDef; } const TType *getUserDef() const { return typeSpecifierNonArray.userDef; }
const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; } const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
......
...@@ -71,6 +71,7 @@ static int reserved_word(yyscan_t yyscanner); ...@@ -71,6 +71,7 @@ static int reserved_word(yyscan_t yyscanner);
static int ES2_reserved_ES3_keyword(TParseContext *context, int token); static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
static int ES2_keyword_ES3_reserved(TParseContext *context, int token); static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
static int ES2_ident_ES3_keyword(TParseContext *context, int token); static int ES2_ident_ES3_keyword(TParseContext *context, int token);
static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
static int uint_constant(TParseContext *context); static int uint_constant(TParseContext *context);
static int int_constant(TParseContext *context); static int int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner); static int float_constant(yyscan_t yyscanner);
...@@ -187,11 +188,24 @@ O [0-7] ...@@ -187,11 +188,24 @@ O [0-7]
"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); } "layout" { return ES2_ident_ES3_keyword(context, LAYOUT); }
"image2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2D); }
"iimage2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2D); }
"uimage2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2D); }
"image2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2DARRAY); }
"iimage2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2DARRAY); }
"uimage2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2DARRAY); }
"image3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE3D); }
"uimage3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE3D); }
"iimage3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE3D); }
"iimageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGECUBE); }
"uimageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGECUBE); }
"imageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); }
"readonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); }
"writeonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); }
/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
"coherent" | "coherent" |
"restrict" | "restrict" |
"readonly" |
"writeonly" |
"resource" | "resource" |
"atomic_uint" | "atomic_uint" |
"noperspective" | "noperspective" |
...@@ -204,23 +218,11 @@ O [0-7] ...@@ -204,23 +218,11 @@ O [0-7]
"filter" | "filter" |
"image1D" | "image1D" |
"image2D" |
"image3D" |
"imageCube" |
"iimage1D" | "iimage1D" |
"iimage2D" |
"iimage3D" |
"iimageCube" |
"uimage1D" | "uimage1D" |
"uimage2D" |
"uimage3D" |
"uimageCube" |
"image1DArray" | "image1DArray" |
"image2DArray" |
"iimage1DArray" | "iimage1DArray" |
"iimage2DArray" |
"uimage1DArray" | "uimage1DArray" |
"uimage2DArray" |
"image1DShadow" | "image1DShadow" |
"image2DShadow" | "image2DShadow" |
"image1DArrayShadow" | "image1DArrayShadow" |
...@@ -463,6 +465,24 @@ int ES2_keyword_ES3_reserved(TParseContext *context, int token) ...@@ -463,6 +465,24 @@ int ES2_keyword_ES3_reserved(TParseContext *context, int token)
return token; return token;
} }
int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token)
{
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
yyscan_t yyscanner = (yyscan_t) context->getScanner();
if (context->getShaderVersion() < 300)
{
yylval->lex.string = NewPoolTString(yytext);
return check_type(yyscanner);
}
else if (context->getShaderVersion() == 300)
{
return reserved_word(yyscanner);
}
return token;
}
int ES2_ident_ES3_keyword(TParseContext *context, int token) int ES2_ident_ES3_keyword(TParseContext *context, int token)
{ {
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
......
...@@ -166,11 +166,14 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons ...@@ -166,11 +166,14 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING %token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
%token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 %token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3
%token <lex> CENTROID FLAT SMOOTH %token <lex> CENTROID FLAT SMOOTH
%token <lex> READONLY WRITEONLY
%token <lex> STRUCT VOID_TYPE WHILE %token <lex> STRUCT VOID_TYPE WHILE
%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY %token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY
%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY %token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
%token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY %token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY
%token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW %token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW
%token <lex> IMAGE2D IIMAGE2D UIMAGE2D IMAGE3D IIMAGE3D UIMAGE3D IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY
%token <lex> IMAGECUBE IIMAGECUBE UIMAGECUBE
%token <lex> LAYOUT %token <lex> LAYOUT
%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT %token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT
...@@ -215,8 +218,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons ...@@ -215,8 +218,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%type <interm.precision> precision_qualifier %type <interm.precision> precision_qualifier
%type <interm.layoutQualifier> layout_qualifier %type <interm.layoutQualifier> layout_qualifier
%type <interm.qualifier> storage_qualifier interpolation_qualifier %type <interm.qualifier> interpolation_qualifier
%type <interm.qualifierWrapper> single_type_qualifier invariant_qualifier %type <interm.qualifierWrapper> storage_qualifier single_type_qualifier invariant_qualifier
%type <interm.typeQualifierBuilder> type_qualifier %type <interm.typeQualifierBuilder> type_qualifier
%type <interm.typeSpecifierNonArray> type_specifier_nonarray struct_specifier %type <interm.typeSpecifierNonArray> type_specifier_nonarray struct_specifier
...@@ -854,11 +857,8 @@ invariant_qualifier ...@@ -854,11 +857,8 @@ invariant_qualifier
single_type_qualifier single_type_qualifier
: storage_qualifier { : storage_qualifier {
if (!context->declaringFunction() && $1 != EvqConst && !context->symbolTable.atGlobalLevel()) context->checkLocalVariableConstStorageQualifier(*$1);
{ $$ = $1;
context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1));
}
$$ = new TStorageQualifierWrapper($1, @1);
} }
| layout_qualifier { | layout_qualifier {
context->checkIsAtGlobalLevel(@1, "layout"); context->checkIsAtGlobalLevel(@1, "layout");
...@@ -883,43 +883,43 @@ storage_qualifier ...@@ -883,43 +883,43 @@ storage_qualifier
VERTEX_ONLY("attribute", @1); VERTEX_ONLY("attribute", @1);
ES2_ONLY("attribute", @1); ES2_ONLY("attribute", @1);
context->checkIsAtGlobalLevel(@1, "attribute"); context->checkIsAtGlobalLevel(@1, "attribute");
$$ = EvqAttribute; $$ = new TStorageQualifierWrapper(EvqAttribute, @1);
} }
| VARYING { | VARYING {
ES2_ONLY("varying", @1); ES2_ONLY("varying", @1);
context->checkIsAtGlobalLevel(@1, "varying"); context->checkIsAtGlobalLevel(@1, "varying");
if (context->getShaderType() == GL_VERTEX_SHADER) if (context->getShaderType() == GL_VERTEX_SHADER)
$$ = EvqVaryingOut; $$ = new TStorageQualifierWrapper(EvqVaryingOut, @1);
else else
$$ = EvqVaryingIn; $$ = new TStorageQualifierWrapper(EvqVaryingIn, @1);
} }
| CONST_QUAL { | CONST_QUAL {
$$ = EvqConst; $$ = new TStorageQualifierWrapper(EvqConst, @1);
} }
| IN_QUAL { | IN_QUAL {
if (context->declaringFunction()) if (context->declaringFunction())
{ {
$$ = EvqIn; $$ = new TStorageQualifierWrapper(EvqIn, @1);
} }
else if (context->getShaderType() == GL_FRAGMENT_SHADER) else if (context->getShaderType() == GL_FRAGMENT_SHADER)
{ {
ES3_OR_NEWER("in", @1, "storage qualifier"); ES3_OR_NEWER("in", @1, "storage qualifier");
$$ = EvqFragmentIn; $$ = new TStorageQualifierWrapper(EvqFragmentIn, @1);
} }
else if (context->getShaderType() == GL_VERTEX_SHADER) else if (context->getShaderType() == GL_VERTEX_SHADER)
{ {
ES3_OR_NEWER("in", @1, "storage qualifier"); ES3_OR_NEWER("in", @1, "storage qualifier");
$$ = EvqVertexIn; $$ = new TStorageQualifierWrapper(EvqVertexIn, @1);
} }
else else
{ {
$$ = EvqComputeIn; $$ = new TStorageQualifierWrapper(EvqComputeIn, @1);
} }
} }
| OUT_QUAL { | OUT_QUAL {
if (context->declaringFunction()) if (context->declaringFunction())
{ {
$$ = EvqOut; $$ = new TStorageQualifierWrapper(EvqOut, @1);
} }
else else
{ {
...@@ -927,11 +927,11 @@ storage_qualifier ...@@ -927,11 +927,11 @@ storage_qualifier
NON_COMPUTE_ONLY("out", @1); NON_COMPUTE_ONLY("out", @1);
if (context->getShaderType() == GL_FRAGMENT_SHADER) if (context->getShaderType() == GL_FRAGMENT_SHADER)
{ {
$$ = EvqFragmentOut; $$ = new TStorageQualifierWrapper(EvqFragmentOut, @1);
} }
else else
{ {
$$ = EvqVertexOut; $$ = new TStorageQualifierWrapper(EvqVertexOut, @1);
} }
} }
} }
...@@ -940,15 +940,21 @@ storage_qualifier ...@@ -940,15 +940,21 @@ storage_qualifier
{ {
context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters"); context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters");
} }
$$ = EvqInOut; $$ = new TStorageQualifierWrapper(EvqInOut, @1);
} }
| CENTROID { | CENTROID {
ES3_OR_NEWER("centroid", @1, "storage qualifier"); ES3_OR_NEWER("centroid", @1, "storage qualifier");
$$ = EvqCentroid; $$ = new TStorageQualifierWrapper(EvqCentroid, @1);
} }
| UNIFORM { | UNIFORM {
context->checkIsAtGlobalLevel(@1, "uniform"); context->checkIsAtGlobalLevel(@1, "uniform");
$$ = EvqUniform; $$ = new TStorageQualifierWrapper(EvqUniform, @1);
}
| READONLY {
$$ = new TMemoryQualifierWrapper(EvqReadOnly, @1);
}
| WRITEONLY {
$$ = new TMemoryQualifierWrapper(EvqWriteOnly, @1);
} }
; ;
...@@ -1182,6 +1188,42 @@ type_specifier_nonarray ...@@ -1182,6 +1188,42 @@ type_specifier_nonarray
| struct_specifier { | struct_specifier {
$$ = $1; $$ = $1;
} }
| IMAGE2D {
$$.initialize(EbtImage2D, @1);
}
| IIMAGE2D {
$$.initialize(EbtIImage2D, @1);
}
| UIMAGE2D {
$$.initialize(EbtUImage2D, @1);
}
| IMAGE3D {
$$.initialize(EbtImage3D, @1);
}
| IIMAGE3D {
$$.initialize(EbtIImage3D, @1);
}
| UIMAGE3D {
$$.initialize(EbtUImage3D, @1);
}
| IMAGE2DARRAY {
$$.initialize(EbtImage2DArray, @1);
}
| IIMAGE2DARRAY {
$$.initialize(EbtIImage2DArray, @1);
}
| UIMAGE2DARRAY {
$$.initialize(EbtUImage2DArray, @1);
}
| IMAGECUBE {
$$.initialize(EbtImageCube, @1);
}
| IIMAGECUBE {
$$.initialize(EbtIImageCube, @1);
}
| UIMAGECUBE {
$$.initialize(EbtUImageCube, @1);
}
| TYPE_NAME { | TYPE_NAME {
// //
// This is for user defined type names. The lexical phase looked up the // This is for user defined type names. The lexical phase looked up the
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -50,134 +50,148 @@ extern int yydebug; ...@@ -50,134 +50,148 @@ extern int yydebug;
/* Token type. */ /* Token type. */
#ifndef YYTOKENTYPE #ifndef YYTOKENTYPE
# define YYTOKENTYPE # define YYTOKENTYPE
enum yytokentype enum yytokentype
{ {
INVARIANT = 258, INVARIANT = 258,
HIGH_PRECISION = 259, HIGH_PRECISION = 259,
MEDIUM_PRECISION = 260, MEDIUM_PRECISION = 260,
LOW_PRECISION = 261, LOW_PRECISION = 261,
PRECISION = 262, PRECISION = 262,
ATTRIBUTE = 263, ATTRIBUTE = 263,
CONST_QUAL = 264, CONST_QUAL = 264,
BOOL_TYPE = 265, BOOL_TYPE = 265,
FLOAT_TYPE = 266, FLOAT_TYPE = 266,
INT_TYPE = 267, INT_TYPE = 267,
UINT_TYPE = 268, UINT_TYPE = 268,
BREAK = 269, BREAK = 269,
CONTINUE = 270, CONTINUE = 270,
DO = 271, DO = 271,
ELSE = 272, ELSE = 272,
FOR = 273, FOR = 273,
IF = 274, IF = 274,
DISCARD = 275, DISCARD = 275,
RETURN = 276, RETURN = 276,
SWITCH = 277, SWITCH = 277,
CASE = 278, CASE = 278,
DEFAULT = 279, DEFAULT = 279,
BVEC2 = 280, BVEC2 = 280,
BVEC3 = 281, BVEC3 = 281,
BVEC4 = 282, BVEC4 = 282,
IVEC2 = 283, IVEC2 = 283,
IVEC3 = 284, IVEC3 = 284,
IVEC4 = 285, IVEC4 = 285,
VEC2 = 286, VEC2 = 286,
VEC3 = 287, VEC3 = 287,
VEC4 = 288, VEC4 = 288,
UVEC2 = 289, UVEC2 = 289,
UVEC3 = 290, UVEC3 = 290,
UVEC4 = 291, UVEC4 = 291,
MATRIX2 = 292, MATRIX2 = 292,
MATRIX3 = 293, MATRIX3 = 293,
MATRIX4 = 294, MATRIX4 = 294,
IN_QUAL = 295, IN_QUAL = 295,
OUT_QUAL = 296, OUT_QUAL = 296,
INOUT_QUAL = 297, INOUT_QUAL = 297,
UNIFORM = 298, UNIFORM = 298,
VARYING = 299, VARYING = 299,
MATRIX2x3 = 300, MATRIX2x3 = 300,
MATRIX3x2 = 301, MATRIX3x2 = 301,
MATRIX2x4 = 302, MATRIX2x4 = 302,
MATRIX4x2 = 303, MATRIX4x2 = 303,
MATRIX3x4 = 304, MATRIX3x4 = 304,
MATRIX4x3 = 305, MATRIX4x3 = 305,
CENTROID = 306, CENTROID = 306,
FLAT = 307, FLAT = 307,
SMOOTH = 308, SMOOTH = 308,
STRUCT = 309, READONLY = 309,
VOID_TYPE = 310, WRITEONLY = 310,
WHILE = 311, STRUCT = 311,
SAMPLER2D = 312, VOID_TYPE = 312,
SAMPLERCUBE = 313, WHILE = 313,
SAMPLER_EXTERNAL_OES = 314, SAMPLER2D = 314,
SAMPLER2DRECT = 315, SAMPLERCUBE = 315,
SAMPLER2DARRAY = 316, SAMPLER_EXTERNAL_OES = 316,
ISAMPLER2D = 317, SAMPLER2DRECT = 317,
ISAMPLER3D = 318, SAMPLER2DARRAY = 318,
ISAMPLERCUBE = 319, ISAMPLER2D = 319,
ISAMPLER2DARRAY = 320, ISAMPLER3D = 320,
USAMPLER2D = 321, ISAMPLERCUBE = 321,
USAMPLER3D = 322, ISAMPLER2DARRAY = 322,
USAMPLERCUBE = 323, USAMPLER2D = 323,
USAMPLER2DARRAY = 324, USAMPLER3D = 324,
SAMPLER3D = 325, USAMPLERCUBE = 325,
SAMPLER3DRECT = 326, USAMPLER2DARRAY = 326,
SAMPLER2DSHADOW = 327, SAMPLER3D = 327,
SAMPLERCUBESHADOW = 328, SAMPLER3DRECT = 328,
SAMPLER2DARRAYSHADOW = 329, SAMPLER2DSHADOW = 329,
LAYOUT = 330, SAMPLERCUBESHADOW = 330,
IDENTIFIER = 331, SAMPLER2DARRAYSHADOW = 331,
TYPE_NAME = 332, IMAGE2D = 332,
FLOATCONSTANT = 333, IIMAGE2D = 333,
INTCONSTANT = 334, UIMAGE2D = 334,
UINTCONSTANT = 335, IMAGE3D = 335,
BOOLCONSTANT = 336, IIMAGE3D = 336,
FIELD_SELECTION = 337, UIMAGE3D = 337,
LEFT_OP = 338, IMAGE2DARRAY = 338,
RIGHT_OP = 339, IIMAGE2DARRAY = 339,
INC_OP = 340, UIMAGE2DARRAY = 340,
DEC_OP = 341, IMAGECUBE = 341,
LE_OP = 342, IIMAGECUBE = 342,
GE_OP = 343, UIMAGECUBE = 343,
EQ_OP = 344, LAYOUT = 344,
NE_OP = 345, IDENTIFIER = 345,
AND_OP = 346, TYPE_NAME = 346,
OR_OP = 347, FLOATCONSTANT = 347,
XOR_OP = 348, INTCONSTANT = 348,
MUL_ASSIGN = 349, UINTCONSTANT = 349,
DIV_ASSIGN = 350, BOOLCONSTANT = 350,
ADD_ASSIGN = 351, FIELD_SELECTION = 351,
MOD_ASSIGN = 352, LEFT_OP = 352,
LEFT_ASSIGN = 353, RIGHT_OP = 353,
RIGHT_ASSIGN = 354, INC_OP = 354,
AND_ASSIGN = 355, DEC_OP = 355,
XOR_ASSIGN = 356, LE_OP = 356,
OR_ASSIGN = 357, GE_OP = 357,
SUB_ASSIGN = 358, EQ_OP = 358,
LEFT_PAREN = 359, NE_OP = 359,
RIGHT_PAREN = 360, AND_OP = 360,
LEFT_BRACKET = 361, OR_OP = 361,
RIGHT_BRACKET = 362, XOR_OP = 362,
LEFT_BRACE = 363, MUL_ASSIGN = 363,
RIGHT_BRACE = 364, DIV_ASSIGN = 364,
DOT = 365, ADD_ASSIGN = 365,
COMMA = 366, MOD_ASSIGN = 366,
COLON = 367, LEFT_ASSIGN = 367,
EQUAL = 368, RIGHT_ASSIGN = 368,
SEMICOLON = 369, AND_ASSIGN = 369,
BANG = 370, XOR_ASSIGN = 370,
DASH = 371, OR_ASSIGN = 371,
TILDE = 372, SUB_ASSIGN = 372,
PLUS = 373, LEFT_PAREN = 373,
STAR = 374, RIGHT_PAREN = 374,
SLASH = 375, LEFT_BRACKET = 375,
PERCENT = 376, RIGHT_BRACKET = 376,
LEFT_ANGLE = 377, LEFT_BRACE = 377,
RIGHT_ANGLE = 378, RIGHT_BRACE = 378,
VERTICAL_BAR = 379, DOT = 379,
CARET = 380, COMMA = 380,
AMPERSAND = 381, COLON = 381,
QUESTION = 382 EQUAL = 382,
}; SEMICOLON = 383,
BANG = 384,
DASH = 385,
TILDE = 386,
PLUS = 387,
STAR = 388,
SLASH = 389,
PERCENT = 390,
LEFT_ANGLE = 391,
RIGHT_ANGLE = 392,
VERTICAL_BAR = 393,
CARET = 394,
AMPERSAND = 395,
QUESTION = 396
};
#endif #endif
/* Value type. */ /* Value type. */
...@@ -204,6 +218,7 @@ union YYSTYPE ...@@ -204,6 +218,7 @@ union YYSTYPE
TIntermNodePair nodePair; TIntermNodePair nodePair;
TIntermTyped* intermTypedNode; TIntermTyped* intermTypedNode;
TIntermAggregate* intermAggregate; TIntermAggregate* intermAggregate;
TIntermBlock *intermBlock;
TIntermSwitch* intermSwitch; TIntermSwitch* intermSwitch;
TIntermCase* intermCase; TIntermCase* intermCase;
}; };
......
...@@ -159,6 +159,30 @@ GLenum GLVariableType(const TType &type) ...@@ -159,6 +159,30 @@ GLenum GLVariableType(const TType &type)
case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW; case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW;
case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW; case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW;
case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW; case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW;
case EbtImage2D:
return GL_IMAGE_2D;
case EbtIImage2D:
return GL_INT_IMAGE_2D;
case EbtUImage2D:
return GL_UNSIGNED_INT_IMAGE_2D;
case EbtImage2DArray:
return GL_IMAGE_2D_ARRAY;
case EbtIImage2DArray:
return GL_INT_IMAGE_2D_ARRAY;
case EbtUImage2DArray:
return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
case EbtImage3D:
return GL_IMAGE_3D;
case EbtIImage3D:
return GL_INT_IMAGE_3D;
case EbtUImage3D:
return GL_UNSIGNED_INT_IMAGE_3D;
case EbtImageCube:
return GL_IMAGE_CUBE;
case EbtIImageCube:
return GL_INT_IMAGE_CUBE;
case EbtUImageCube:
return GL_UNSIGNED_INT_IMAGE_CUBE;
default: UNREACHABLE(); default: UNREACHABLE();
} }
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
'<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp', '<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RemovePow_test.cpp', '<(angle_path)/src/tests/compiler_tests/RemovePow_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderExtension_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShaderExtension_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderImage_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderVariable_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShaderVariable_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShCompile_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShCompile_test.cpp',
'<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp', '<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp',
......
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ShaderImage_test.cpp:
// Tests for images
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/TranslatorESSL.h"
#include "tests/test_utils/compiler_test.h"
namespace
{
// Checks that the imageStore call with mangled name imageStoreMangledName exists in the AST.
// Further each argument is checked whether it matches the expected properties given the compiled
// shader.
void CheckImageStoreCall(TIntermNode *astRoot,
const TString &imageStoreMangledName,
TBasicType imageType,
int storeLocationNominalSize,
TBasicType storeValueType,
int storeValueNominalSize)
{
const TIntermAggregate *imageStoreFunctionCall =
FindFunctionCallNode(astRoot, imageStoreMangledName);
ASSERT_NE(nullptr, imageStoreFunctionCall);
const TIntermSequence *storeArguments = imageStoreFunctionCall->getSequence();
ASSERT_EQ(3u, storeArguments->size());
const TIntermTyped *storeArgument1Typed = (*storeArguments)[0]->getAsTyped();
ASSERT_EQ(imageType, storeArgument1Typed->getBasicType());
const TIntermTyped *storeArgument2Typed = (*storeArguments)[1]->getAsTyped();
ASSERT_EQ(EbtInt, storeArgument2Typed->getBasicType());
ASSERT_EQ(storeLocationNominalSize, storeArgument2Typed->getNominalSize());
const TIntermTyped *storeArgument3Typed = (*storeArguments)[2]->getAsTyped();
ASSERT_EQ(storeValueType, storeArgument3Typed->getBasicType());
ASSERT_EQ(storeValueNominalSize, storeArgument3Typed->getNominalSize());
}
// Checks that the imageLoad call with mangled name imageLoadMangledName exists in the AST.
// Further each argument is checked whether it matches the expected properties given the compiled
// shader.
void CheckImageLoadCall(TIntermNode *astRoot,
const TString &imageLoadMangledName,
TBasicType imageType,
int loadLocationNominalSize)
{
const TIntermAggregate *imageLoadFunctionCall =
FindFunctionCallNode(astRoot, imageLoadMangledName);
ASSERT_NE(nullptr, imageLoadFunctionCall);
const TIntermSequence *loadArguments = imageLoadFunctionCall->getSequence();
ASSERT_EQ(2u, loadArguments->size());
const TIntermTyped *loadArgument1Typed = (*loadArguments)[0]->getAsTyped();
ASSERT_EQ(imageType, loadArgument1Typed->getBasicType());
const TIntermTyped *loadArgument2Typed = (*loadArguments)[1]->getAsTyped();
ASSERT_EQ(EbtInt, loadArgument2Typed->getBasicType());
ASSERT_EQ(loadLocationNominalSize, loadArgument2Typed->getNominalSize());
}
// Checks whether the image is properly exported as a uniform by the compiler.
void CheckExportedImageUniform(const std::vector<sh::Uniform> &uniforms,
size_t uniformIndex,
GLenum imageTypeGL,
const TString &imageName)
{
ASSERT_EQ(1u, uniforms.size());
const auto &imageUniform = uniforms[uniformIndex];
ASSERT_EQ(imageTypeGL, imageUniform.type);
ASSERT_STREQ(imageUniform.name.c_str(), imageName.c_str());
}
// Checks whether the image is saved in the AST as a node with the correct properties given the
// shader.
void CheckImageDeclaration(TIntermNode *astRoot,
const TString &imageName,
TBasicType imageType,
TLayoutImageInternalFormat internalFormat,
bool readonly,
bool writeonly)
{
const TIntermSymbol *myImageNode = FindSymbolNode(astRoot, imageName, imageType);
ASSERT_NE(nullptr, myImageNode);
const TType &myImageType = myImageNode->getType();
TLayoutQualifier myImageLayoutQualifier = myImageType.getLayoutQualifier();
ASSERT_EQ(internalFormat, myImageLayoutQualifier.imageInternalFormat);
TMemoryQualifier myImageMemoryQualifier = myImageType.getMemoryQualifier();
ASSERT_EQ(readonly, myImageMemoryQualifier.readonly);
ASSERT_EQ(writeonly, myImageMemoryQualifier.writeonly);
}
} // namespace
class ShaderImageTest : public testing::Test
{
public:
ShaderImageTest() {}
protected:
virtual void SetUp()
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
mTranslator = new TranslatorESSL(GL_COMPUTE_SHADER, SH_GLES3_1_SPEC);
ASSERT_TRUE(mTranslator->Init(resources));
}
virtual void TearDown() { delete mTranslator; }
// Return true when compilation succeeds
bool compile(const std::string &shaderString)
{
const char *shaderStrings[] = {shaderString.c_str()};
mASTRoot = mTranslator->compileTreeForTesting(shaderStrings, 1,
SH_INTERMEDIATE_TREE | SH_VARIABLES);
TInfoSink &infoSink = mTranslator->getInfoSink();
mInfoLog = infoSink.info.c_str();
return mASTRoot != nullptr;
}
protected:
std::string mTranslatedCode;
std::string mInfoLog;
TranslatorESSL *mTranslator;
TIntermNode *mASTRoot;
};
// Test that an image2D is properly parsed and exported as a uniform.
TEST_F(ShaderImageTest, Image2DDeclaration)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4) in;\n"
"layout(rgba32f) uniform highp readonly image2D myImage;\n"
"void main() {\n"
" ivec2 sz = imageSize(myImage);\n"
"}";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed" << mInfoLog;
}
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_IMAGE_2D, "myImage");
CheckImageDeclaration(mASTRoot, "myImage", EbtImage2D, EiifRGBA32F, true, false);
}
// Test that an image3D is properly parsed and exported as a uniform.
TEST_F(ShaderImageTest, Image3DDeclaration)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4) in;\n"
"layout(rgba32ui) uniform highp writeonly readonly uimage3D myImage;\n"
"void main() {\n"
" ivec3 sz = imageSize(myImage);\n"
"}";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed" << mInfoLog;
}
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_UNSIGNED_INT_IMAGE_3D, "myImage");
CheckImageDeclaration(mASTRoot, "myImage", EbtUImage3D, EiifRGBA32UI, true, true);
}
// Check that imageLoad calls get correctly parsed.
TEST_F(ShaderImageTest, ImageLoad)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4) in;\n"
"layout(rgba32f) uniform highp readonly image2D my2DImageInput;\n"
"layout(rgba32i) uniform highp readonly iimage3D my3DImageInput;\n"
"void main() {\n"
" vec4 result = imageLoad(my2DImageInput, ivec2(gl_LocalInvocationID.xy));\n"
" ivec4 result2 = imageLoad(my3DImageInput, ivec3(gl_LocalInvocationID.xyz));\n"
"}";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed" << mInfoLog;
}
// imageLoad call with image2D passed
CheckImageLoadCall(mASTRoot, "imageLoad(im21;vi2;", EbtImage2D, 2);
// imageLoad call with image3D passed
CheckImageLoadCall(mASTRoot, "imageLoad(iim31;vi3;", EbtIImage3D, 3);
}
// Check that imageStore calls get correctly parsed.
TEST_F(ShaderImageTest, ImageStore)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4) in;\n"
"layout(rgba32f) uniform highp writeonly image2D my2DImageOutput;\n"
"layout(rgba32ui) uniform highp writeonly uimage2DArray my2DImageArrayOutput;\n"
"void main() {\n"
" imageStore(my2DImageOutput, ivec2(gl_LocalInvocationID.xy), vec4(0.0));\n"
" imageStore(my2DImageArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));\n"
"}";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed" << mInfoLog;
}
// imageStore call with image2D
CheckImageStoreCall(mASTRoot, "imageStore(im21;vi2;vf4;", EbtImage2D, 2, EbtFloat, 4);
// imageStore call with image2DArray
CheckImageStoreCall(mASTRoot, "imageStore(uim2a1;vi3;vu4;", EbtUImage2DArray, 3, EbtUInt, 4);
}
...@@ -42,6 +42,33 @@ class ShaderVariableFinder : public TIntermTraverser ...@@ -42,6 +42,33 @@ class ShaderVariableFinder : public TIntermTraverser
TBasicType mBasicType; TBasicType mBasicType;
}; };
class FunctionCallFinder : public TIntermTraverser
{
public:
FunctionCallFinder(const TString &functionName)
: TIntermTraverser(true, false, false), mFunctionName(functionName), mNodeFound(nullptr)
{
}
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
if (node->getOp() == EOpFunctionCall &&
node->getFunctionSymbolInfo()->getName() == mFunctionName)
{
mNodeFound = node;
return false;
}
return true;
}
bool isFound() const { return mNodeFound != nullptr; }
const TIntermAggregate *getNode() const { return mNodeFound; }
private:
TString mFunctionName;
TIntermAggregate *mNodeFound;
};
} // anonymous namespace } // anonymous namespace
bool compileTestShader(GLenum type, bool compileTestShader(GLenum type,
...@@ -215,3 +242,10 @@ const TIntermSymbol *FindSymbolNode(TIntermNode *root, ...@@ -215,3 +242,10 @@ const TIntermSymbol *FindSymbolNode(TIntermNode *root,
root->traverse(&finder); root->traverse(&finder);
return finder.getNode(); return finder.getNode();
} }
const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName)
{
FunctionCallFinder finder(functionName);
root->traverse(&finder);
return finder.getNode();
}
...@@ -93,4 +93,7 @@ const TIntermSymbol *FindSymbolNode(TIntermNode *root, ...@@ -93,4 +93,7 @@ const TIntermSymbol *FindSymbolNode(TIntermNode *root,
const TString &symbolName, const TString &symbolName,
TBasicType basicType); TBasicType basicType);
// Returns a pointer to a function call node with a mangled name functionName.
const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName);
#endif // TESTS_TEST_UTILS_COMPILER_TEST_H_ #endif // TESTS_TEST_UTILS_COMPILER_TEST_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment