Implement GL_ARB_shader_image_load_store. Partly done (format layout qualifiers) from a submission.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27670 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2014-08-10 18:19:36 +00:00
parent e4423f5da1
commit ddea678e3e
26 changed files with 674 additions and 83 deletions

View file

@ -88,6 +88,7 @@ struct TBuiltInResource {
int maxFragmentInputComponents;
int maxImageUnits;
int maxCombinedImageUnitsAndFragmentOutputs;
int maxCombinedShaderOutputResources;
int maxImageSamples;
int maxVertexImageUniforms;
int maxTessControlImageUniforms;

View file

@ -241,6 +241,61 @@ enum TVertexOrder {
EvoCcw
};
// Note: order matters, as type of format is done by comparison.
enum TLayoutFormat {
ElfNone,
// Float image
ElfRgba32f,
ElfRgba16f,
ElfRg32f,
ElfRg16f,
ElfR11fG11fB10f,
ElfR32f,
ElfR16f,
ElfRgba16,
ElfRgb10A2,
ElfRgba8,
ElfRg16,
ElfRg8,
ElfR16,
ElfR8,
ElfRgba16Snorm,
ElfRgba8Snorm,
ElfRg16Snorm,
ElfRg8Snorm,
ElfR16Snorm,
ElfR8Snorm,
ElfFloatGuard, // to help with comparisons
// Int image
ElfRgba32i,
ElfRgba16i,
ElfRgba8i,
ElfRg32i,
ElfRg16i,
ElfRg8i,
ElfR32i,
ElfR16i,
ElfR8i,
ElfIntGuard, // to help with comparisons
// Uint image
ElfRgba32ui,
ElfRgba16ui,
ElfRgba8ui,
ElfRg32ui,
ElfRg16ui,
ElfRg8ui,
ElfR32ui,
ElfR16ui,
ElfR8ui,
ElfCount
};
class TQualifier {
public:
void clear()
@ -416,6 +471,8 @@ public:
layoutXfbBuffer = layoutXfbBufferEnd;
layoutXfbStride = layoutXfbStrideEnd;
layoutXfbOffset = layoutXfbOffsetEnd;
layoutFormat = ElfNone;
}
bool hasLayout() const
{
@ -423,7 +480,8 @@ public:
hasLocation() ||
hasBinding() ||
hasStream() ||
hasXfb();
hasXfb() ||
hasFormat();
}
TLayoutMatrix layoutMatrix : 3;
TLayoutPacking layoutPacking : 4;
@ -451,6 +509,8 @@ public:
unsigned int layoutXfbOffset : 10;
static const unsigned int layoutXfbOffsetEnd = 0x3FF;
TLayoutFormat layoutFormat : 8;
bool hasUniformLayout() const
{
return hasMatrix() ||
@ -491,6 +551,10 @@ public:
{
return layoutStream != layoutStreamEnd;
}
bool hasFormat() const
{
return layoutFormat != ElfNone;
}
bool hasXfb() const
{
return hasXfbBuffer() ||
@ -527,12 +591,58 @@ public:
default: return "none";
}
}
static const char* getLayoutFormatString(TLayoutFormat f)
{
switch (f) {
case ElfRgba32f: return "rgba32f";
case ElfRgba16f: return "rgba16f";
case ElfRg32f: return "rg32f";
case ElfRg16f: return "rg16f";
case ElfR11fG11fB10f: return "r11f_g11f_b10f";
case ElfR32f: return "r32f";
case ElfR16f: return "r16f";
case ElfRgba16: return "rgba16";
case ElfRgb10A2: return "rgb10_a2";
case ElfRgba8: return "rgba8";
case ElfRg16: return "rg16";
case ElfRg8: return "rg8";
case ElfR16: return "r16";
case ElfR8: return "r8";
case ElfRgba16Snorm: return "rgba16_snorm";
case ElfRgba8Snorm: return "rgba8_snorm";
case ElfRg16Snorm: return "rg16_snorm";
case ElfRg8Snorm: return "rg8_snorm";
case ElfR16Snorm: return "r16_snorm";
case ElfR8Snorm: return "r8_snorm";
case ElfRgba32i: return "rgba32i";
case ElfRgba16i: return "rgba16i";
case ElfRgba8i: return "rgba8i";
case ElfRg32i: return "rg32i";
case ElfRg16i: return "rg16i";
case ElfRg8i: return "rg8i";
case ElfR32i: return "r32i";
case ElfR16i: return "r16i";
case ElfR8i: return "r8i";
case ElfRgba32ui: return "rgba32ui";
case ElfRgba16ui: return "rgba16ui";
case ElfRgba8ui: return "rgba8ui";
case ElfRg32ui: return "rg32ui";
case ElfRg16ui: return "rg16ui";
case ElfRg8ui: return "rg8ui";
case ElfR32ui: return "r32ui";
case ElfR16ui: return "r16ui";
case ElfR8ui: return "r8ui";
default: return "none";
}
}
static const char* getGeometryString(TLayoutGeometry geometry)
{
switch (geometry) {
case ElgPoints: return "points";
case ElgLines: return "lines";
case ElgLinesAdjacency: return "lines_adjancency";
case ElgLinesAdjacency: return "lines_adjacency";
case ElgLineStrip: return "line_strip";
case ElgTriangles: return "triangles";
case ElgTrianglesAdjacency: return "triangles_adjacency";
@ -583,6 +693,7 @@ struct TShaderQualifiers {
TVertexSpacing spacing;
TVertexOrder order;
bool pointMode;
bool earlyFragmentTests; // fragment input
void init()
{
@ -594,6 +705,7 @@ struct TShaderQualifiers {
spacing = EvsNone;
order = EvoNone;
pointMode = false;
earlyFragmentTests = false;
}
// Merge in characteristics from the 'src' qualifier. They can override when
@ -616,6 +728,8 @@ struct TShaderQualifiers {
order = src.order;
if (src.pointMode)
pointMode = true;
if (src.earlyFragmentTests)
earlyFragmentTests = true;
}
};
@ -1023,6 +1137,9 @@ public:
if (qualifier.hasAlign())
p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
if (qualifier.hasFormat())
p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat));
if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset())
p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
if (qualifier.hasXfbOffset())

View file

@ -845,7 +845,7 @@ void TBuiltIns::initialize(int version, EProfile profile)
"void barrier();"
);
if (version >= 420)
if (version >= 130)
commonBuiltins.append(
"void memoryBarrier();"
);
@ -1467,9 +1467,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
// enumerate all the types
for (int image = 0; image <= 1; ++image) { // loop over "bool" image vs sampler
if (image > 0 && version < 420)
continue;
for (int shadow = 0; shadow <= 1; ++shadow) { // loop over "bool" shadow or not
for (int ms = 0; ms <=1; ++ms) {
@ -1523,8 +1520,7 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
addImageFunctions(sampler, typeName, version, profile);
else {
addSamplingFunctions(sampler, typeName, version, profile);
if (version >= 130)
addGatherFunctions(sampler, typeName, version, profile);
addGatherFunctions(sampler, typeName, version, profile);
}
}
}
@ -1577,7 +1573,63 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int versi
//
void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
{
// TODO: 4.2 Functionality: imaging functions
int dims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
TString imageParams = typeName;
if (dims == 1)
imageParams.append(", int");
else {
imageParams.append(", ivec");
imageParams.append(postfixes[dims]);
}
if (sampler.ms)
imageParams.append(", int");
commonBuiltins.append(prefixes[sampler.type]);
commonBuiltins.append("vec4 imageLoad(readonly ");
commonBuiltins.append(imageParams);
commonBuiltins.append(");\n");
commonBuiltins.append("void imageStore(writeonly ");
commonBuiltins.append(imageParams);
commonBuiltins.append(", ");
commonBuiltins.append(prefixes[sampler.type]);
commonBuiltins.append("vec4);\n");
if (sampler.type == EbtInt || sampler.type == EbtUint) {
const char* dataType = sampler.type == EbtInt ? "int" : "uint";
const int numBuiltins = 7;
static const char* atomicFunc[numBuiltins] = {
" imageAtomicAdd(",
" imageAtomicMin(",
" imageAtomicMax(",
" imageAtomicAnd(",
" imageAtomicOr(",
" imageAtomicXor(",
" imageAtomicExchange("
};
for (size_t i = 0; i < numBuiltins; ++i) {
commonBuiltins.append(dataType);
commonBuiltins.append(atomicFunc[i]);
if (version >= 450)
commonBuiltins.append("coherent ");
commonBuiltins.append(imageParams);
commonBuiltins.append(", ");
commonBuiltins.append(dataType);
commonBuiltins.append(");\n");
}
commonBuiltins.append(dataType);
commonBuiltins.append(" imageAtomicCompSwap(");
commonBuiltins.append(imageParams);
commonBuiltins.append(", ");
commonBuiltins.append(dataType);
commonBuiltins.append(", ");
commonBuiltins.append(dataType);
commonBuiltins.append(");\n");
}
}
//
@ -2111,17 +2163,27 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
}
// images
if (version >= 420) {
//snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.);
//snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.);
if (version >= 130) {
snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.maxImageUnits);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.maxCombinedImageUnitsAndFragmentOutputs);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedShaderOutputResources = %d;", resources.maxCombinedShaderOutputResources);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.maxImageSamples);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.maxVertexImageUniforms);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.maxTessControlImageUniforms);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.maxTessEvaluationImageUniforms);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.maxFragmentImageUniforms);
s.append(builtInConstant);
snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.maxCombinedImageUniforms);
s.append(builtInConstant);
}
// compute
@ -2264,6 +2326,11 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
symbolTable.setFunctionExtensions("textureCubeGradEXT", 1, &GL_EXT_shader_texture_lod);
}
// GL_ARB_shader_image_load_store
if (version < 420)
symbolTable.setFunctionExtensions("memoryBarrier", 1, &GL_ARB_shader_image_load_store);
// All the image access functions are protected by checks on the type of the first argument.
symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &GL_EXT_frag_depth);
break;

View file

@ -967,18 +967,32 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct
requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
if (arguments) {
// Make sure storage qualifications work for these arguments.
// Make sure qualifications work for these arguments.
TIntermAggregate* aggregate = arguments->getAsAggregate();
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage;
if (qual == EvqOut || qual == EvqInOut) {
// At this early point there is a slight ambiguity between whether an aggregate 'arguments'
// is the single argument itself or its children are the arguments. Only one argument
// means take 'arguments' itself as the one argument.
TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
// At this early point there is a slight ambiguity between whether an aggregate 'arguments'
// is the single argument itself or its children are the arguments. Only one argument
// means take 'arguments' itself as the one argument.
TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier();
if (formalQualifier.storage == EvqOut || formalQualifier.storage == EvqInOut) {
if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
}
TQualifier& argQualifier = arg->getAsTyped()->getQualifier();
if (argQualifier.isMemory()) {
const char* message = "argument cannot drop memory qualifier when passed to formal parameter";
if (argQualifier.volatil && ! formalQualifier.volatil)
error(arguments->getLoc(), message, "volatile", "");
if (argQualifier.coherent && ! formalQualifier.coherent)
error(arguments->getLoc(), message, "coherent", "");
if (argQualifier.restrict && ! formalQualifier.restrict)
error(arguments->getLoc(), message, "restrict", "");
if (argQualifier.readonly && ! formalQualifier.readonly)
error(arguments->getLoc(), message, "readonly", "");
if (argQualifier.writeonly && ! formalQualifier.writeonly)
error(arguments->getLoc(), message, "writeonly", "");
}
}
// Convert 'in' arguments
@ -1273,6 +1287,14 @@ void TParseContext::nonOpBuiltInCheck(TSourceLoc loc, const TFunction& fnCandida
}
}
}
if (fnCandidate.getName().compare(0, 11, "imageAtomic") == 0) {
const TType& imageType = callNode.getSequence()[0]->getAsTyped()->getType();
if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
} else
error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
}
}
//
@ -2651,6 +2673,13 @@ void TParseContext::paramCheckFix(TSourceLoc loc, const TStorageQualifier& quali
void TParseContext::paramCheckFix(TSourceLoc loc, const TQualifier& qualifier, TType& type)
{
if (qualifier.isMemory()) {
type.getQualifier().volatil = qualifier.volatil;
type.getQualifier().coherent = qualifier.coherent;
type.getQualifier().readonly = qualifier.readonly;
type.getQualifier().writeonly = qualifier.writeonly;
type.getQualifier().restrict = qualifier.restrict;
}
if (qualifier.isAuxiliary() ||
qualifier.isInterpolation())
error(loc, "cannot use auxiliary or interpolation qualifiers on a function parameter", "", "");
@ -2898,6 +2927,14 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
publicType.qualifier.layoutPacking = ElpStd430;
return;
}
for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) {
if (id == TQualifier::getLayoutFormatString(format)) {
requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "image load store");
profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shader_image_load_store, "image load store");
publicType.qualifier.layoutFormat = format;
return;
}
}
if (language == EShLangGeometry || language == EShLangTessEvaluation) {
if (id == TQualifier::getGeometryString(ElgTriangles)) {
publicType.shaderQualifiers.geometry = ElgTriangles;
@ -2987,8 +3024,14 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
publicType.shaderQualifiers.pixelCenterInteger = true;
return;
}
if (id == "early_fragment_tests") {
requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "early_fragment_tests");
profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shader_image_load_store, "early_fragment_tests");
publicType.shaderQualifiers.earlyFragmentTests = true;
return;
}
}
error(loc, "unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4)", id.c_str(), "");
error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
}
// Put the id's layout qualifier value into the public type. This is before we know any
@ -3169,6 +3212,9 @@ void TParseContext::mergeObjectLayoutQualifiers(TSourceLoc loc, TQualifier& dst,
if (src.hasStream())
dst.layoutStream = src.layoutStream;
if (src.hasFormat())
dst.layoutFormat = src.layoutFormat;
if (src.hasXfbBuffer())
dst.layoutXfbBuffer = src.layoutXfbBuffer;
@ -3332,6 +3378,23 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
if (type.getBasicType() == EbtBlock)
error(loc, "only applies to block members, not blocks", "offset", "");
}
// Image format
if (qualifier.hasFormat()) {
if (type.getBasicType() != EbtSampler || ! type.getSampler().image)
error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
else {
if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard)
error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
if (type.getSampler().type == EbtInt && (qualifier.layoutFormat < ElfFloatGuard || qualifier.layoutFormat > ElfIntGuard))
error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
if (type.getSampler().type == EbtUint && qualifier.layoutFormat < ElfIntGuard)
error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
}
} else if (type.getBasicType() == EbtSampler && type.getSampler().image && !qualifier.writeonly)
error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
if (qualifier.isMemory() && (type.getBasicType() != EbtSampler || ! type.getSampler().image))
error(loc, "memory qualifiers can only be used on image types", "", "");
}
// Do layout error checking that can be done within a qualifier proper, not needing to know
@ -4498,6 +4561,12 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
else
error(loc, "can only apply to 'in'", "point_mode", "");
}
if (publicType.shaderQualifiers.earlyFragmentTests) {
if (publicType.qualifier.storage == EvqVaryingIn)
intermediate.setEarlyFragmentTests();
else
error(loc, "can only apply to 'in'", "early_fragment_tests", "");
}
const TQualifier& qualifier = publicType.qualifier;

View file

@ -672,15 +672,17 @@ int TScanContext::tokenizeIdentifier()
return identifierOrType();
return keyword;
case ATOMIC_UINT:
return es30ReservedFromGLSL(420);
case COHERENT:
case RESTRICT:
case READONLY:
case WRITEONLY:
case ATOMIC_UINT:
return es30ReservedFromGLSL(420);
return es30ReservedFromGLSL(parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store) ? 130 : 420);
case VOLATILE:
if (parseContext.profile == EEsProfile || parseContext.version < 420)
if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
reservedWord();
return keyword;
@ -766,7 +768,7 @@ int TScanContext::tokenizeIdentifier()
case IMAGECUBEARRAY:
case IIMAGECUBEARRAY:
case UIMAGECUBEARRAY:
case UIMAGECUBEARRAY:
case IMAGE2DMS:
case IIMAGE2DMS:
case UIMAGE2DMS:
@ -993,6 +995,9 @@ int TScanContext::identifierOrReserved(bool reserved)
// but then got reserved by ES 3.0.
int TScanContext::es30ReservedFromGLSL(int version)
{
if (parseContext.symbolTable.atBuiltInLevel())
return keyword;
if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
(parseContext.profile != EEsProfile && parseContext.version < version)) {
if (parseContext.forwardCompatible)
@ -1067,7 +1072,7 @@ int TScanContext::firstGenerationImage()
{
afterType = true;
if (parseContext.profile != EEsProfile && parseContext.version >= 420)
if (parseContext.symbolTable.atBuiltInLevel() || (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
return keyword;
if ((parseContext.profile == EEsProfile && parseContext.version >= 300) ||
@ -1087,7 +1092,7 @@ int TScanContext::secondGenerationImage()
{
afterType = true;
if (parseContext.profile != EEsProfile && parseContext.version >= 420)
if (parseContext.symbolTable.atBuiltInLevel() || parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store)))
return keyword;
if (parseContext.forwardCompatible)

View file

@ -166,6 +166,7 @@ void TParseContext::initializeExtensionBehavior()
extensionBehavior[GL_ARB_texture_cube_map_array] = EBhDisable;
extensionBehavior[GL_ARB_shader_texture_lod] = EBhDisable;
extensionBehavior[GL_ARB_explicit_attrib_location] = EBhDisablePartial; // "index" for fragment outputs is missing
extensionBehavior[GL_ARB_shader_image_load_store] = EBhDisable;
}
// Get code that is not part of a shared symbol table, is specific to this shader,
@ -203,7 +204,8 @@ const char* TParseContext::getPreamble()
"#define GL_ARB_enhanced_layouts 1\n"
"#define GL_ARB_texture_cube_map_array 1\n"
"#define GL_ARB_shader_texture_lod 1\n"
"#define GL_ARB_explicit_attrib_location 1\n";
"#define GL_ARB_explicit_attrib_location 1\n"
"#define GL_ARB_shader_image_load_store 1\n";
}
}

View file

@ -90,6 +90,7 @@ const char* const GL_ARB_enhanced_layouts = "GL_ARB_enhanced_layouts";
const char* const GL_ARB_texture_cube_map_array = "GL_ARB_texture_cube_map_array";
const char* const GL_ARB_shader_texture_lod = "GL_ARB_shader_texture_lod";
const char* const GL_ARB_explicit_attrib_location = "GL_ARB_explicit_attrib_location";
const char* const GL_ARB_shader_image_load_store = "GL_ARB_shader_image_load_store";
} // end namespace glslang

View file

@ -611,6 +611,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
infoSink.debug << "gl_FragCoord pixel center is integer\n";
if (originUpperLeft)
infoSink.debug << "gl_FragCoord origin is upper left\n";
if (earlyFragmentTests)
infoSink.debug << "using early_fragment_tests\n";
break;
case EShLangCompute:

View file

@ -80,6 +80,9 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger)
error(infoSink, "gl_FragCoord redeclarations must match across shaders\n");
if (! earlyFragmentTests)
earlyFragmentTests = unit.earlyFragmentTests;
if (inputPrimitive == ElgNone)
inputPrimitive = unit.inputPrimitive;
else if (inputPrimitive != unit.inputPrimitive)

View file

@ -112,7 +112,7 @@ public:
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v),
numMains(0), numErrors(0), recursive(false),
invocations(0), vertices(0), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false),
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), xfbMode(false)
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), xfbMode(false)
{
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
}
@ -235,6 +235,8 @@ public:
bool getOriginUpperLeft() const { return originUpperLeft; }
void setPixelCenterInteger() { pixelCenterInteger = true; }
bool getPixelCenterInteger() const { return pixelCenterInteger; }
void setEarlyFragmentTests() { earlyFragmentTests = true; }
bool getEarlyFragmentTests() const { return earlyFragmentTests; }
void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
void merge(TInfoSink&, TIntermediate&);
@ -287,6 +289,7 @@ protected:
TVertexSpacing vertexSpacing;
TVertexOrder vertexOrder;
bool pointMode;
bool earlyFragmentTests;
bool xfbMode;
typedef std::list<TCall> TGraph;