blob: b673f98eaefc5f8571e35dfe0ff08ae3fd7b46f0 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2014-2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief
*/ /*-------------------------------------------------------------------*/
#include "glwEnums.hpp"
#include "gluContextInfo.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include <assert.h>
#include <map>
#include "es31cExplicitUniformLocationTest.hpp"
namespace glcts
{
using namespace glw;
namespace
{
class Logger
{
public:
Logger() : null_log_(0)
{
}
Logger(const Logger& rhs)
{
null_log_ = rhs.null_log_;
if (!null_log_)
{
str_ << rhs.str_.str();
}
}
~Logger()
{
s_tcuLog->writeMessage(str_.str().c_str());
if (!str_.str().empty())
{
s_tcuLog->writeMessage(NL);
}
}
template <class T>
Logger& operator<<(const T& t)
{
if (!null_log_)
{
str_ << t;
}
return *this;
}
static tcu::TestLog* Get()
{
return s_tcuLog;
}
static void setOutput(tcu::TestLog& log)
{
s_tcuLog = &log;
}
private:
void operator=(const Logger&);
bool null_log_;
std::ostringstream str_;
static tcu::TestLog* s_tcuLog;
};
tcu::TestLog* Logger::s_tcuLog = NULL;
class DefOccurence
{
public:
enum DefOccurenceEnum
{
ALL_SH,
VSH,
FSH_OR_CSH, //"one shader"
ALL_BUT_FSH,
ALL_BUT_VSH,
NONE_SH,
} occurence;
DefOccurence(DefOccurenceEnum _occurence) : occurence(_occurence)
{
}
bool occurs(GLenum shader) const
{
if (occurence == NONE_SH)
{
return false;
}
if (occurence == ALL_SH)
{
return true;
}
if (occurence == FSH_OR_CSH)
{
return shader == GL_FRAGMENT_SHADER || shader == GL_COMPUTE_SHADER;
}
if (occurence == VSH)
{
return shader == GL_VERTEX_SHADER;
}
if (occurence == ALL_BUT_FSH)
{
return shader != GL_FRAGMENT_SHADER;
}
if (occurence == ALL_BUT_VSH)
{
return shader != GL_VERTEX_SHADER;
}
assert(0);
return false;
}
};
class LocationSpecifier
{
};
class IndexSpecifier
{
};
class LayoutSpecifierBase
{
public:
enum NumSys
{
Dec,
Oct,
Hex,
};
LayoutSpecifierBase(int _val, NumSys _numSys, DefOccurence _occurence)
: val(_val), numSys(_numSys), occurence(_occurence)
{
}
bool isImplicit(const std::vector<GLenum> stages) const
{
bool implicit = true;
for (size_t i = 0; i < stages.size(); i++)
{
implicit &= !occurence.occurs(stages[i]);
}
return implicit;
}
int val;
NumSys numSys;
DefOccurence occurence;
};
template <class T>
class LayoutSpecifier : public LayoutSpecifierBase
{
public:
LayoutSpecifier(int _val, NumSys _numSys, DefOccurence _occurence) : LayoutSpecifierBase(_val, _numSys, _occurence)
{
}
static LayoutSpecifier<T> C(int _val, NumSys _sys = Dec)
{
return LayoutSpecifier<T>(_val, _sys, DefOccurence::ALL_SH);
}
static LayoutSpecifier<T> C(int _val, DefOccurence _occurence)
{
return LayoutSpecifier<T>(_val, Dec, _occurence);
}
static LayoutSpecifier<T> Implicit()
{
return LayoutSpecifier<T>(1999999, Dec, DefOccurence::NONE_SH);
}
void streamDefinition(std::ostringstream& str, GLenum shader) const;
};
typedef LayoutSpecifier<LocationSpecifier> Loc;
typedef LayoutSpecifier<IndexSpecifier> Index;
template <>
void LayoutSpecifier<LocationSpecifier>::streamDefinition(std::ostringstream& str, GLenum shader) const
{
if (val < 0 || !occurence.occurs(shader))
{
return;
}
str << "layout(location = ";
if (numSys == Loc::Oct)
{
str << std::oct << "0";
}
else if (numSys == Loc::Hex)
{
str << std::hex << "0x";
}
str << val << std::dec << ") ";
}
template <>
void LayoutSpecifier<IndexSpecifier>::streamDefinition(std::ostringstream& str, GLenum shader) const
{
if (val < 0 || !occurence.occurs(shader))
{
return;
}
str << "layout(index = ";
if (numSys == Loc::Oct)
{
str << std::oct << "0";
}
else if (numSys == Loc::Hex)
{
str << std::hex << "0x";
}
str << val << std::dec << ") ";
}
class UniformStructCounter
{
public:
UniformStructCounter() : counter(0)
{
}
GLint getNextCount()
{
return counter++;
}
private:
UniformStructCounter(const UniformStructCounter&);
GLint counter;
};
class UniformType
{
public:
UniformType(GLenum _enumType, int _arraySize = 0)
: enumType(_enumType), arraySize(_arraySize), isArray(_arraySize > 0), signedType(true)
{
if (!arraySize)
{
arraySize = 1;
}
arraySizesSegmented.push_back(arraySize);
fill();
}
UniformType(GLenum _enumType, const std::vector<int>& _arraySizesSegmented)
: enumType(_enumType), arraySizesSegmented(_arraySizesSegmented), isArray(true), signedType(true)
{
arraySize = 1;
for (size_t i = 0; i < arraySizesSegmented.size(); i++)
{
assert(arraySizesSegmented[i] > 0);
arraySize *= arraySizesSegmented[i];
}
fill();
}
UniformType(UniformStructCounter& structCounter, std::vector<UniformType> _childTypes, int _arraySize = 0)
: enumType(0), arraySize(_arraySize), childTypes(_childTypes), isArray(_arraySize > 0), signedType(true)
{
baseType = 0;
std::ostringstream _str;
_str << "S" << structCounter.getNextCount();
strType = _str.str();
if (!arraySize)
{
arraySize = 1;
}
arraySizesSegmented.push_back(arraySize);
}
inline const std::string& str() const
{
return strType;
}
inline const std::string& refStr() const
{
return refStrType;
}
bool isStruct() const
{
return (baseType == 0);
}
bool isSigned() const
{
return signedType;
}
const char* abs() const
{
switch (baseType)
{
case GL_FLOAT:
case GL_SAMPLER:
return "0.1";
case GL_UNSIGNED_INT:
return "0u";
case GL_INT:
return "0";
default:
assert(0);
return "";
}
}
std::pair<int, int> getSize() const
{
return size;
}
GLenum getBaseType() const
{
return baseType;
}
void streamArrayStr(std::ostringstream& _str, int arrayElem = -1) const
{
if (!isArray)
{
return;
}
if (arrayElem < 0)
{
for (size_t segment = 0; segment < arraySizesSegmented.size(); segment++)
{
_str << "[" << arraySizesSegmented[segment] << "]";
}
}
else
{
int tailSize = arraySize;
for (size_t segment = 0; segment < arraySizesSegmented.size(); segment++)
{
tailSize /= arraySizesSegmented[segment];
_str << "[" << arrayElem / tailSize << "]";
arrayElem %= tailSize;
}
}
}
GLenum enumType;
//arrays-of-arrays size
std::vector<int> arraySizesSegmented;
//premultiplied array size
int arraySize;
//child types for nested (struct) types;
std::vector<UniformType> childTypes;
private:
void fill()
{
size = std::pair<int, int>(1, 1);
switch (enumType)
{
case GL_SAMPLER_2D:
refStrType = "vec4";
strType = "sampler2D";
baseType = GL_SAMPLER;
break;
case GL_FLOAT:
refStrType = strType = "float";
baseType = GL_FLOAT;
break;
case GL_INT:
refStrType = strType = "int";
baseType = GL_INT;
break;
case GL_UNSIGNED_INT:
refStrType = strType = "uint";
baseType = GL_UNSIGNED_INT;
signedType = false;
break;
case GL_FLOAT_VEC2:
refStrType = strType = "vec2";
baseType = GL_FLOAT;
size.first = 2;
break;
case GL_FLOAT_VEC3:
refStrType = strType = "vec3";
baseType = GL_FLOAT;
size.first = 3;
break;
case GL_FLOAT_VEC4:
refStrType = strType = "vec4";
baseType = GL_FLOAT;
size.first = 4;
break;
case GL_FLOAT_MAT2:
strType = "mat2";
refStrType = "vec2";
baseType = GL_FLOAT;
size.first = size.second = 2;
break;
case GL_FLOAT_MAT3:
strType = "mat3";
refStrType = "vec3";
baseType = GL_FLOAT;
size.first = size.second = 3;
break;
case GL_FLOAT_MAT4:
strType = "mat4";
refStrType = "vec4";
baseType = GL_FLOAT;
size.first = size.second = 4;
break;
case GL_FLOAT_MAT2x3:
strType = "mat2x3";
refStrType = "vec3";
baseType = GL_FLOAT;
size.first = 3;
size.second = 2;
break;
case GL_FLOAT_MAT4x3:
strType = "mat4x3";
refStrType = "vec3";
baseType = GL_FLOAT;
size.first = 3;
size.second = 4;
break;
case GL_FLOAT_MAT2x4:
strType = "mat2x4";
refStrType = "vec4";
baseType = GL_FLOAT;
size.first = 4;
size.second = 2;
break;
case GL_FLOAT_MAT3x4:
strType = "mat3x4";
refStrType = "vec4";
baseType = GL_FLOAT;
size.first = 4;
size.second = 3;
break;
case GL_FLOAT_MAT3x2:
strType = "mat3x2";
refStrType = "vec2";
baseType = GL_FLOAT;
size.first = 2;
size.second = 3;
break;
case GL_FLOAT_MAT4x2:
strType = "mat4x2";
refStrType = "vec2";
baseType = GL_FLOAT;
size.first = 2;
size.second = 4;
break;
case GL_INT_VEC2:
refStrType = strType = "ivec2";
baseType = GL_INT;
size.first = 2;
break;
case GL_INT_VEC3:
refStrType = strType = "ivec3";
baseType = GL_INT;
size.first = 3;
break;
case GL_INT_VEC4:
refStrType = strType = "ivec4";
baseType = GL_INT;
size.first = 4;
break;
default:
assert(0);
}
}
std::string strType, refStrType;
std::pair<int, int> size;
GLenum baseType;
bool isArray;
bool signedType;
};
class UniformValueGenerator
{
public:
UniformValueGenerator() : fValue(0.0f), iValue(0)
{
}
GLfloat genF()
{
if (fValue > 99999.0f)
{
fValue = 0.0f;
}
return (fValue += 1.0f);
}
GLint genI()
{
return (iValue += 1);
}
private:
UniformValueGenerator(const UniformValueGenerator&);
GLfloat fValue;
GLint iValue;
};
class UniformValue
{
public:
void streamValue(std::ostringstream& str, int arrayElement = 0, int column = 0) const
{
int arrayElementSize = type.getSize().first * type.getSize().second;
str << type.refStr() << "(";
if (type.getBaseType() == GL_SAMPLER)
{
for (size_t elem = 0; elem < 4; elem++)
{
if (elem)
str << ", ";
str << fValues[arrayElement * 4 + elem];
}
str << ")";
return;
}
for (int elem = 0; fValues.size() && elem < type.getSize().first; elem++)
{
if (elem)
str << ", ";
str << fValues[arrayElement * arrayElementSize + column * type.getSize().first + elem] << ".0";
}
for (int elem = 0; iValues.size() && elem < type.getSize().first; elem++)
{
if (elem)
str << ", ";
str << iValues[arrayElement * arrayElementSize + elem];
}
for (int elem = 0; uValues.size() && elem < type.getSize().first; elem++)
{
if (elem)
str << ", ";
str << uValues[arrayElement * arrayElementSize + elem] << "u";
}
str << ")";
}
const void* getPtr(int arrayElement) const
{
int arrayElementSize = type.getSize().first * type.getSize().second;
if (type.getBaseType() == GL_INT || type.getBaseType() == GL_SAMPLER)
{
return &iValues[arrayElement * arrayElementSize];
}
else if (type.getBaseType() == GL_UNSIGNED_INT)
{
return &uValues[arrayElement * arrayElementSize];
}
else if (type.getBaseType() == GL_FLOAT)
{
return &fValues[arrayElement * arrayElementSize];
}
assert(0);
return NULL;
}
UniformValue(const UniformType& _type, UniformValueGenerator& generator) : type(_type)
{
const int sizeRow = type.getSize().first;
const int sizeColumn = type.getSize().second;
if (type.isStruct())
{
return;
}
if (type.getBaseType() == GL_INT)
{
assert(sizeColumn == 1);
iValues.resize(sizeRow * type.arraySize);
for (size_t elem = 0; elem < iValues.size(); elem++)
{
iValues[elem] = generator.genI();
}
}
else if (type.getBaseType() == GL_UNSIGNED_INT)
{
assert(sizeColumn == 1);
uValues.resize(sizeRow * type.arraySize);
for (size_t elem = 0; elem < uValues.size(); elem++)
{
uValues[elem] = static_cast<GLuint>(generator.genI());
}
}
else if (type.getBaseType() == GL_FLOAT)
{
fValues.resize(sizeColumn * sizeRow * type.arraySize);
for (size_t elem = 0; elem < fValues.size(); elem++)
{
fValues[elem] = generator.genF();
}
}
else if (type.getBaseType() == GL_SAMPLER)
{
//color ref value
fValues.resize(4 * type.arraySize);
for (size_t elem = 0; elem < fValues.size(); elem++)
{
fValues[elem] = float(elem) / float(fValues.size());
}
//uniform value
iValues.resize(type.arraySize);
for (size_t elem = 0; elem < iValues.size(); elem++)
{
iValues[elem] = generator.genI() % 16;
}
}
else
{
assert(0);
}
}
std::vector<GLfloat> fValues;
std::vector<GLint> iValues;
std::vector<GLint> uValues;
private:
UniformType type;
};
class Uniform
{
public:
Uniform(UniformValueGenerator& generator, UniformType _type, Loc _location,
DefOccurence _declOccurence = DefOccurence::ALL_SH, DefOccurence _usageOccurence = DefOccurence::ALL_SH)
: type(_type)
, location(_location)
, declOccurence(_declOccurence)
, usageOccurence(_usageOccurence)
, value(_type, generator)
{
if (type.isStruct())
{
int currentLocation = location.val;
for (int arrayElem = 0; arrayElem < type.arraySize; arrayElem++)
{
for (size_t child = 0; child < type.childTypes.size(); child++)
{
Loc childLocation = Loc::Implicit();
if (currentLocation > 0)
{
childLocation = Loc::C(currentLocation);
}
childUniforms.push_back(
Uniform(generator, type.childTypes[child], childLocation, declOccurence, usageOccurence));
currentLocation += type.childTypes[child].arraySize;
}
}
}
}
void setName(const std::string& parentName, const std::string& _name)
{
shortName = _name;
{
std::ostringstream __name;
__name << parentName << _name;
name = __name.str();
}
if (type.isStruct())
{
for (size_t i = 0; i < childUniforms.size(); i++)
{
std::ostringstream childName;
childName << "m" << (i % (childUniforms.size() / type.arraySize));
std::ostringstream childParentName;
childParentName << name;
type.streamArrayStr(childParentName, (int)(i / type.arraySize));
childParentName << ".";
childUniforms[i].setName(childParentName.str(), childName.str());
}
}
}
const std::string& getName() const
{
return name;
}
void streamDefinition(std::ostringstream& str) const
{
str << type.str() << " " << shortName;
type.streamArrayStr(str);
}
UniformType type;
Loc location;
DefOccurence declOccurence, usageOccurence;
UniformValue value;
std::vector<Uniform> childUniforms;
std::string name, shortName;
};
class SubroutineFunction
{
public:
SubroutineFunction(UniformValueGenerator& generator, Index _index = Index::Implicit())
: index(_index), embeddedRetVal(GL_FLOAT_VEC4, generator)
{
}
const UniformValue& getRetVal() const
{
return embeddedRetVal;
}
inline const std::string& getName() const
{
return name;
}
void setName(int _name)
{
std::ostringstream __name;
__name << "sf" << _name;
name = __name.str();
}
Index index;
private:
UniformValue embeddedRetVal;
std::string name;
};
class SubroutineFunctionSet
{
public:
SubroutineFunctionSet(UniformValueGenerator& generator, size_t count = 0) : fn(count, SubroutineFunction(generator))
{
}
void push_back(const SubroutineFunction& _fn)
{
fn.push_back(_fn);
}
inline const std::string& getTypeName() const
{
return typeName;
}
void setTypeName(int _name)
{
std::ostringstream __name;
__name << "st" << _name;
typeName = __name.str();
}
std::vector<SubroutineFunction> fn;
std::string typeName;
};
class SubroutineUniform
{
public:
SubroutineUniform(UniformValueGenerator& generator, SubroutineFunctionSet& _functions, Loc _location,
int _arraySize = 0, DefOccurence _defOccurence = DefOccurence::ALL_SH, bool _used = true)
: functions(_functions)
, location(_location)
, arraySize(_arraySize)
, defOccurence(_defOccurence)
, used(_used)
, embeddedUIntUniform(GL_UNSIGNED_INT, generator)
{
assert(arraySize >= 0);
if (!arraySize)
{
arraySize = 1;
isArray = false;
}
else
{
isArray = true;
}
arraySizesSegmented.push_back(arraySize);
embeddedUIntUniform = UniformValue(UniformType(GL_UNSIGNED_INT, arraySize), generator);
for (int i = 0; i < arraySize; i++)
{
embeddedUIntUniform.uValues[i] = static_cast<GLint>(embeddedUIntUniform.uValues[i] % functions.fn.size());
}
}
SubroutineUniform(UniformValueGenerator& generator, SubroutineFunctionSet& _functions, Loc _location,
std::vector<int> _arraySizesSegmented, DefOccurence _defOccurence = DefOccurence::ALL_SH,
bool _used = true)
: functions(_functions)
, location(_location)
, defOccurence(_defOccurence)
, used(_used)
, arraySizesSegmented(_arraySizesSegmented)
, isArray(true)
, embeddedUIntUniform(GL_UNSIGNED_INT, generator)
{
arraySize = 1;
for (size_t i = 0; i < arraySizesSegmented.size(); i++)
{
assert(arraySizesSegmented[i] > 0);
arraySize *= arraySizesSegmented[i];
}
embeddedUIntUniform = UniformValue(UniformType(GL_UNSIGNED_INT, arraySize), generator);
for (int i = 0; i < arraySize; i++)
{
embeddedUIntUniform.uValues[i] = static_cast<GLint>(embeddedUIntUniform.uValues[i] % functions.fn.size());
}
}
void setName(const std::string& _name)
{
name = _name;
}
const std::string& getName() const
{
return name;
}
void streamArrayStr(std::ostringstream& str, int arrayElem = -1) const
{
if (!isArray)
{
return;
}
if (arrayElem < 0)
{
for (size_t segment = 0; segment < arraySizesSegmented.size(); segment++)
{
str << "[" << arraySizesSegmented[segment] << "]";
}
}
else
{
int tailSize = arraySize;
for (size_t segment = 0; segment < arraySizesSegmented.size(); segment++)
{
tailSize /= arraySizesSegmented[segment];
str << "[" << arrayElem / tailSize << "]";
arrayElem %= tailSize;
}
}
}
const SubroutineFunction& getSelectedFunction(int arrayElem) const
{
assert(arrayElem < arraySize);
return functions.fn[embeddedUIntUniform.uValues[arrayElem]];
}
SubroutineFunctionSet functions;
Loc location;
int arraySize;
DefOccurence defOccurence;
bool used;
private:
std::vector<int> arraySizesSegmented;
bool isArray;
UniformValue embeddedUIntUniform;
std::string name;
};
class ShaderKey
{
public:
ShaderKey()
{
}
ShaderKey(GLenum _stage, const std::string& _input, const std::string& _output)
: stage(_stage), input(_input), output(_output)
{
}
GLenum stage;
std::string input, output;
bool operator<(const ShaderKey& rhs) const
{
if (stage == rhs.stage)
{
if (input == rhs.input)
{
return (output < rhs.output);
}
return input < rhs.input;
}
return stage < rhs.stage;
}
};
class CompiledProgram
{
public:
GLuint name;
std::vector<GLenum> stages;
};
class ShaderSourceFactory
{
static void streamUniformDefinitions(const std::vector<Uniform>& uniforms, GLenum shader, std::ostringstream& ret)
{
for (size_t i = 0; i < uniforms.size(); i++)
{
if (uniforms[i].declOccurence.occurs(shader))
{
if (uniforms[i].type.isStruct())
{
ret << "struct " << uniforms[i].type.str() << " {" << std::endl;
for (size_t child = 0; child < uniforms[i].childUniforms.size() / uniforms[i].type.arraySize;
child++)
{
ret << " ";
uniforms[i].childUniforms[child].streamDefinition(ret);
ret << ";" << std::endl;
}
ret << "};" << std::endl;
}
uniforms[i].location.streamDefinition(ret, shader);
ret << "uniform ";
uniforms[i].streamDefinition(ret);
ret << ";" << std::endl;
}
}
}
static void streamSubroutineDefinitions(const std::vector<SubroutineUniform>& subroutineUniforms, GLenum shader,
std::ostringstream& ret)
{
if (subroutineUniforms.size())
{
//add a "zero" uniform;
ret << "uniform float zero;" << std::endl;
}
for (size_t i = 0; i < subroutineUniforms.size(); i++)
{
if (subroutineUniforms[i].defOccurence.occurs(shader))
{
//subroutine vec4 st0(float param);
ret << "subroutine vec4 " << subroutineUniforms[i].functions.getTypeName() << "(float param);"
<< std::endl;
for (size_t fn = 0; fn < subroutineUniforms[i].functions.fn.size(); fn++)
{
//layout(index = X) subroutine(st0) vec4 sf0(float param) { .... };
subroutineUniforms[i].functions.fn[fn].index.streamDefinition(ret, shader);
ret << "subroutine(" << subroutineUniforms[i].functions.getTypeName() << ") vec4 "
<< subroutineUniforms[i].functions.fn[fn].getName() << "(float param) { return zero + ";
subroutineUniforms[i].functions.fn[fn].getRetVal().streamValue(ret);
ret << "; }" << std::endl;
}
//layout(location = X) subroutine uniform stX uX[...];
subroutineUniforms[i].location.streamDefinition(ret, shader);
ret << "subroutine uniform " << subroutineUniforms[i].functions.getTypeName() << " "
<< subroutineUniforms[i].getName();
subroutineUniforms[i].streamArrayStr(ret);
ret << ";" << std::endl;
}
}
}
static void streamUniformValidator(std::ostringstream& ret, const Uniform& uniform, GLenum shader,
const char* outTemporary)
{
if (uniform.declOccurence.occurs(shader) && uniform.usageOccurence.occurs(shader))
{
if (uniform.type.isStruct())
{
for (size_t child = 0; child < uniform.childUniforms.size(); child++)
{
streamUniformValidator(ret, uniform.childUniforms[child], shader, outTemporary);
}
}
else
{
for (int arrayElement = 0; arrayElement < uniform.type.arraySize; arrayElement++)
{
for (int column = 0; column < uniform.type.getSize().second; column++)
{
std::string columnIndex;
if (uniform.type.getSize().second > 1)
{
std::ostringstream str;
str << "[" << column << "]";
columnIndex = str.str();
}
std::string absoluteF;
if (uniform.type.isSigned())
{
absoluteF = "abs";
}
if (uniform.type.getBaseType() == GL_SAMPLER)
{
ret << NL " if (any(greaterThan(" << absoluteF << "(texture(" << uniform.getName();
uniform.type.streamArrayStr(ret, arrayElement);
ret << columnIndex << ", vec2(0.5)) - ";
uniform.value.streamValue(ret, arrayElement, column);
ret << " ), " << uniform.type.refStr() << "(" << uniform.type.abs() << ")))) {";
}
else if (uniform.type.getSize().first > 1)
{
ret << NL " if (any(greaterThan(" << absoluteF << "(" << uniform.getName();
uniform.type.streamArrayStr(ret, arrayElement);
ret << columnIndex << " - ";
uniform.value.streamValue(ret, arrayElement, column);
ret << "), " << uniform.type.refStr() << "(" << uniform.type.abs() << ")))) {";
}
else
{
ret << NL " if (" << absoluteF << "(" << uniform.getName();
uniform.type.streamArrayStr(ret, arrayElement);
ret << " - ";
uniform.value.streamValue(ret, arrayElement);
ret << ") >" << uniform.type.refStr() << "(" << uniform.type.abs() << ")) {";
}
ret << NL " " << outTemporary << " = vec4 (1.0, 0.0, 0.0, 1.0);";
ret << NL " }";
}
}
}
}
}
static void streamUniformValidators(std::ostringstream& ret, const std::vector<Uniform>& uniforms, GLenum shader,
const char* outTemporary)
{
for (size_t i = 0; i < uniforms.size(); i++)
{
streamUniformValidator(ret, uniforms[i], shader, outTemporary);
}
}
static void streamSubroutineValidator(std::ostringstream& ret, const SubroutineUniform& subroutineUniform,
GLenum shader, const char* outTemporary)
{
if (subroutineUniform.defOccurence.occurs(shader) && subroutineUniform.used)
{
for (int arrayElem = 0; arrayElem < subroutineUniform.arraySize; arrayElem++)
{
ret << NL " if (any(greaterThan(abs(" << subroutineUniform.getName();
subroutineUniform.streamArrayStr(ret, arrayElem);
ret << "(zero) - ";
subroutineUniform.getSelectedFunction(arrayElem).getRetVal().streamValue(ret);
ret << "), vec4(0.1)))) {";
ret << NL " " << outTemporary << " = vec4 (1.0, 0.0, 0.0, 1.0);";
ret << NL " }";
}
}
}
static void streamSubroutineValidators(std::ostringstream& ret,
const std::vector<SubroutineUniform>& subroutineUniforms, GLenum shader,
const char* outTemporary)
{
for (size_t i = 0; i < subroutineUniforms.size(); i++)
{
streamSubroutineValidator(ret, subroutineUniforms[i], shader, outTemporary);
}
}
static void streamShaderHeader(std::ostringstream& str, const glu::ContextType type)
{
if (glu::isContextTypeES(type))
{
str << "#version 310 es" NL "precision highp float;" NL "precision highp int;";
}
else
{
str << "#version 430 core" NL;
}
}
static std::string generateFragmentShader(const ShaderKey& key, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms,
const std::string& additionalDef, const glu::ContextType type)
{
std::ostringstream ret;
streamShaderHeader(ret, type);
ret << NL;
streamUniformDefinitions(uniforms, GL_FRAGMENT_SHADER, ret);
ret << NL;
streamSubroutineDefinitions(subroutineUniforms, GL_FRAGMENT_SHADER, ret);
ret << NL << additionalDef << NL "in vec4 " << key.input << ";" << NL "out vec4 out_FragColor;"
<< NL "void main() {" << NL " vec4 validationResult = " << key.input << ";" << NL;
streamUniformValidators(ret, uniforms, GL_FRAGMENT_SHADER, "validationResult");
ret << NL;
streamSubroutineValidators(ret, subroutineUniforms, GL_FRAGMENT_SHADER, "validationResult");
ret << NL " out_FragColor = validationResult;" << NL "}";
return ret.str();
}
static std::string generateVertexShader(const ShaderKey& key, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms,
const std::string& additionalDef, const glu::ContextType type)
{
std::ostringstream ret;
streamShaderHeader(ret, type);
ret << NL;
streamUniformDefinitions(uniforms, GL_VERTEX_SHADER, ret);
ret << NL;
streamSubroutineDefinitions(subroutineUniforms, GL_VERTEX_SHADER, ret);
ret << NL << additionalDef << NL "in vec4 in_Position;" << NL "out vec4 " << key.output << ";"
<< NL "void main() {" << NL " vec4 validationResult = vec4(0.0, 1.0, 0.0, 1.0);" << NL;
streamUniformValidators(ret, uniforms, GL_VERTEX_SHADER, "validationResult");
ret << NL;
streamSubroutineValidators(ret, subroutineUniforms, GL_VERTEX_SHADER, "validationResult");
ret << NL " " << key.output << " = validationResult;" << NL " gl_Position = in_Position;" << NL "}";
return ret.str();
}
static std::string generateComputeShader(const ShaderKey&, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms,
const std::string& additionalDef, const glu::ContextType type)
{
std::ostringstream ret;
streamShaderHeader(ret, type);
ret << NL "layout (local_size_x = 1, local_size_y = 1) in;"
<< NL "layout (std430, binding = 1) buffer ResultBuffer {" << NL " vec4 cs_ValidationResult;" << NL "};"
<< NL;
streamUniformDefinitions(uniforms, GL_COMPUTE_SHADER, ret);
ret << NL;
streamSubroutineDefinitions(subroutineUniforms, GL_COMPUTE_SHADER, ret);
ret << NL << additionalDef << NL "void main() {" << NL " vec4 validationResult = vec4(0.0, 1.0, 0.0, 1.0);"
<< NL;
streamUniformValidators(ret, uniforms, GL_COMPUTE_SHADER, "validationResult");
ret << NL;
streamSubroutineValidators(ret, subroutineUniforms, GL_COMPUTE_SHADER, "validationResult");
ret << NL " cs_ValidationResult = validationResult;" << NL "}";
return ret.str();
}
public:
static std::string generateShader(const ShaderKey& key, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms,
const std::string& additionalDef, const glu::ContextType type)
{
switch (key.stage)
{
case GL_VERTEX_SHADER:
return generateVertexShader(key, uniforms, subroutineUniforms, additionalDef, type);
case GL_FRAGMENT_SHADER:
return generateFragmentShader(key, uniforms, subroutineUniforms, additionalDef, type);
case GL_COMPUTE_SHADER:
return generateComputeShader(key, uniforms, subroutineUniforms, additionalDef, type);
default:
assert(0);
return "";
}
}
};
class ExplicitUniformLocationCaseBase : public glcts::SubcaseBase
{
virtual std::string Title()
{
return "";
}
virtual std::string Purpose()
{
return "";
}
virtual std::string Method()
{
return "";
}
virtual std::string PassCriteria()
{
return "";
}
int getWindowWidth()
{
return m_context.getRenderContext().getRenderTarget().getWidth();
}
int getWindowHeight()
{
return m_context.getRenderContext().getRenderTarget().getHeight();
}
std::map<ShaderKey, GLuint> CreateShaders(const std::vector<std::vector<ShaderKey> >& programConfigs,
const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms,
const std::string& additionalDef)
{
std::map<ShaderKey, GLuint> ret;
//create shaders
for (size_t config = 0; config < programConfigs.size(); config++)
{
for (size_t target = 0; target < programConfigs[config].size(); target++)
{
if (ret.find(programConfigs[config][target]) == ret.end())
{
GLuint shader = glCreateShader(programConfigs[config][target].stage);
std::string source = ShaderSourceFactory::generateShader(programConfigs[config][target], uniforms,
subroutineUniforms, additionalDef,
m_context.getRenderContext().getType());
const char* cSource[] = { source.c_str() };
glShaderSource(shader, 1, cSource, NULL);
ret[programConfigs[config][target]] = shader;
}
}
}
//compile shaders
for (std::map<ShaderKey, GLuint>::iterator i = ret.begin(); i != ret.end(); i++)
{
glCompileShader(i->second);
}
return ret;
}
long CreatePrograms(std::vector<CompiledProgram>& programs, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms, const std::string& additionalDef,
bool negativeCompile, bool negativeLink)
{
long ret = NO_ERROR;
std::vector<std::vector<ShaderKey> > programConfigs;
{
std::vector<ShaderKey> vsh_fsh(2);
vsh_fsh[0] = ShaderKey(GL_VERTEX_SHADER, "", "vs_ValidationResult");
vsh_fsh[1] = ShaderKey(GL_FRAGMENT_SHADER, "vs_ValidationResult", "");
programConfigs.push_back(vsh_fsh);
}
{
std::vector<ShaderKey> csh(1);
csh[0] = ShaderKey(GL_COMPUTE_SHADER, "", "");
programConfigs.push_back(csh);
}
std::map<ShaderKey, GLuint> shaders =
CreateShaders(programConfigs, uniforms, subroutineUniforms, additionalDef);
//query compilation results
for (std::map<ShaderKey, GLuint>::iterator it = shaders.begin(); it != shaders.end(); it++)
{
GLint status;
glGetShaderiv(it->second, GL_COMPILE_STATUS, &status);
GLchar infoLog[1000], source[4000];
glGetShaderSource(it->second, 4000, NULL, source);
glGetShaderInfoLog(it->second, 1000, NULL, infoLog);
Logger::Get()->writeKernelSource(source);
Logger::Get()->writeCompileInfo("shader", "", status == GL_TRUE, infoLog);
if (!negativeLink)
{
if (!negativeCompile)
{
if (status != GL_TRUE)
{
Logger() << "Shader compilation failed";
ret |= ERROR;
}
}
else
{
if (status)
{
Logger() << "Negative compilation case failed: shader shoult not compile, but "
"GL_COMPILE_STATUS != 0";
ret |= ERROR;
}
}
}
}
if (negativeCompile)
{
//delete shaders
for (std::map<ShaderKey, GLuint>::iterator it = shaders.begin(); it != shaders.end(); it++)
{
glDeleteShader(it->second);
}
return ret;
}
//assemble programs and link
for (size_t config = 0; config < programConfigs.size(); config++)
{
CompiledProgram program;
program.name = glCreateProgram();
for (size_t target = 0; target < programConfigs[config].size(); target++)
{
GLuint shader = shaders.find(programConfigs[config][target])->second;
glAttachShader(program.name, shader);
program.stages.push_back(programConfigs[config][target].stage);
}
programs.push_back(program);
glLinkProgram(programs[config].name);
}
for (size_t config = 0; config < programConfigs.size(); config++)
{
glLinkProgram(programs[config].name);
}
//delete shaders
for (std::map<ShaderKey, GLuint>::iterator it = shaders.begin(); it != shaders.end(); it++)
{
glDeleteShader(it->second);
}
//query link status:
for (size_t config = 0; config < programConfigs.size(); config++)
{
GLint status;
glGetProgramiv(programs[config].name, GL_LINK_STATUS, &status);
GLchar infoLog[1000];
glGetProgramInfoLog(programs[config].name, 1000, NULL, infoLog);
Logger::Get()->writeCompileInfo("program", "", status == GL_TRUE, infoLog);
if (!negativeLink)
{
if (status != GL_TRUE)
{
Logger() << "Shader link failed";
ret |= ERROR;
}
}
else
{
if (status)
{
Logger() << "Negative link case failed: program should not link, but GL_LINK_STATUS != 0";
ret |= ERROR;
}
}
}
return ret;
}
long DeletePrograms(std::vector<CompiledProgram>& programs)
{
for (size_t i = 0; i < programs.size(); i++)
{
glDeleteProgram(programs[i].name);
}
programs.resize(0);
return NO_ERROR;
}
void setUniform(const Uniform& uniform, const CompiledProgram& program)
{
bool used = false;
for (size_t i = 0; i < program.stages.size(); i++)
{
used |= uniform.declOccurence.occurs(program.stages[i]) && uniform.usageOccurence.occurs(program.stages[i]);
}
if (!used)
return;
if (uniform.type.isStruct())
{
for (size_t j = 0; j < uniform.childUniforms.size(); j++)
{
setUniform(uniform.childUniforms[j], program);
}
}
else
{
GLint loc;
if (uniform.location.isImplicit(program.stages))
{
std::ostringstream name;
name << uniform.getName();
uniform.type.streamArrayStr(name, 0);
loc = glGetUniformLocation(program.name, name.str().c_str());
}
else
{
loc = uniform.location.val;
}
for (int arrayElem = 0; arrayElem < uniform.type.arraySize; arrayElem++)
{
switch (uniform.type.enumType)
{
case GL_FLOAT:
glUniform1f(loc, *(GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_VEC2:
glUniform2fv(loc, 1, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_VEC3:
glUniform3fv(loc, 1, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_VEC4:
glUniform4fv(loc, 1, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT2:
glUniformMatrix2fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT3:
glUniformMatrix3fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT4:
glUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT2x3:
glUniformMatrix2x3fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT4x3:
glUniformMatrix4x3fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT2x4:
glUniformMatrix2x4fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT3x4:
glUniformMatrix3x4fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT3x2:
glUniformMatrix3x2fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_FLOAT_MAT4x2:
glUniformMatrix4x2fv(loc, 1, GL_FALSE, (GLfloat*)uniform.value.getPtr(arrayElem));
break;
case GL_INT:
case GL_SAMPLER_2D:
glUniform1i(loc, *(GLint*)uniform.value.getPtr(arrayElem));
break;
case GL_INT_VEC2:
glUniform2iv(loc, 1, (GLint*)uniform.value.getPtr(arrayElem));
break;
case GL_INT_VEC3:
glUniform3iv(loc, 1, (GLint*)uniform.value.getPtr(arrayElem));
break;
case GL_INT_VEC4:
glUniform4iv(loc, 1, (GLint*)uniform.value.getPtr(arrayElem));
break;
case GL_UNSIGNED_INT:
glUniform1ui(loc, *(GLuint*)uniform.value.getPtr(arrayElem));
break;
default:
assert(0);
}
loc++;
}
}
}
void setSubroutineUniform(const SubroutineUniform& subroutineUniform, const CompiledProgram& program, GLenum stage,
std::vector<glw::GLuint>& indicesOut)
{
bool used = subroutineUniform.defOccurence.occurs(stage) && subroutineUniform.used;
if (used)
{
for (int arrayElem = 0; arrayElem < subroutineUniform.arraySize; arrayElem++)
{
GLint loc = -1;
if (subroutineUniform.location.isImplicit(program.stages))
{
std::ostringstream name;
name << subroutineUniform.getName();
subroutineUniform.streamArrayStr(name, arrayElem);
loc = glGetSubroutineUniformLocation(program.name, stage, name.str().c_str());
}
else
{
loc = subroutineUniform.location.val + arrayElem;
}
if (loc >= 0)
{
const SubroutineFunction& selectedFunction = subroutineUniform.getSelectedFunction(arrayElem);
int index = -1;
if (selectedFunction.index.isImplicit(std::vector<GLenum>(1, stage)))
{
index = glGetSubroutineIndex(program.name, stage, selectedFunction.getName().c_str());
}
else
{
index = selectedFunction.index.val;
}
if (loc < (int)indicesOut.size())
{
indicesOut[loc] = index;
}
else
{
assert(0);
}
}
else
{
assert(0);
}
}
}
}
long runExecuteProgram(const CompiledProgram& program, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms)
{
long ret = NO_ERROR;
glUseProgram(program.name);
for (size_t i = 0; i < uniforms.size(); i++)
{
setUniform(uniforms[i], program);
}
for (size_t stage = 0; stage < program.stages.size() && subroutineUniforms.size(); stage++)
{
glw::GLint numactive;
glGetProgramStageiv(program.name, program.stages[stage], GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
&numactive);
if (numactive)
{
std::vector<glw::GLuint> indices(numactive, 0);
for (size_t i = 0; i < subroutineUniforms.size(); i++)
{
setSubroutineUniform(subroutineUniforms[i], program, program.stages[stage], indices);
}
glUniformSubroutinesuiv(program.stages[stage], numactive, &indices[0]);
}
}
if (program.stages[0] != GL_COMPUTE_SHADER)
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
for (size_t i = 0; i < pixels.size(); i += 4)
{
if (pixels[i] != 0 || pixels[i + 1] != 255 || pixels[i + 2] != 0)
{
ret |= ERROR;
Logger() << "Program " << program.name << ": Wrong color. Expected green, got (" << (int)pixels[i]
<< ", " << (int)pixels[i + 1] << ", " << (int)pixels[i + 2] << ", " << (int)pixels[i + 3]
<< ").";
break;
}
}
Logger().Get()->writeImage("rendered image", "", QP_IMAGE_COMPRESSION_MODE_BEST, QP_IMAGE_FORMAT_RGBA8888,
getWindowWidth(), getWindowHeight(), 0, &pixels[0]);
}
else
{
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(GLfloat), NULL, GL_DYNAMIC_READ);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
GLfloat* color = reinterpret_cast<GLfloat*>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * sizeof(GLfloat), GL_MAP_READ_BIT));
if (color[0] != 0 || color[1] != 1.0 || color[2] != 0)
{
ret |= ERROR;
Logger() << "Program " << program.name << ": Wrong color. Expected green, got (" << (int)color[0]
<< ", " << (int)color[1] << ", " << (int)color[2] << ", " << (int)color[3] << ").";
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glDeleteBuffers(1, &buffer);
}
return ret;
}
long runQueryUniform(const CompiledProgram& program, const Uniform& uniform, std::set<GLuint>& usedLocations,
GLint max)
{
long ret = NO_ERROR;
/*
glGetUniformLocation(program, name);
Query passes if returned value is unique in current program, matches
explicit location (if passed in GLSL code) and is less than value of
GL_MAX_UNIFORM_LOCATIONS.
glGetProgramResourceLocation(program, GL_UNIFIORM, name);
Query passes if returned value matches value returned from
glGetUniformLocation().
*/
if (uniform.type.isStruct())
{
for (size_t i = 0; i < uniform.childUniforms.size(); i++)
{
ret |= runQueryUniform(program, uniform.childUniforms[i], usedLocations, max);
}
}
else
{
for (int arrayElem = 0; arrayElem < uniform.type.arraySize; arrayElem++)
{
/* Location that is taken by this uniform (even if not used).*/
GLint reservedLocation = -1;
if (!uniform.location.isImplicit(program.stages))
{
reservedLocation = uniform.location.val + arrayElem;
}
//optimization: for continuous arrays run queries at the beging and end only.
bool runQueries = uniform.location.isImplicit(program.stages) ||
(arrayElem < 1000 || arrayElem > uniform.type.arraySize - 1000);
if (runQueries)
{
std::ostringstream name;
name << uniform.getName();
uniform.type.streamArrayStr(name, arrayElem);
GLint returned = glGetUniformLocation(program.name, name.str().c_str());
GLint returnedPIQ = glGetProgramResourceLocation(program.name, GL_UNIFORM, name.str().c_str());
if (returned != returnedPIQ)
{
ret |= ERROR;
Logger()
<< "Locations of uniform \"" << name.str()
<< "\" returned by glGetUniformLocation and differ glGetProgramResourceLocation differ: "
<< returned << " != " << returnedPIQ << ".";
}
bool used = false;
for (size_t i = 0; i < program.stages.size(); i++)
{
used |= uniform.declOccurence.occurs(program.stages[i]) &&
uniform.usageOccurence.occurs(program.stages[i]);
}
if (!uniform.location.isImplicit(program.stages))
{
//Validate uniform location against explicit value
GLint expected = reservedLocation;
if (!(expected == returned || (!used && returned == -1)))
{
ret |= ERROR;
Logger() << "Unexpected uniform \"" << name.str() << "\" location: expected " << expected
<< ", got " << returned << ".";
}
}
else
{
//Check if location > 0 if used;
if (used)
{
if (returned < 0)
{
ret |= ERROR;
Logger() << "Unexpected uniform \"" << name.str()
<< "\" location: expected positive value, got " << returned << ".";
}
else
{
reservedLocation = returned;
}
}
}
if (returned >= 0)
{
//check if location is less than max
if (returned >= max)
{
ret |= ERROR;
Logger() << "Uniform \"" << name.str() << "\" returned location (" << returned
<< ") is greater than implementation dependent limit (" << max << ").";
}
}
} //if (runQueries)
//usedLocations is always checked (even if queries were not run.
if (reservedLocation >= 0)
{
//check if location is unique
if (usedLocations.find(reservedLocation) != usedLocations.end())
{
ret |= ERROR;
Logger() << "Uniform location (" << reservedLocation << ") is not unique.";
}
usedLocations.insert(reservedLocation);
}
}
}
return ret;
}
long runQueryUniformSubroutine(const CompiledProgram& program, GLenum stage,
const SubroutineUniform& subroutineUniform, std::set<GLuint>& usedLocations,
GLint max)
{
long ret = NO_ERROR;
/*
glGetSubroutineUniformLocation(program, shaderType, name)
Query passes if returned value is unique in current program stage,
matches explicit location (if passed in GLSL code) and is less than
value of GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS.
glGetProgramResourceLocation(program, GL_(VERTEX|FRAGMENT|COMPUTE|...
..._SUBROUTINE_UNIFORM, name)
Query passes if returned value matches value returned from
glGetUniformLocation().
*/
for (int arrayElem = 0; arrayElem < subroutineUniform.arraySize; arrayElem++)
{
std::ostringstream name;
name << subroutineUniform.getName();
subroutineUniform.streamArrayStr(name, arrayElem);
GLint returned = glGetSubroutineUniformLocation(program.name, stage, name.str().c_str());
glw::GLenum piqStage = 0;
switch (stage)
{
case GL_VERTEX_SHADER:
piqStage = GL_VERTEX_SUBROUTINE_UNIFORM;
break;
case GL_FRAGMENT_SHADER:
piqStage = GL_FRAGMENT_SUBROUTINE_UNIFORM;
break;
case GL_COMPUTE_SHADER:
piqStage = GL_COMPUTE_SUBROUTINE_UNIFORM;
break;
default:
assert(0);
}
GLint returnedPIQ = glGetProgramResourceLocation(program.name, piqStage, name.str().c_str());
if (returned != returnedPIQ)
{
ret |= ERROR;
Logger() << "Locations of subrutine uniform \"" << name.str()
<< "\" returned by glGetUniformLocation and differ glGetProgramResourceLocation differ: "
<< returned << " != " << returnedPIQ << ".";
}
bool used = subroutineUniform.defOccurence.occurs(stage) && subroutineUniform.used;
GLint reservedLocation = -1;
if (!subroutineUniform.location.isImplicit(std::vector<glw::GLenum>(1, stage)))
{
//Validate uniform location against explicit value
GLint expected = subroutineUniform.location.val + arrayElem;
if (!(expected == returned || (!used && returned == -1)))
{
ret |= ERROR;
Logger() << "Unexpected subroutine uniform \"" << name.str() << "\" location: expected " << expected
<< ", got " << returned << ".";
}
reservedLocation = expected;
}
else
{
//Check if location > 0 if used;
if (used)
{
if (returned < 0)
{
ret |= ERROR;
Logger() << "Unexpected subroutine uniform \"" << name.str()
<< "\" location: expected positive value, got " << returned << ".";
}
else
{
reservedLocation = returned;
}
}
}
if (reservedLocation >= 0)
{
//check if location is unique
if (usedLocations.find(reservedLocation) != usedLocations.end())
{
ret |= ERROR;
Logger() << "Subroutine uniform \"" << name.str() << "\" location (" << reservedLocation
<< ") is not unique.";
}
usedLocations.insert(reservedLocation);
}
if (returned >= 0)
{
//check if location is less than max
if (returned >= max)
{
ret |= ERROR;
Logger() << "Subroutine uniform \"" << name.str() << "\" returned location (" << returned
<< ") is greater than implementation dependent limit (" << max << ").";
}
}
}
return ret;
}
long runQueryUniformSubroutineFunction(const CompiledProgram& program, GLenum stage,
const SubroutineFunction& subroutineFunction, std::set<GLuint>& usedIndices,
GLint max, bool used)
{
long ret = NO_ERROR;
/*
glGetSubroutineIndex(program, shaderType, name)
Query passes if returned value is unique in current program stage,
matches explicit index (if passed in GLSL code) and is less than value
of GL_MAX_SUBROUTINES.
glGetProgramResourceIndex(program, GL_(VERTEX|FRAGMENT|COMPUTE|...
..._SUBROUTINE, name)
Query passes if returned value matches value returned from
glGetSubroutineIndex().
*/
std::string name = subroutineFunction.getName();
GLint returned = glGetSubroutineIndex(program.name, stage, name.c_str());
glw::GLenum piqStage = 0;
switch (stage)
{
case GL_VERTEX_SHADER:
piqStage = GL_VERTEX_SUBROUTINE;
break;
case GL_FRAGMENT_SHADER:
piqStage = GL_FRAGMENT_SUBROUTINE;
break;
case GL_COMPUTE_SHADER:
piqStage = GL_COMPUTE_SUBROUTINE;
break;
default:
assert(0);
}
GLint returnedPIQ = glGetProgramResourceIndex(program.name, piqStage, name.c_str());
if (returned != returnedPIQ)
{
ret |= ERROR;
Logger() << "Indices of subroutine function \"" << name
<< "\" returned by glGetSubroutineIndex and differ glGetProgramResourceIndex differ: " << returned
<< " != " << returnedPIQ << ".";
}
GLint reservedIndex = -1;
if (!subroutineFunction.index.isImplicit(std::vector<glw::GLenum>(1, stage)))
{
//Validate uniform location against explicit value
GLint expected = subroutineFunction.index.val;
if (!(expected == returned || (!used && returned == -1)))
{
ret |= ERROR;
Logger() << "Unexpected subroutine function \"" << name << "\" index: expected " << expected << ", got "
<< returned << ".";
}
reservedIndex = expected;
}
else
{
//Check if location > 0 if used;
if (used)
{
if (returned < 0)
{
ret |= ERROR;
Logger() << "Unexpected subroutine function \"" << name << "\" index: expected positive value, got "
<< returned << ".";
}
else
{
reservedIndex = returned;
}
}
}
if (reservedIndex >= 0)
{
//check if location is unique
if (usedIndices.find(reservedIndex) != usedIndices.end())
{
ret |= ERROR;
Logger() << "Subroutine function \"" << name << "\" index (" << reservedIndex << ") is not unique.";
}
usedIndices.insert(reservedIndex);
}
if (returned >= 0)
{
//check if location is less than max
if (returned >= max)
{
ret |= ERROR;
Logger() << "Subroutine function \"" << name << "\" returned index (" << returned
<< ") is greater than implementation dependent limit (" << max << ").";
}
}
return ret;
}
long runQueryProgram(const CompiledProgram& program, const std::vector<Uniform>& uniforms,
const std::vector<SubroutineUniform>& subroutineUniforms)
{
long ret = NO_ERROR;
{
std::set<GLuint> usedLocations;
GLint max;
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &max);
for (size_t i = 0; i < uniforms.size(); i++)
{
ret |= runQueryUniform(program, uniforms[i], usedLocations, max);
}
}
if (subroutineUniforms.size())
{
GLint maxLocation, maxIndex;
glGetIntegerv(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, &maxLocation);
glGetIntegerv(GL_MAX_SUBROUTINES, &maxIndex);
for (size_t stage = 0; stage < program.stages.size(); stage++)
{
std::set<GLuint> usedLocations;
std::set<GLuint> usedIndices;
for (size_t i = 0; i < subroutineUniforms.size(); i++)
{
ret |= runQueryUniformSubroutine(program, program.stages[stage], subroutineUniforms[i],
usedLocations, maxLocation);
for (size_t fn = 0; fn < subroutineUniforms[i].functions.fn.size(); fn++)
{
ret |= runQueryUniformSubroutineFunction(
program, program.stages[stage], subroutineUniforms[i].functions.fn[fn], usedIndices,
maxIndex,
subroutineUniforms[i].defOccurence.occurs(program.stages[stage]) &&
subroutineUniforms[i].used);
}
}
}
}
return ret;
}
protected:
UniformValueGenerator uniformValueGenerator;
UniformStructCounter uniformStructCounter;
long doRun(std::vector<SubroutineUniform>& subroutineUniforms)
{
assert(subroutineUniforms.size());
std::vector<Uniform> noUniforms;
return doRun(noUniforms, subroutineUniforms);
}
long doRun(std::vector<Uniform>& uniforms)
{
assert(uniforms.size());
std::vector<SubroutineUniform> noSubroutineUniforms;
return doRun(uniforms, noSubroutineUniforms);
}
long doRunNegativeCompile(const std::string additionalDef)
{
std::vector<Uniform> noUniforms;
std::vector<SubroutineUniform> noSubroutineUniforms;
return doRun(noUniforms, noSubroutineUniforms, additionalDef, true);
}
long doRunNegativeLink(std::vector<Uniform>& uniforms)
{
std::vector<SubroutineUniform> noSubroutineUniforms;
return doRun(uniforms, noSubroutineUniforms, "", false, true);
}
long doRunNegativeLink(std::vector<SubroutineUniform>& subroutineUniforms)
{
std::vector<Uniform> noUniforms;
return doRun(noUniforms, subroutineUniforms, "", false, true);
}
long doRun(std::vector<Uniform>& uniforms, std::vector<SubroutineUniform>& subroutineUniforms,
std::string additionalDef = "", bool negativeCompile = false, bool negativeLink = false)
{
long ret = NO_ERROR;
std::string parentUniformName = "";
for (size_t i = 0; i < uniforms.size(); i++)
{
std::ostringstream name;
name << "u" << i;
uniforms[i].setName(parentUniformName, name.str());
}
int subroutineTypeCounter = 0;
int subroutineFunctionCounter = 0;
for (size_t i = 0; i < subroutineUniforms.size(); i++)
{
std::ostringstream name;
name << "u" << i + uniforms.size();
subroutineUniforms[i].setName(name.str());
if (!subroutineUniforms[i].functions.getTypeName().size())
{
subroutineUniforms[i].functions.setTypeName(subroutineTypeCounter++);
for (size_t fn = 0; fn < subroutineUniforms[i].functions.fn.size(); fn++)
{
subroutineUniforms[i].functions.fn[fn].setName(subroutineFunctionCounter++);
}
}
}
GLfloat coords[] = {
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
};
GLuint vbo, vao;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
std::vector<CompiledProgram> programs;
ret |= CreatePrograms(programs, uniforms, subroutineUniforms, additionalDef, negativeCompile, negativeLink);
for (size_t i = 0; i < programs.size() && ret == NO_ERROR && !negativeCompile && !negativeLink; i++)
{
ret |= runExecuteProgram(programs[i], uniforms, subroutineUniforms);
ret |= runQueryProgram(programs[i], uniforms, subroutineUniforms);
}
glUseProgram(0);
DeletePrograms(programs);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
return ret;
}
};
class UniformLoc : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform vec4 u0;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2), DefOccurence::FSH_OR_CSH));
return doRun(uniforms);
}
};
class UniformLocNonDec : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 0x0a) uniform vec4 u0;
//layout (location = 010) uniform vec4 u1;
std::vector<Uniform> uniforms;
uniforms.push_back(
Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(0x0a, Loc::Hex), DefOccurence::FSH_OR_CSH));
uniforms.push_back(
Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(010, Loc::Oct), DefOccurence::FSH_OR_CSH));
return doRun(uniforms);
}
};
class UniformLocMultipleStages : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform vec4 u0;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2)));
return doRun(uniforms);
}
};
class UniformLocMultipleUniforms : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform vec4 u0;
//layout (location = 3) uniform vec4 u1;
//layout (location = 5) uniform vec4 u2;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(3)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(5)));
return doRun(uniforms);
}
};
class UniformLocTypesMix : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform float u0;
//layout (location = 3) uniform vec3 u1;
//layout (location = 0) uniform uint u2;
//layout (location = 1) uniform ivec3 u3;
//layout (location = 4) uniform mat2 u4;
//layout (location = 7) uniform mat2 u5;
//layout (location = 5) uniform mat2 u6;
//layout (location = 6) uniform mat3 u7;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(2)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC3, Loc::C(3)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_UNSIGNED_INT, Loc::C(0)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_INT_VEC3, Loc::C(1)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT2, Loc::C(4)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT2, Loc::C(7)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT2, Loc::C(5)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT3, Loc::C(6)));
return doRun(uniforms);
}
};
class UniformLocTypesMat : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::vector<Uniform> uniforms;
//layout (location = 1) uniform mat2x3 u0;
//layout (location = 2) uniform mat3x2 u1;
//layout (location = 0) uniform mat2 u2;
//layout (location = 3) uniform imat3x4 u3;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT2x3, Loc::C(1)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT3x2, Loc::C(2)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT2, Loc::C(0)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_MAT4x3, Loc::C(3)));
return doRun(uniforms);
}
};
class UniformLocTypesSamplers : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 1) uniform sampler2D s0[3];
//layout (location = 13) uniform sampler2D s1;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_SAMPLER_2D, 3), Loc::C(1)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_SAMPLER_2D, Loc::C(13)));
std::vector<GLuint> texUnits;
std::vector<std::vector<GLubyte> > colors;
for (size_t i = 0; i < uniforms.size(); i++)
{
for (int elem = 0; elem < uniforms[i].type.arraySize; elem++)
{
texUnits.push_back(uniforms[i].value.iValues[elem]);
std::vector<GLubyte> color(4);
color[0] = static_cast<GLubyte>(255. * uniforms[i].value.fValues[4 * elem + 0] + 0.5);
color[1] = static_cast<GLubyte>(255. * uniforms[i].value.fValues[4 * elem + 1] + 0.5);
color[2] = static_cast<GLubyte>(255. * uniforms[i].value.fValues[4 * elem + 2] + 0.5);
color[3] = static_cast<GLubyte>(255. * uniforms[i].value.fValues[4 * elem + 3] + 0.5);
colors.push_back(color);
}
}
std::vector<GLuint> textures(texUnits.size());
glGenTextures((GLsizei)(textures.size()), &textures[0]);
for (size_t i = 0; i < textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + texUnits[i]);
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &colors[i][0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glActiveTexture(GL_TEXTURE0);
long ret = doRun(uniforms);
glDeleteTextures((GLsizei)(textures.size()), &textures[0]);
return ret;
}
};
class UniformLocTypesStructs : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
/**
* This test case uses following uniform declarations:
*
* struct S {
* vec4 u0;
* float u1[2];
* mat2 u2;
* };
* layout (location = 1) uniform S s0[3];
* layout (location = 13) uniform S s1;
*/
std::vector<UniformType> members;
members.push_back(GL_FLOAT_VEC4);
members.push_back(UniformType(GL_FLOAT, 2));
members.push_back(GL_FLOAT_MAT2);
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(uniformStructCounter, members, 3), Loc::C(1)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(uniformStructCounter, members), Loc::C(13)));
return doRun(uniforms);
}
};
class UniformLocArraysNonSpaced : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform float[3] u0;
//layout (location = 5) uniform vec3[2] u1;
//layout (location = 7) uniform int[3] u2;
//layout (location = 10) uniform ivec4 u3;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, 3), Loc::C(2)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT_VEC3, 2), Loc::C(5)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_INT, 3), Loc::C(7)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_INT_VEC4, Loc::C(10)));
return doRun(uniforms);
}
};
class UniformLocArraySpaced : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform float u0;
//layout (location = 5) uniform vec3[2] u1;
//layout (location = 8) uniform int[3] u2;
//layout (location = 12) uniform ivec4[1] u3;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(2)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT_VEC3, 2), Loc::C(5)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_INT, 3), Loc::C(8)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_INT_VEC4, 1), Loc::C(12)));
return doRun(uniforms);
}
};
class UniformLocArrayofArrays : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform float[2][3] u0;
//layout (location = 8) uniform vec3[2][2] u1;
//layout (location = 12) uniform float u2;
std::vector<Uniform> uniforms;
{
std::vector<int> arraySizesSegmented(2);
arraySizesSegmented[0] = 2;
arraySizesSegmented[1] = 3;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, arraySizesSegmented), Loc::C(2)));
}
{
std::vector<int> arraySizesSegmented(2);
arraySizesSegmented[0] = arraySizesSegmented[1] = 2;
uniforms.push_back(
Uniform(uniformValueGenerator, UniformType(GL_FLOAT_VEC3, arraySizesSegmented), Loc::C(8)));
}
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(12)));
return doRun(uniforms);
}
};
class UniformLocMixWithImplicit : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 0) uniform float u0;
//layout (location = 2) uniform vec3 u1;
//layout (location = 3) uniform int u2;
//uniform float u0;
//uniform vec3 u1;
//uniform int u2;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(0, DefOccurence::FSH_OR_CSH)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC3, Loc::C(2, DefOccurence::FSH_OR_CSH)));
uniforms.push_back(Uniform(uniformValueGenerator, GL_INT, Loc::C(3, DefOccurence::FSH_OR_CSH)));
return doRun(uniforms);
}
};
class UniformLocMixWithImplicit2 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//uniform float[3] u0;
//layout (location = 3) uniform vec3[2] u1;
//uniform int[3] u2;
//layout (location = 8) uniform ivec4 u3;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, 3), Loc::Implicit()));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT_VEC3, 2), Loc::C(3)));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_INT, 3), Loc::Implicit()));
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_INT_VEC4, 2), Loc::C(8)));
return doRun(uniforms);
}
};
class UniformLocMixWithImplicit3 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 0) uniform float u0; //unused
//layout (location = 2) uniform vec3 u1; //unused
//layout (location = 3) uniform int u2; //unused
//uniform float u3;
//uniform vec3 u4;
//uniform int u5;
std::vector<Uniform> uniforms;
uniforms.push_back(
Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(0), DefOccurence::ALL_SH, DefOccurence::NONE_SH));
uniforms.push_back(
Uniform(uniformValueGenerator, GL_FLOAT_VEC3, Loc::C(2), DefOccurence::ALL_SH, DefOccurence::NONE_SH));
uniforms.push_back(
Uniform(uniformValueGenerator, GL_INT, Loc::C(3), DefOccurence::ALL_SH, DefOccurence::NONE_SH));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::Implicit()));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC3, Loc::Implicit()));
uniforms.push_back(Uniform(uniformValueGenerator, GL_INT, Loc::Implicit()));
return doRun(uniforms);
}
};
class UniformLocMixWithImplicitMax : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
long ret = NO_ERROR;
GLint max;
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &max);
const int implicitCount = 1;
int tests[3] = { 0, 3, max - implicitCount };
for (int test = 0; test < 3; test++)
{
std::vector<Uniform> uniforms;
//for performance reasons fill-up all avaliable locations with an unused arrays.
if (tests[test] > 0)
{
//[0..test - 1]
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, tests[test]), Loc::C(0),
DefOccurence::ALL_SH, DefOccurence::NONE_SH));
assert(uniforms[uniforms.size() - 1].location.val + uniforms[uniforms.size() - 1].type.arraySize ==
tests[test]);
}
if (tests[test] < max - implicitCount)
{
//[test + 1..max]
uniforms.push_back(
Uniform(uniformValueGenerator, UniformType(GL_FLOAT, max - implicitCount - tests[test]),
Loc::C(tests[test] + implicitCount), DefOccurence::ALL_SH, DefOccurence::NONE_SH));
assert(uniforms[uniforms.size() - 1].location.val + uniforms[uniforms.size() - 1].type.arraySize ==
max);
}
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::Implicit()));
ret |= doRun(uniforms);
}
return ret;
}
};
class UniformLocMixWithImplicitMaxArray : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
long ret = NO_ERROR;
GLint max;
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &max);
const int implicitCount = 3;
int tests[3] = { 0, 3, max - 4 };
for (int test = 0; test < 3; test++)
{
std::vector<Uniform> uniforms;
//for performance reasons fill-up all avaliable locations with an unused arrays.
if (tests[test] > 0)
{
//[0..test - 1]
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, tests[test]), Loc::C(0),
DefOccurence::ALL_SH, DefOccurence::NONE_SH));
assert(uniforms[uniforms.size() - 1].location.val + uniforms[uniforms.size() - 1].type.arraySize ==
tests[test]);
}
if (tests[test] < max - implicitCount)
{
//[test + 3 ..max]
uniforms.push_back(
Uniform(uniformValueGenerator, UniformType(GL_FLOAT, max - implicitCount - tests[test]),
Loc::C(tests[test] + implicitCount), DefOccurence::ALL_SH, DefOccurence::NONE_SH));
assert(uniforms[uniforms.size() - 1].location.val + uniforms[uniforms.size() - 1].type.arraySize ==
max);
}
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, implicitCount), Loc::Implicit()));
ret |= doRun(uniforms);
}
return ret;
}
};
class UniformLocImplicitInSomeStages : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//One shader: uniform float u0;
//Another shader: layout (location = 3) uniform float u0;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(3, DefOccurence::FSH_OR_CSH)));
return doRun(uniforms);
}
};
class UniformLocImplicitInSomeStages2 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//One shader: uniform float u0;
//Another shader: layout (location = 3) uniform float u0; //not used!
std::vector<Uniform> uniforms;
//location only in fsh, declaration in all shaders, usage in all shaders but fsh.
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(3, DefOccurence::FSH_OR_CSH),
DefOccurence::ALL_SH, DefOccurence::ALL_BUT_FSH));
return doRun(uniforms);
}
};
class UniformLocImplicitInSomeStages3 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::vector<Uniform> uniforms;
//location only in fsh, declaration in all shaders, usage in all shaders but fsh.
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(3, DefOccurence::FSH_OR_CSH),
DefOccurence::ALL_SH, DefOccurence::ALL_BUT_FSH));
//location in all but fsh, declaration in all shaders, usage in fsh.
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(2, DefOccurence::ALL_BUT_FSH),
DefOccurence::ALL_SH, DefOccurence::FSH_OR_CSH));
//location only in fsh, declaration in all shaders, usage in all shaders but fsh.
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, 3), Loc::C(7, DefOccurence::FSH_OR_CSH),
DefOccurence::ALL_SH, DefOccurence::ALL_BUT_FSH));
//location in all but fsh, declaration in all shaders, usage in fsh.
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, 3),
Loc::C(4, DefOccurence::ALL_BUT_FSH), DefOccurence::ALL_SH,
DefOccurence::FSH_OR_CSH));
//location only in vsh, declaration in all shaders, usage in all shaders but vsh.
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(0, DefOccurence::VSH), DefOccurence::ALL_SH,
DefOccurence::ALL_BUT_VSH));
//location only in vsh, declaration in all shaders, usage in all shaders but vsh.
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::C(1, DefOccurence::ALL_BUT_FSH),
DefOccurence::ALL_SH, DefOccurence::ALL_BUT_VSH));
return doRun(uniforms);
}
};
class UniformLocNegativeCompileNonNumberLiteral : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def = "layout (location = x) uniform float u0;";
return doRunNegativeCompile(def);
}
};
class UniformLocNegativeCompileNonConstLoc : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def = NL "const int i = 1;" NL "layout (location = i) uniform float u0;";
return doRunNegativeCompile(def);
}
};
class UniformLocNegativeLinkLocationReused1 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = 2) uniform float u0;
//layout (location = 2) uniform float u1;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2), DefOccurence::FSH_OR_CSH));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2), DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(uniforms);
}
};
class UniformLocNegativeLinkLocationReused2 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
///layout (location = 2) uniform float u0;
//layout (location = 2) uniform float u1;
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2), DefOccurence::FSH_OR_CSH));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(2), DefOccurence::ALL_BUT_FSH));
return doRunNegativeLink(uniforms);
}
};
class UniformLocNegativeLinkMaxLocation : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout (location = X) uniform float u0;
//Where X is substituted with value of GL_MAX_UNIFORM_LOCATIONS.
GLint max;
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &max);
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT_VEC4, Loc::C(max), DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(uniforms);
}
};
class UniformLocNegativeLinkMaxMaxNumOfLocation : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
GLint max;
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &max);
std::vector<Uniform> uniforms;
uniforms.push_back(Uniform(uniformValueGenerator, UniformType(GL_FLOAT, max), Loc::C(0),
DefOccurence::FSH_OR_CSH, DefOccurence::NONE_SH));
uniforms.push_back(Uniform(uniformValueGenerator, GL_FLOAT, Loc::Implicit(), DefOccurence::ALL_BUT_FSH));
return doRunNegativeLink(uniforms);
}
};
class SubRoutineLoc : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 2) subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocNonDecimal : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 0x0a) subroutine uniform st0 u0;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(0x0a, Loc::Hex), 0,
DefOccurence::FSH_OR_CSH));
//layout(location = 010 ) subroutine uniform st0 u1;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(010, Loc::Oct), 0,
DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocAllStages : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 2) subroutine uniform st0 u0;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2)));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocArrays : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 1) subroutine uniform st0 u0[2];
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(1), 2));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocArraysMix : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
//subroutine vec4 st1(float param);
//subroutine(st1) vec4 sf2(float param) { .... };
//subroutine(st1) vec4 sf3(float param) { .... };
SubroutineFunctionSet functions_st1(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 1) subroutine uniform st0 u0[2];
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(1), 2));
////layout(location = 3) subroutine uniform st0 u1[2][3];
std::vector<int> arraySizesSegmented(2);
arraySizesSegmented[0] = 2;
arraySizesSegmented[1] = 3;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(3), arraySizesSegmented));
//layout(location = 9) subroutine uniform st1 u2;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st1, Loc::C(9)));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocMixWithImplicit : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
//subroutine(st0) vec4 sf0(float param) { .... };
//subroutine(st0) vec4 sf1(float param) { .... };
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit()));
//layout(location = 1 ) subroutine uniform st0 u1;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(0)));
//layout(location = 0 ) subroutine uniform st0 u2;
subroutineUniforms.push_back(SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(1)));
return doRun(subroutineUniforms);
}
};
class SubRoutineLocCompilationNonNumberLiteral : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def =
NL "subroutine vec4 st0(float param);" NL "subroutine(st0) vec4 sf0(float param) { return param; }" NL
"layout(location = x ) subroutine uniform st0 u0;";
return doRunNegativeCompile(def);
}
};
class SubRoutineLocCompilationNonConstLoc : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def = NL "const int i = 1;" NL "subroutine vec4 st0(float param);" NL
"subroutine(st0) vec4 sf0(float param) { return param; }" NL
"layout(location = i ) subroutine uniform st0 u0;";
return doRunNegativeCompile(def);
}
};
class SubRoutineLocLinkLocationReused1 : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout(location = 1) subroutine uniform st0 u0;
//layout(location = 1) subroutine uniform st0 u0;
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2), 0, DefOccurence::FSH_OR_CSH));
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
class SubRoutineLocLinkLocationMaxLocation : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//layout(location = N) subroutine uniform st0 u0;
//Where X is substituted with value of GL_MAX_UNIFORM_LOCATIONS.
GLint max;
glGetIntegerv(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, &max);
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(max), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
class SubRoutineLocLinkMaxNumOfLocations : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
GLint max;
glGetIntegerv(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, &max);
SubroutineFunctionSet functions_st0(uniformValueGenerator, 2);
std::vector<SubroutineUniform> subroutineUniforms;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(0), max, DefOccurence::FSH_OR_CSH, false));
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
class SubroutineIndex : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 1) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(1)));
//layout(index = 2) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexNonDecimal : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 0x0a) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(0x0a, Index::Hex)));
//layout(index = 010 ) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(010, Index::Oct)));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexLoc : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 1) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(1)));
//layout(index = 2) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 3) subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(3), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexNonCont : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 0) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(0)));
//layout(index = 2) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 2) subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexMultUniforms : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//one shader:
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 1) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(1)));
//layout(index = 3) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(3)));
//subroutine vec4 st1(float param);
SubroutineFunctionSet functions_st1(uniformValueGenerator);
//layout(index = 2) subroutine(st1) vec4 sf2(float param) { .... };
functions_st1.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
//layout(index = 0) subroutine(st1) vec4 sf3(float param) { .... };
functions_st1.push_back(SubroutineFunction(uniformValueGenerator, Index::C(0)));
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 1) subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(1), 0, DefOccurence::FSH_OR_CSH));
//layout(location = 9) subroutine uniform st1 u1;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st1, Loc::C(9), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexAllstages : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 1) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(1)));
//layout(index = 2) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::ALL_SH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexMixImplicit : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::Implicit()));
//layout(index = 1) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(1)));
//layout(index = 0) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(0)));
std::vector<SubroutineUniform> subroutineUniforms;
//layout(location = 2) subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::C(2), 0, DefOccurence::FSH_OR_CSH));
return doRun(subroutineUniforms);
}
};
class SubroutineIndexNegativeCompilationNonNumberLiteral : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def = NL "subroutine vec4 st0(float param);" NL
"layout(index = x) subroutine(st0) vec4 sf1(float param) { return param; };";
return doRunNegativeCompile(def);
}
};
class SubroutineIndexNegativeCompilationNonConstIndex : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
std::string def =
NL "const int i = 1;" NL "layout(index = i) subroutine(st0) vec4 sf1(float param) { return param; };";
return doRunNegativeCompile(def);
}
};
class SubroutineIndexNegativeLinkIndexReused : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = 2) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
//layout(index = 2) subroutine(st0) vec4 sf1(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(2)));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
class SubroutineIndexNegativeLinkMaxIndex : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
GLint max;
glGetIntegerv(GL_MAX_SUBROUTINES, &max);
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
//layout(index = N) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(max)));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
class SubroutineIndexNegativeLinkMaxNumOfIndices : public ExplicitUniformLocationCaseBase
{
virtual long Run()
{
//subroutine vec4 st0(float param);
SubroutineFunctionSet functions_st0(uniformValueGenerator);
glw::GLint max;
glGetIntegerv(GL_MAX_SUBROUTINES, &max);
for (int i = 0; i < max; i++)
{
//layout(index = N) subroutine(st0) vec4 sf0(float param) { .... };
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::C(i)));
}
functions_st0.push_back(SubroutineFunction(uniformValueGenerator, Index::Implicit()));
std::vector<SubroutineUniform> subroutineUniforms;
//subroutine uniform st0 u0;
subroutineUniforms.push_back(
SubroutineUniform(uniformValueGenerator, functions_st0, Loc::Implicit(), 0, DefOccurence::FSH_OR_CSH));
return doRunNegativeLink(subroutineUniforms);
}
};
}
ExplicitUniformLocationGLTests::ExplicitUniformLocationGLTests(glcts::Context& context)
: TestCaseGroup(context, "explicit_uniform_location", "")
{
}
ExplicitUniformLocationGLTests::~ExplicitUniformLocationGLTests(void)
{
}
void ExplicitUniformLocationGLTests::init()
{
using namespace glcts;
Logger::setOutput(m_context.getTestContext().getLog());
addChild(new TestSubcase(m_context, "uniform-loc", TestSubcase::Create<UniformLoc>));
addChild(new TestSubcase(m_context, "uniform-loc-nondecimal", TestSubcase::Create<UniformLocNonDec>));
addChild(new TestSubcase(m_context, "uniform-loc-all-stages", TestSubcase::Create<UniformLocMultipleStages>));
addChild(
new TestSubcase(m_context, "uniform-loc-multiple-uniforms", TestSubcase::Create<UniformLocMultipleUniforms>));
addChild(new TestSubcase(m_context, "uniform-loc-types-mix", TestSubcase::Create<UniformLocTypesMix>));
addChild(new TestSubcase(m_context, "uniform-loc-types-mat", TestSubcase::Create<UniformLocTypesMat>));
addChild(new TestSubcase(m_context, "uniform-loc-types-structs", TestSubcase::Create<UniformLocTypesStructs>));
addChild(new TestSubcase(m_context, "uniform-loc-types-samplers", TestSubcase::Create<UniformLocTypesSamplers>));
addChild(
new TestSubcase(m_context, "uniform-loc-arrays-nonspaced", TestSubcase::Create<UniformLocArraysNonSpaced>));
addChild(new TestSubcase(m_context, "uniform-loc-arrays-spaced", TestSubcase::Create<UniformLocArraySpaced>));
addChild(new TestSubcase(m_context, "uniform-loc-arrays-of-arrays", TestSubcase::Create<UniformLocArrayofArrays>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit", TestSubcase::Create<UniformLocMixWithImplicit>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit2", TestSubcase::Create<UniformLocMixWithImplicit2>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit3", TestSubcase::Create<UniformLocMixWithImplicit3>));
addChild(new TestSubcase(m_context, "uniform-loc-mix-with-implicit-max",
TestSubcase::Create<UniformLocMixWithImplicitMax>));
addChild(new TestSubcase(m_context, "uniform-loc-mix-with-implicit-max-array",
TestSubcase::Create<UniformLocMixWithImplicitMaxArray>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages",
TestSubcase::Create<UniformLocImplicitInSomeStages>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages2",
TestSubcase::Create<UniformLocImplicitInSomeStages2>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages3",
TestSubcase::Create<UniformLocImplicitInSomeStages3>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-compile-non-number-literal",
TestSubcase::Create<UniformLocNegativeCompileNonNumberLiteral>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-compile-nonconst-loc",
TestSubcase::Create<UniformLocNegativeCompileNonConstLoc>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-location-reused1",
TestSubcase::Create<UniformLocNegativeLinkLocationReused1>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-location-reused2",
TestSubcase::Create<UniformLocNegativeLinkLocationReused2>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-max-location",
TestSubcase::Create<UniformLocNegativeLinkMaxLocation>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-max-num-of-locations",
TestSubcase::Create<UniformLocNegativeLinkMaxMaxNumOfLocation>));
addChild(new TestSubcase(m_context, "subroutine-loc", TestSubcase::Create<SubRoutineLoc>));
addChild(new TestSubcase(m_context, "subroutine-loc-nondecimal", TestSubcase::Create<SubRoutineLocNonDecimal>));
addChild(new TestSubcase(m_context, "subroutine-loc-all-stages", TestSubcase::Create<SubRoutineLocAllStages>));
addChild(new TestSubcase(m_context, "subroutine-loc-arrays", TestSubcase::Create<SubRoutineLocArrays>));
addChild(new TestSubcase(m_context, "subroutine-loc-arrays-mix", TestSubcase::Create<SubRoutineLocArraysMix>));
addChild(new TestSubcase(m_context, "subroutine-loc-mix-with-implicit",
TestSubcase::Create<SubRoutineLocMixWithImplicit>));
addChild(new TestSubcase(m_context, "subroutine-loc-negative-compilation-non-number-literal",
TestSubcase::Create<SubRoutineLocCompilationNonNumberLiteral>));
addChild(new TestSubcase(m_context, "subroutine-loc-negative-compilation-nonconst-loc",
TestSubcase::Create<SubRoutineLocCompilationNonConstLoc>));
addChild(new TestSubcase(m_context, "subroutine-loc-negative-link-location-reused1",
TestSubcase::Create<SubRoutineLocLinkLocationReused1>));
addChild(new TestSubcase(m_context, "subroutine-loc-negative-link-location-max-location",
TestSubcase::Create<SubRoutineLocLinkLocationMaxLocation>));
addChild(new TestSubcase(m_context, "subroutine-loc-negative-link-max-num-of-locations",
TestSubcase::Create<SubRoutineLocLinkMaxNumOfLocations>));
addChild(new TestSubcase(m_context, "subroutine-index", TestSubcase::Create<SubroutineIndex>));
addChild(new TestSubcase(m_context, "subroutine-index-nondecimal", TestSubcase::Create<SubroutineIndexNonDecimal>));
addChild(new TestSubcase(m_context, "subroutine-index-loc", TestSubcase::Create<SubroutineIndexLoc>));
addChild(
new TestSubcase(m_context, "subroutine-index-non-continuous", TestSubcase::Create<SubroutineIndexNonCont>));
addChild(new TestSubcase(m_context, "subroutine-index-multiple-uniforms",
TestSubcase::Create<SubroutineIndexMultUniforms>));
addChild(new TestSubcase(m_context, "subroutine-index-all-stages", TestSubcase::Create<SubroutineIndexAllstages>));
addChild(
new TestSubcase(m_context, "subroutine-index-mix-implicit", TestSubcase::Create<SubroutineIndexMixImplicit>));
addChild(new TestSubcase(m_context, "subroutine-index-negative-compilation-non-number-literal",
TestSubcase::Create<SubroutineIndexNegativeCompilationNonNumberLiteral>));
addChild(new TestSubcase(m_context, "subroutine-index-negative-compilation-nonconst-index",
TestSubcase::Create<SubroutineIndexNegativeCompilationNonConstIndex>));
addChild(new TestSubcase(m_context, "subroutine-index-negative-link-index-reused",
TestSubcase::Create<SubroutineIndexNegativeLinkIndexReused>));
addChild(new TestSubcase(m_context, "subroutine-index-negative-link-location-maxindex",
TestSubcase::Create<SubroutineIndexNegativeLinkMaxIndex>));
addChild(new TestSubcase(m_context, "subroutine-index-negative-link-max-num-of-indices",
TestSubcase::Create<SubroutineIndexNegativeLinkMaxNumOfIndices>));
}
ExplicitUniformLocationES31Tests::ExplicitUniformLocationES31Tests(glcts::Context& context)
: TestCaseGroup(context, "explicit_uniform_location", "")
{
}
ExplicitUniformLocationES31Tests::~ExplicitUniformLocationES31Tests(void)
{
}
void ExplicitUniformLocationES31Tests::init()
{
using namespace glcts;
Logger::setOutput(m_context.getTestContext().getLog());
addChild(new TestSubcase(m_context, "uniform-loc", TestSubcase::Create<UniformLoc>));
addChild(new TestSubcase(m_context, "uniform-loc-nondecimal", TestSubcase::Create<UniformLocNonDec>));
addChild(new TestSubcase(m_context, "uniform-loc-all-stages", TestSubcase::Create<UniformLocMultipleStages>));
addChild(
new TestSubcase(m_context, "uniform-loc-multiple-uniforms", TestSubcase::Create<UniformLocMultipleUniforms>));
addChild(new TestSubcase(m_context, "uniform-loc-types-mix", TestSubcase::Create<UniformLocTypesMix>));
addChild(new TestSubcase(m_context, "uniform-loc-types-mat", TestSubcase::Create<UniformLocTypesMat>));
addChild(new TestSubcase(m_context, "uniform-loc-types-structs", TestSubcase::Create<UniformLocTypesStructs>));
addChild(new TestSubcase(m_context, "uniform-loc-types-samplers", TestSubcase::Create<UniformLocTypesSamplers>));
addChild(
new TestSubcase(m_context, "uniform-loc-arrays-nonspaced", TestSubcase::Create<UniformLocArraysNonSpaced>));
addChild(new TestSubcase(m_context, "uniform-loc-arrays-spaced", TestSubcase::Create<UniformLocArraySpaced>));
addChild(new TestSubcase(m_context, "uniform-loc-arrays-of-arrays", TestSubcase::Create<UniformLocArrayofArrays>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit", TestSubcase::Create<UniformLocMixWithImplicit>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit2", TestSubcase::Create<UniformLocMixWithImplicit2>));
addChild(
new TestSubcase(m_context, "uniform-loc-mix-with-implicit3", TestSubcase::Create<UniformLocMixWithImplicit3>));
addChild(new TestSubcase(m_context, "uniform-loc-mix-with-implicit-max",
TestSubcase::Create<UniformLocMixWithImplicitMax>));
addChild(new TestSubcase(m_context, "uniform-loc-mix-with-implicit-max-array",
TestSubcase::Create<UniformLocMixWithImplicitMaxArray>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages",
TestSubcase::Create<UniformLocImplicitInSomeStages>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages2",
TestSubcase::Create<UniformLocImplicitInSomeStages2>));
addChild(new TestSubcase(m_context, "uniform-loc-implicit-in-some-stages3",
TestSubcase::Create<UniformLocImplicitInSomeStages3>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-compile-non-number-literal",
TestSubcase::Create<UniformLocNegativeCompileNonNumberLiteral>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-compile-nonconst-loc",
TestSubcase::Create<UniformLocNegativeCompileNonConstLoc>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-location-reused1",
TestSubcase::Create<UniformLocNegativeLinkLocationReused1>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-location-reused2",
TestSubcase::Create<UniformLocNegativeLinkLocationReused2>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-max-location",
TestSubcase::Create<UniformLocNegativeLinkMaxLocation>));
addChild(new TestSubcase(m_context, "uniform-loc-negative-link-max-num-of-locations",
TestSubcase::Create<UniformLocNegativeLinkMaxMaxNumOfLocation>));
}
}