You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2428 lines
94 KiB
2428 lines
94 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 2.0 Module
|
|
* -------------------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* 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 Uniform API tests.
|
|
*
|
|
* \todo [2013-02-26 nuutti] Much duplication between this and ES3.
|
|
* Utilities to glshared?
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es2fUniformApiTests.hpp"
|
|
#include "gluCallLogWrapper.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluVarType.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "gluTextureUtil.hpp"
|
|
#include "gluTexture.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
#include "deRandom.hpp"
|
|
#include "deStringUtil.hpp"
|
|
#include "deSharedPtr.hpp"
|
|
#include "deString.h"
|
|
#include "deMemory.h"
|
|
|
|
#include "glwEnums.hpp"
|
|
#include "glwFunctions.hpp"
|
|
|
|
#include <set>
|
|
#include <cstring>
|
|
|
|
using namespace glw;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles2
|
|
{
|
|
namespace Functional
|
|
{
|
|
|
|
using std::vector;
|
|
using std::string;
|
|
using tcu::TestLog;
|
|
using tcu::ScopedLogSection;
|
|
using glu::ShaderProgram;
|
|
using glu::StructType;
|
|
using de::Random;
|
|
using de::SharedPtr;
|
|
|
|
typedef bool (* dataTypePredicate)(glu::DataType);
|
|
|
|
static const int MAX_RENDER_WIDTH = 32;
|
|
static const int MAX_RENDER_HEIGHT = 32;
|
|
static const int MAX_NUM_SAMPLER_UNIFORMS = 16;
|
|
|
|
static const glu::DataType s_testDataTypes[] =
|
|
{
|
|
glu::TYPE_FLOAT,
|
|
glu::TYPE_FLOAT_VEC2,
|
|
glu::TYPE_FLOAT_VEC3,
|
|
glu::TYPE_FLOAT_VEC4,
|
|
glu::TYPE_FLOAT_MAT2,
|
|
glu::TYPE_FLOAT_MAT3,
|
|
glu::TYPE_FLOAT_MAT4,
|
|
|
|
glu::TYPE_INT,
|
|
glu::TYPE_INT_VEC2,
|
|
glu::TYPE_INT_VEC3,
|
|
glu::TYPE_INT_VEC4,
|
|
|
|
glu::TYPE_BOOL,
|
|
glu::TYPE_BOOL_VEC2,
|
|
glu::TYPE_BOOL_VEC3,
|
|
glu::TYPE_BOOL_VEC4,
|
|
|
|
glu::TYPE_SAMPLER_2D,
|
|
glu::TYPE_SAMPLER_CUBE
|
|
};
|
|
|
|
static inline int getGLInt (const glw::Functions& funcs, const deUint32 name)
|
|
{
|
|
int val = -1;
|
|
funcs.getIntegerv(name, &val);
|
|
return val;
|
|
}
|
|
|
|
static inline tcu::Vec4 vec4FromPtr (const float* const ptr)
|
|
{
|
|
tcu::Vec4 result;
|
|
for (int i = 0; i < 4; i++)
|
|
result[i] = ptr[i];
|
|
return result;
|
|
}
|
|
|
|
static inline string beforeLast (const string& str, const char c)
|
|
{
|
|
return str.substr(0, str.find_last_of(c));
|
|
}
|
|
|
|
static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color)
|
|
{
|
|
for (int z = 0; z < access.getDepth(); z++)
|
|
for (int y = 0; y < access.getHeight(); y++)
|
|
for (int x = 0; x < access.getWidth(); x++)
|
|
access.setPixel(color, x, y, z);
|
|
}
|
|
|
|
static inline int getSamplerNumLookupDimensions (const glu::DataType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case glu::TYPE_SAMPLER_2D:
|
|
return 2;
|
|
|
|
case glu::TYPE_SAMPLER_CUBE:
|
|
return 3;
|
|
|
|
default: // \note All others than 2d and cube are gles3-only types.
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
template<glu::DataType T>
|
|
static bool dataTypeEquals (const glu::DataType t)
|
|
{
|
|
return t == T;
|
|
}
|
|
|
|
template<int N>
|
|
static bool dataTypeIsMatrixWithNRows (const glu::DataType t)
|
|
{
|
|
return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N;
|
|
}
|
|
|
|
static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate)
|
|
{
|
|
if (type.isBasicType())
|
|
return predicate(type.getBasicType());
|
|
else if (type.isArrayType())
|
|
return typeContainsMatchingBasicType(type.getElementType(), predicate);
|
|
else
|
|
{
|
|
DE_ASSERT(type.isStructType());
|
|
const StructType& structType = *type.getStructPtr();
|
|
for (int i = 0; i < structType.getNumMembers(); i++)
|
|
if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate))
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type)
|
|
{
|
|
if (type.isBasicType())
|
|
{
|
|
const glu::DataType basicType = type.getBasicType();
|
|
if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end())
|
|
dst.push_back(basicType);
|
|
}
|
|
else if (type.isArrayType())
|
|
getDistinctSamplerTypes(dst, type.getElementType());
|
|
else
|
|
{
|
|
DE_ASSERT(type.isStructType());
|
|
const StructType& structType = *type.getStructPtr();
|
|
for (int i = 0; i < structType.getNumMembers(); i++)
|
|
getDistinctSamplerTypes(dst, structType.getMember(i).getType());
|
|
}
|
|
}
|
|
|
|
static int getNumSamplersInType (const glu::VarType& type)
|
|
{
|
|
if (type.isBasicType())
|
|
return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0;
|
|
else if (type.isArrayType())
|
|
return getNumSamplersInType(type.getElementType()) * type.getArraySize();
|
|
else
|
|
{
|
|
DE_ASSERT(type.isStructType());
|
|
const StructType& structType = *type.getStructPtr();
|
|
int sum = 0;
|
|
for (int i = 0; i < structType.getNumMembers(); i++)
|
|
sum += getNumSamplersInType(structType.getMember(i).getType());
|
|
return sum;
|
|
}
|
|
}
|
|
|
|
static glu::VarType generateRandomType (const int maxDepth, int& curStructIdx, vector<const StructType*>& structTypesDst, Random& rnd)
|
|
{
|
|
const bool isStruct = maxDepth > 0 && rnd.getFloat() < 0.2f;
|
|
const bool isArray = rnd.getFloat() < 0.3f;
|
|
|
|
if (isStruct)
|
|
{
|
|
const int numMembers = rnd.getInt(1, 5);
|
|
StructType* const structType = new StructType(("structType" + de::toString(curStructIdx++)).c_str());
|
|
|
|
for (int i = 0; i < numMembers; i++)
|
|
structType->addMember(("m" + de::toString(i)).c_str(), generateRandomType(maxDepth-1, curStructIdx, structTypesDst, rnd));
|
|
|
|
structTypesDst.push_back(structType);
|
|
return isArray ? glu::VarType(glu::VarType(structType), rnd.getInt(1, 5)) : glu::VarType(structType);
|
|
}
|
|
else
|
|
{
|
|
const glu::DataType basicType = (glu::DataType)s_testDataTypes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testDataTypes)-1)];
|
|
const glu::Precision precision = glu::isDataTypeBoolOrBVec(basicType) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
return isArray ? glu::VarType(glu::VarType(basicType, precision), rnd.getInt(1, 5)) : glu::VarType(basicType, precision);
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
struct VarValue
|
|
{
|
|
glu::DataType type;
|
|
|
|
union
|
|
{
|
|
float floatV[4*4]; // At most mat4. \note Matrices here are column-major.
|
|
deInt32 intV[4];
|
|
bool boolV[4];
|
|
struct
|
|
{
|
|
int unit;
|
|
float fillColor[4];
|
|
} samplerV;
|
|
} val;
|
|
};
|
|
|
|
enum CaseShaderType
|
|
{
|
|
CASESHADERTYPE_VERTEX = 0,
|
|
CASESHADERTYPE_FRAGMENT,
|
|
CASESHADERTYPE_BOTH,
|
|
|
|
CASESHADERTYPE_LAST
|
|
};
|
|
|
|
struct Uniform
|
|
{
|
|
string name;
|
|
glu::VarType type;
|
|
|
|
Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {}
|
|
};
|
|
|
|
// A set of uniforms, along with related struct types.
|
|
class UniformCollection
|
|
{
|
|
public:
|
|
int getNumUniforms (void) const { return (int)m_uniforms.size(); }
|
|
int getNumStructTypes (void) const { return (int)m_structTypes.size(); }
|
|
Uniform& getUniform (const int ndx) { return m_uniforms[ndx]; }
|
|
const Uniform& getUniform (const int ndx) const { return m_uniforms[ndx]; }
|
|
const StructType* getStructType (const int ndx) const { return m_structTypes[ndx]; }
|
|
void addUniform (const Uniform& uniform) { m_uniforms.push_back(uniform); }
|
|
void addStructType (const StructType* const type) { m_structTypes.push_back(type); }
|
|
|
|
UniformCollection (void) {}
|
|
~UniformCollection (void)
|
|
{
|
|
for (int i = 0; i < (int)m_structTypes.size(); i++)
|
|
delete m_structTypes[i];
|
|
}
|
|
|
|
// Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one.
|
|
// \note receiver takes ownership of the struct types.
|
|
void moveContents (UniformCollection& receiver)
|
|
{
|
|
for (int i = 0; i < (int)m_uniforms.size(); i++)
|
|
receiver.addUniform(m_uniforms[i]);
|
|
m_uniforms.clear();
|
|
|
|
for (int i = 0; i < (int)m_structTypes.size(); i++)
|
|
receiver.addStructType(m_structTypes[i]);
|
|
m_structTypes.clear();
|
|
}
|
|
|
|
bool containsMatchingBasicType (const dataTypePredicate predicate) const
|
|
{
|
|
for (int i = 0; i < (int)m_uniforms.size(); i++)
|
|
if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
vector<glu::DataType> getSamplerTypes (void) const
|
|
{
|
|
vector<glu::DataType> samplerTypes;
|
|
for (int i = 0; i < (int)m_uniforms.size(); i++)
|
|
getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type);
|
|
return samplerTypes;
|
|
}
|
|
|
|
bool containsSeveralSamplerTypes (void) const
|
|
{
|
|
return getSamplerTypes().size() > 1;
|
|
}
|
|
|
|
int getNumSamplers (void) const
|
|
{
|
|
int sum = 0;
|
|
for (int i = 0; i < (int)m_uniforms.size(); i++)
|
|
sum += getNumSamplersInType(m_uniforms[i].type);
|
|
return sum;
|
|
}
|
|
|
|
static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "")
|
|
{
|
|
UniformCollection* const res = new UniformCollection;
|
|
const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec)));
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "")
|
|
{
|
|
UniformCollection* const res = new UniformCollection;
|
|
const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3)));
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
|
|
{
|
|
UniformCollection* const res = new UniformCollection;
|
|
const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
|
|
StructType* const structType = new StructType((string("structType") + nameSuffix).c_str());
|
|
structType->addMember("m0", glu::VarType(type0, prec0));
|
|
structType->addMember("m1", glu::VarType(type1, prec1));
|
|
if (containsArrays)
|
|
{
|
|
structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3));
|
|
structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3));
|
|
}
|
|
|
|
res->addStructType(structType);
|
|
res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
|
|
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "")
|
|
{
|
|
UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix);
|
|
res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3);
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "")
|
|
{
|
|
UniformCollection* const res = new UniformCollection;
|
|
const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP;
|
|
StructType* const structType = new StructType((string("structType") + nameSuffix).c_str());
|
|
StructType* const subStructType = new StructType((string("subStructType") + nameSuffix).c_str());
|
|
StructType* const subSubStructType = new StructType((string("subSubStructType") + nameSuffix).c_str());
|
|
|
|
subSubStructType->addMember("mss0", glu::VarType(type0, prec0));
|
|
subSubStructType->addMember("mss1", glu::VarType(type1, prec1));
|
|
|
|
subStructType->addMember("ms0", glu::VarType(type1, prec1));
|
|
subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2));
|
|
subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2));
|
|
|
|
structType->addMember("m0", glu::VarType(type0, prec0));
|
|
structType->addMember("m1", glu::VarType(subStructType));
|
|
structType->addMember("m2", glu::VarType(type1, prec1));
|
|
|
|
res->addStructType(subSubStructType);
|
|
res->addStructType(subStructType);
|
|
res->addStructType(structType);
|
|
|
|
res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType)));
|
|
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* multipleBasic (const char* const nameSuffix = "")
|
|
{
|
|
static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 };
|
|
UniformCollection* const res = new UniformCollection;
|
|
|
|
for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
|
|
{
|
|
UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
|
|
sub->moveContents(*res);
|
|
delete sub;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* multipleBasicArray (const char* const nameSuffix = "")
|
|
{
|
|
static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 };
|
|
UniformCollection* const res = new UniformCollection;
|
|
|
|
for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++)
|
|
{
|
|
UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str());
|
|
sub->moveContents(*res);
|
|
delete sub;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "")
|
|
{
|
|
static const glu::DataType types0[] = { glu::TYPE_FLOAT, glu::TYPE_INT, glu::TYPE_BOOL_VEC4 };
|
|
static const glu::DataType types1[] = { glu::TYPE_FLOAT_VEC4, glu::TYPE_INT_VEC4, glu::TYPE_BOOL };
|
|
UniformCollection* const res = new UniformCollection;
|
|
|
|
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1));
|
|
|
|
for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++)
|
|
{
|
|
UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str());
|
|
sub->moveContents(*res);
|
|
delete sub;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static UniformCollection* random (const deUint32 seed)
|
|
{
|
|
Random rnd (seed);
|
|
const int numUniforms = rnd.getInt(1, 5);
|
|
int structIdx = 0;
|
|
UniformCollection* const res = new UniformCollection;
|
|
|
|
for (int i = 0; i < numUniforms; i++)
|
|
{
|
|
vector<const StructType*> structTypes;
|
|
Uniform uniform(("u_var" + de::toString(i)).c_str(), glu::VarType());
|
|
|
|
// \note Discard uniforms that would cause number of samplers to exceed MAX_NUM_SAMPLER_UNIFORMS.
|
|
do
|
|
{
|
|
for (int j = 0; j < (int)structTypes.size(); j++)
|
|
delete structTypes[j];
|
|
structTypes.clear();
|
|
uniform.type = generateRandomType(3, structIdx, structTypes, rnd);
|
|
} while (res->getNumSamplers() + getNumSamplersInType(uniform.type) > MAX_NUM_SAMPLER_UNIFORMS);
|
|
|
|
res->addUniform(uniform);
|
|
for (int j = 0; j < (int)structTypes.size(); j++)
|
|
res->addStructType(structTypes[j]);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
// \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes
|
|
// would mean that we'd need to update pointers from uniforms to point to the new structTypes.
|
|
// When the same UniformCollection is needed in several places, a SharedPtr is used instead.
|
|
UniformCollection (const UniformCollection&); // Not allowed.
|
|
UniformCollection& operator= (const UniformCollection&); // Not allowed.
|
|
|
|
vector<Uniform> m_uniforms;
|
|
vector<const StructType*> m_structTypes;
|
|
};
|
|
|
|
}; // anonymous
|
|
|
|
static VarValue getSamplerFillValue (const VarValue& sampler)
|
|
{
|
|
DE_ASSERT(glu::isDataTypeSampler(sampler.type));
|
|
|
|
VarValue result;
|
|
result.type = glu::TYPE_FLOAT_VEC4;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
result.val.floatV[i] = sampler.val.samplerV.fillColor[i];
|
|
|
|
return result;
|
|
}
|
|
|
|
static VarValue getSamplerUnitValue (const VarValue& sampler)
|
|
{
|
|
DE_ASSERT(glu::isDataTypeSampler(sampler.type));
|
|
|
|
VarValue result;
|
|
result.type = glu::TYPE_INT;
|
|
result.val.intV[0] = sampler.val.samplerV.unit;
|
|
|
|
return result;
|
|
}
|
|
|
|
static string shaderVarValueStr (const VarValue& value)
|
|
{
|
|
const int numElems = glu::getDataTypeScalarSize(value.type);
|
|
std::ostringstream result;
|
|
|
|
if (numElems > 1)
|
|
result << glu::getDataTypeName(value.type) << "(";
|
|
|
|
for (int i = 0; i < numElems; i++)
|
|
{
|
|
if (i > 0)
|
|
result << ", ";
|
|
|
|
if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
|
|
result << de::floatToString(value.val.floatV[i], 2);
|
|
else if (glu::isDataTypeIntOrIVec((value.type)))
|
|
result << de::toString(value.val.intV[i]);
|
|
else if (glu::isDataTypeBoolOrBVec((value.type)))
|
|
result << (value.val.boolV[i] ? "true" : "false");
|
|
else if (glu::isDataTypeSampler((value.type)))
|
|
result << shaderVarValueStr(getSamplerFillValue(value));
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
if (numElems > 1)
|
|
result << ")";
|
|
|
|
return result.str();
|
|
}
|
|
|
|
static string apiVarValueStr (const VarValue& value)
|
|
{
|
|
const int numElems = glu::getDataTypeScalarSize(value.type);
|
|
std::ostringstream result;
|
|
|
|
if (numElems > 1)
|
|
result << "(";
|
|
|
|
for (int i = 0; i < numElems; i++)
|
|
{
|
|
if (i > 0)
|
|
result << ", ";
|
|
|
|
if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type))
|
|
result << de::floatToString(value.val.floatV[i], 2);
|
|
else if (glu::isDataTypeIntOrIVec((value.type)))
|
|
result << de::toString(value.val.intV[i]);
|
|
else if (glu::isDataTypeBoolOrBVec((value.type)))
|
|
result << (value.val.boolV[i] ? "true" : "false");
|
|
else if (glu::isDataTypeSampler((value.type)))
|
|
result << value.val.samplerV.unit;
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
if (numElems > 1)
|
|
result << ")";
|
|
|
|
return result.str();
|
|
}
|
|
|
|
static VarValue generateRandomVarValue (const glu::DataType type, Random& rnd, int samplerUnit = -1 /* Used if type is a sampler type. \note Samplers' unit numbers are not randomized. */)
|
|
{
|
|
const int numElems = glu::getDataTypeScalarSize(type);
|
|
VarValue result;
|
|
result.type = type;
|
|
|
|
DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type)));
|
|
|
|
if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
|
|
}
|
|
else if (glu::isDataTypeIntOrIVec(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.intV[i] = rnd.getInt(-10, 10);
|
|
}
|
|
else if (glu::isDataTypeBoolOrBVec(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.boolV[i] = rnd.getBool();
|
|
}
|
|
else if (glu::isDataTypeSampler(type))
|
|
{
|
|
result.val.samplerV.unit = samplerUnit;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
result.val.samplerV.fillColor[i] = rnd.getFloat(0.0f, 1.0f);
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
static VarValue generateZeroVarValue (const glu::DataType type)
|
|
{
|
|
const int numElems = glu::getDataTypeScalarSize(type);
|
|
VarValue result;
|
|
result.type = type;
|
|
|
|
if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.floatV[i] = 0.0f;
|
|
}
|
|
else if (glu::isDataTypeIntOrIVec(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.intV[i] = 0;
|
|
}
|
|
else if (glu::isDataTypeBoolOrBVec(type))
|
|
{
|
|
for (int i = 0; i < numElems; i++)
|
|
result.val.boolV[i] = false;
|
|
}
|
|
else if (glu::isDataTypeSampler(type))
|
|
{
|
|
result.val.samplerV.unit = 0;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
result.val.samplerV.fillColor[i] = 0.12f * (float)i;
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
static bool apiVarValueEquals (const VarValue& a, const VarValue& b)
|
|
{
|
|
const int size = glu::getDataTypeScalarSize(a.type);
|
|
const float floatThreshold = 0.05f;
|
|
|
|
DE_ASSERT(a.type == b.type);
|
|
|
|
if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type))
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold)
|
|
return false;
|
|
}
|
|
else if (glu::isDataTypeIntOrIVec(a.type))
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
if (a.val.intV[i] != b.val.intV[i])
|
|
return false;
|
|
}
|
|
else if (glu::isDataTypeBoolOrBVec(a.type))
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
if (a.val.boolV[i] != b.val.boolV[i])
|
|
return false;
|
|
}
|
|
else if (glu::isDataTypeSampler(a.type))
|
|
{
|
|
if (a.val.samplerV.unit != b.val.samplerV.unit)
|
|
return false;
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd)
|
|
{
|
|
DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type));
|
|
|
|
const int size = glu::getDataTypeScalarSize(boolValue.type);
|
|
const glu::DataType targetType = size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size);
|
|
VarValue result;
|
|
result.type = targetType;
|
|
|
|
switch (targetScalarType)
|
|
{
|
|
case glu::TYPE_INT:
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
if (boolValue.val.boolV[i])
|
|
{
|
|
result.val.intV[i] = rnd.getInt(-10, 10);
|
|
if (result.val.intV[i] == 0)
|
|
result.val.intV[i] = 1;
|
|
}
|
|
else
|
|
result.val.intV[i] = 0;
|
|
}
|
|
break;
|
|
|
|
case glu::TYPE_FLOAT:
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
if (boolValue.val.boolV[i])
|
|
{
|
|
result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f);
|
|
if (result.val.floatV[i] == 0.0f)
|
|
result.val.floatV[i] = 1.0f;
|
|
}
|
|
else
|
|
result.val.floatV[i] = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static const char* getCaseShaderTypeName (const CaseShaderType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case CASESHADERTYPE_VERTEX: return "vertex";
|
|
case CASESHADERTYPE_FRAGMENT: return "fragment";
|
|
case CASESHADERTYPE_BOTH: return "both";
|
|
default:
|
|
DE_ASSERT(false);
|
|
return DE_NULL;
|
|
}
|
|
}
|
|
|
|
static CaseShaderType randomCaseShaderType (const deUint32 seed)
|
|
{
|
|
return (CaseShaderType)Random(seed).getInt(0, CASESHADERTYPE_LAST-1);
|
|
}
|
|
|
|
class UniformCase : public TestCase, protected glu::CallLogWrapper
|
|
{
|
|
public:
|
|
enum Feature
|
|
{
|
|
// ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices.
|
|
FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX = 1<<0,
|
|
|
|
// UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glUniform1f(), where possible. If not given, use pass-by-pointer versions.
|
|
FEATURE_UNIFORMFUNC_VALUE = 1<<1,
|
|
|
|
// ARRAYASSIGN: how basic-type arrays are assigned with glUniform*(). If none given, assign each element of an array separately.
|
|
FEATURE_ARRAYASSIGN_FULL = 1<<2, //!< Assign all elements of an array with one glUniform*().
|
|
FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO = 1<<3, //!< Assign two elements per one glUniform*().
|
|
|
|
// UNIFORMUSAGE_EVERY_OTHER: use about half of the uniforms. If not given, use all uniforms (except that some array indices may be omitted according to ARRAYUSAGE).
|
|
FEATURE_UNIFORMUSAGE_EVERY_OTHER = 1<<4,
|
|
|
|
// BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float.
|
|
FEATURE_BOOLEANAPITYPE_INT = 1<<5,
|
|
|
|
// UNIFORMVALUE_ZERO: use zero-valued uniforms. If not given, use random uniform values.
|
|
FEATURE_UNIFORMVALUE_ZERO = 1<<6,
|
|
|
|
// ARRAY_FIRST_ELEM_NAME_NO_INDEX: in certain API functions, when referring to the first element of an array, use just the array name without [0] at the end.
|
|
FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX = 1<<7
|
|
};
|
|
|
|
UniformCase (Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features);
|
|
UniformCase (Context& context, const char* name, const char* description, deUint32 seed); // \note Randomizes caseType, uniformCollection and features.
|
|
virtual ~UniformCase (void);
|
|
|
|
virtual void init (void);
|
|
virtual void deinit (void);
|
|
|
|
IterateResult iterate (void);
|
|
|
|
protected:
|
|
// A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d).
|
|
struct BasicUniform
|
|
{
|
|
string name;
|
|
glu::DataType type;
|
|
bool isUsedInShader;
|
|
VarValue finalValue; //!< The value we ultimately want to set for this uniform.
|
|
|
|
string rootName; //!< If this is a member of a basic-typed array, rootName is the name of that array with "[0]" appended. Otherwise it equals name.
|
|
int elemNdx; //!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1.
|
|
int rootSize; //!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1.
|
|
|
|
BasicUniform (const char* const name_,
|
|
const glu::DataType type_,
|
|
const bool isUsedInShader_,
|
|
const VarValue& finalValue_,
|
|
const char* const rootName_ = DE_NULL,
|
|
const int elemNdx_ = -1,
|
|
const int rootSize_ = 1)
|
|
: name (name_)
|
|
, type (type_)
|
|
, isUsedInShader (isUsedInShader_)
|
|
, finalValue (finalValue_)
|
|
, rootName (rootName_ == DE_NULL ? name_ : rootName_)
|
|
, elemNdx (elemNdx_)
|
|
, rootSize (rootSize_)
|
|
{
|
|
}
|
|
|
|
static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name)
|
|
{
|
|
for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++)
|
|
{
|
|
if (it->name == name)
|
|
return it;
|
|
}
|
|
return vec.end();
|
|
}
|
|
};
|
|
|
|
// Reference values for info that is expected to be reported by glGetActiveUniform().
|
|
struct BasicUniformReportRef
|
|
{
|
|
string name;
|
|
// \note minSize and maxSize are for arrays and can be distinct since implementations are allowed, but not required, to trim the inactive end indices of arrays.
|
|
int minSize;
|
|
int maxSize;
|
|
glu::DataType type;
|
|
bool isUsedInShader;
|
|
|
|
BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used)
|
|
: name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); }
|
|
BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used)
|
|
: name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {}
|
|
};
|
|
|
|
// Info that is actually reported by glGetActiveUniform().
|
|
struct BasicUniformReportGL
|
|
{
|
|
string name;
|
|
int nameLength;
|
|
int size;
|
|
glu::DataType type;
|
|
|
|
int index;
|
|
|
|
BasicUniformReportGL (const char* const name_, const int nameLength_, const int size_, const glu::DataType type_, const int index_)
|
|
: name(name_), nameLength(nameLength_), size(size_), type(type_), index(index_) {}
|
|
|
|
static vector<BasicUniformReportGL>::const_iterator findWithName (const vector<BasicUniformReportGL>& vec, const char* const name)
|
|
{
|
|
for (vector<BasicUniformReportGL>::const_iterator it = vec.begin(); it != vec.end(); it++)
|
|
{
|
|
if (it->name == name)
|
|
return it;
|
|
}
|
|
return vec.end();
|
|
}
|
|
};
|
|
|
|
// Query info with glGetActiveUniform() and check validity.
|
|
bool getActiveUniforms (vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL);
|
|
// Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID.
|
|
bool getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL);
|
|
// Check that every uniform has the default (zero) value.
|
|
bool checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
|
|
// Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value).
|
|
void assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd);
|
|
// Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values.
|
|
bool compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms);
|
|
// Render and check that all pixels are white (i.e. all uniform comparisons passed).
|
|
bool renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd);
|
|
|
|
virtual bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0;
|
|
|
|
const deUint32 m_features;
|
|
const SharedPtr<const UniformCollection> m_uniformCollection;
|
|
|
|
private:
|
|
static deUint32 randomFeatures (deUint32 seed);
|
|
|
|
// Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected
|
|
// to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names.
|
|
void generateBasicUniforms (vector<BasicUniform>& basicUniformsDst,
|
|
vector<BasicUniformReportRef>& basicUniformReportsDst,
|
|
const glu::VarType& varType,
|
|
const char* varName,
|
|
bool isParentActive,
|
|
int& samplerUnitCounter,
|
|
Random& rnd) const;
|
|
|
|
void writeUniformDefinitions (std::ostringstream& dst) const;
|
|
void writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const;
|
|
void writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const;
|
|
|
|
string generateVertexSource (const vector<BasicUniform>& basicUniforms) const;
|
|
string generateFragmentSource (const vector<BasicUniform>& basicUniforms) const;
|
|
|
|
void setupTexture (const VarValue& value);
|
|
|
|
const CaseShaderType m_caseShaderType;
|
|
|
|
vector<glu::Texture2D*> m_textures2d;
|
|
vector<glu::TextureCube*> m_texturesCube;
|
|
vector<deUint32> m_filledTextureUnits;
|
|
};
|
|
|
|
deUint32 UniformCase::randomFeatures (const deUint32 seed)
|
|
{
|
|
static const deUint32 arrayUsageChoices[] = { 0, FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX };
|
|
static const deUint32 uniformFuncChoices[] = { 0, FEATURE_UNIFORMFUNC_VALUE };
|
|
static const deUint32 arrayAssignChoices[] = { 0, FEATURE_ARRAYASSIGN_FULL, FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO };
|
|
static const deUint32 uniformUsageChoices[] = { 0, FEATURE_UNIFORMUSAGE_EVERY_OTHER };
|
|
static const deUint32 booleanApiTypeChoices[] = { 0, FEATURE_BOOLEANAPITYPE_INT };
|
|
static const deUint32 uniformValueChoices[] = { 0, FEATURE_UNIFORMVALUE_ZERO };
|
|
|
|
Random rnd(seed);
|
|
|
|
deUint32 result = 0;
|
|
|
|
#define ARRAY_CHOICE(ARR) ((ARR)[rnd.getInt(0, DE_LENGTH_OF_ARRAY(ARR)-1)])
|
|
|
|
result |= ARRAY_CHOICE(arrayUsageChoices);
|
|
result |= ARRAY_CHOICE(uniformFuncChoices);
|
|
result |= ARRAY_CHOICE(arrayAssignChoices);
|
|
result |= ARRAY_CHOICE(uniformUsageChoices);
|
|
result |= ARRAY_CHOICE(booleanApiTypeChoices);
|
|
result |= ARRAY_CHOICE(uniformValueChoices);
|
|
|
|
#undef ARRAY_CHOICE
|
|
|
|
return result;
|
|
}
|
|
|
|
UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features)
|
|
: TestCase (context, name, description)
|
|
, CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog())
|
|
, m_features (features)
|
|
, m_uniformCollection (uniformCollection)
|
|
, m_caseShaderType (caseShaderType)
|
|
{
|
|
}
|
|
|
|
UniformCase::UniformCase (Context& context, const char* name, const char* description, const deUint32 seed)
|
|
: TestCase (context, name, description)
|
|
, CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog())
|
|
, m_features (randomFeatures(seed))
|
|
, m_uniformCollection (UniformCollection::random(seed))
|
|
, m_caseShaderType (randomCaseShaderType(seed))
|
|
{
|
|
}
|
|
|
|
void UniformCase::init (void)
|
|
{
|
|
{
|
|
const glw::Functions& funcs = m_context.getRenderContext().getFunctions();
|
|
const int numSamplerUniforms = m_uniformCollection->getNumSamplers();
|
|
const int vertexTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0;
|
|
const int fragmentTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0;
|
|
const int combinedTexUnitsRequired = vertexTexUnitsRequired + fragmentTexUnitsRequired;
|
|
const int vertexTexUnitsSupported = getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
|
|
const int fragmentTexUnitsSupported = getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS);
|
|
const int combinedTexUnitsSupported = getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
|
|
|
|
DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS);
|
|
|
|
if (vertexTexUnitsRequired > vertexTexUnitsSupported)
|
|
throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported");
|
|
if (fragmentTexUnitsRequired > fragmentTexUnitsSupported)
|
|
throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported");
|
|
if (combinedTexUnitsRequired > combinedTexUnitsSupported)
|
|
throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported");
|
|
}
|
|
|
|
enableLogging(true);
|
|
}
|
|
|
|
void UniformCase::deinit (void)
|
|
{
|
|
for (int i = 0; i < (int)m_textures2d.size(); i++)
|
|
delete m_textures2d[i];
|
|
m_textures2d.clear();
|
|
|
|
for (int i = 0; i < (int)m_texturesCube.size(); i++)
|
|
delete m_texturesCube[i];
|
|
m_texturesCube.clear();
|
|
|
|
m_filledTextureUnits.clear();
|
|
}
|
|
|
|
UniformCase::~UniformCase (void)
|
|
{
|
|
UniformCase::deinit();
|
|
}
|
|
|
|
void UniformCase::generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, vector<BasicUniformReportRef>& basicUniformReportsDst, const glu::VarType& varType, const char* const varName, const bool isParentActive, int& samplerUnitCounter, Random& rnd) const
|
|
{
|
|
if (varType.isBasicType())
|
|
{
|
|
const bool isActive = isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true);
|
|
const glu::DataType type = varType.getBasicType();
|
|
const VarValue value = m_features & FEATURE_UNIFORMVALUE_ZERO ? generateZeroVarValue(type)
|
|
: glu::isDataTypeSampler(type) ? generateRandomVarValue(type, rnd, samplerUnitCounter++)
|
|
: generateRandomVarValue(varType.getBasicType(), rnd);
|
|
|
|
basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value));
|
|
basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive));
|
|
}
|
|
else if (varType.isArrayType())
|
|
{
|
|
const int size = varType.getArraySize();
|
|
const string arrayRootName = string("") + varName + "[0]";
|
|
vector<bool> isElemActive;
|
|
|
|
for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++)
|
|
{
|
|
const string indexedName = string("") + varName + "[" + de::toString(elemNdx) + "]";
|
|
const bool isCurElemActive = isParentActive &&
|
|
(m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true) &&
|
|
(m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX ? elemNdx == size/2 : true);
|
|
|
|
isElemActive.push_back(isCurElemActive);
|
|
|
|
if (varType.getElementType().isBasicType())
|
|
{
|
|
// \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays.
|
|
const glu::DataType elemBasicType = varType.getElementType().getBasicType();
|
|
const VarValue value = m_features & FEATURE_UNIFORMVALUE_ZERO ? generateZeroVarValue(elemBasicType)
|
|
: glu::isDataTypeSampler(elemBasicType) ? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++)
|
|
: generateRandomVarValue(elemBasicType, rnd);
|
|
|
|
basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size));
|
|
}
|
|
else
|
|
generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd);
|
|
}
|
|
|
|
if (varType.getElementType().isBasicType())
|
|
{
|
|
int minSize;
|
|
for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--);
|
|
|
|
basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(varType.isStructType());
|
|
|
|
const StructType& structType = *varType.getStructPtr();
|
|
|
|
for (int i = 0; i < structType.getNumMembers(); i++)
|
|
{
|
|
const glu::StructMember& member = structType.getMember(i);
|
|
const string memberFullName = string("") + varName + "." + member.getName();
|
|
|
|
generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const
|
|
{
|
|
for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++)
|
|
dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n";
|
|
|
|
for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
|
|
dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n";
|
|
|
|
dst << "\n";
|
|
|
|
{
|
|
static const struct
|
|
{
|
|
dataTypePredicate requiringTypes[2];
|
|
const char* definition;
|
|
} compareFuncs[] =
|
|
{
|
|
{ { glu::isDataTypeFloatOrVec, glu::isDataTypeMatrix }, "mediump float compare_float (mediump float a, mediump float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_VEC2>, dataTypeIsMatrixWithNRows<2> }, "mediump float compare_vec2 (mediump vec2 a, mediump vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_VEC3>, dataTypeIsMatrixWithNRows<3> }, "mediump float compare_vec3 (mediump vec3 a, mediump vec3 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_VEC4>, dataTypeIsMatrixWithNRows<4> }, "mediump float compare_vec4 (mediump vec4 a, mediump vec4 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_MAT2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat2 (mediump mat2 a, mediump mat2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_MAT3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat3 (mediump mat3 a, mediump mat3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }" },
|
|
{ { dataTypeEquals<glu::TYPE_FLOAT_MAT4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat4 (mediump mat4 a, mediump mat4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }" },
|
|
{ { dataTypeEquals<glu::TYPE_INT>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_int (mediump int a, mediump int b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_INT_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec2 (mediump ivec2 a, mediump ivec2 b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_INT_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec3 (mediump ivec3 a, mediump ivec3 b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_INT_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec4 (mediump ivec4 a, mediump ivec4 b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_BOOL>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_BOOL_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_BOOL_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }" },
|
|
{ { dataTypeEquals<glu::TYPE_BOOL_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }" }
|
|
};
|
|
|
|
const bool containsSamplers = !m_uniformCollection->getSamplerTypes().empty();
|
|
|
|
for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++)
|
|
{
|
|
const dataTypePredicate (&typeReq)[2] = compareFuncs[compFuncNdx].requiringTypes;
|
|
const bool containsTypeSampler = containsSamplers && (typeReq[0](glu::TYPE_FLOAT_VEC4) || typeReq[1](glu::TYPE_FLOAT_VEC4));
|
|
|
|
if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1]))
|
|
dst << compareFuncs[compFuncNdx].definition << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const
|
|
{
|
|
if (glu::isDataTypeSampler(uniform.type))
|
|
{
|
|
dst << "compare_vec4("
|
|
<< (uniform.type == glu::TYPE_SAMPLER_2D ? "texture2D" : "textureCube")
|
|
<< "(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))";
|
|
}
|
|
else
|
|
dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name;
|
|
|
|
dst << ", " << shaderVarValueStr(uniform.finalValue) << ")";
|
|
}
|
|
|
|
void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const
|
|
{
|
|
for (int i = 0; i < (int)basicUniforms.size(); i++)
|
|
{
|
|
const BasicUniform& unif = basicUniforms[i];
|
|
|
|
if (unif.isUsedInShader)
|
|
{
|
|
dst << "\t" << variableName << " *= ";
|
|
writeUniformCompareExpr(dst, basicUniforms[i]);
|
|
dst << ";\n";
|
|
}
|
|
else
|
|
dst << "\t// UNUSED: " << basicUniforms[i].name << "\n";
|
|
}
|
|
}
|
|
|
|
string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const
|
|
{
|
|
const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH;
|
|
std::ostringstream result;
|
|
|
|
result << "attribute highp vec4 a_position;\n"
|
|
"varying mediump float v_vtxOut;\n"
|
|
"\n";
|
|
|
|
if (isVertexCase)
|
|
writeUniformDefinitions(result);
|
|
|
|
result << "\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
" v_vtxOut = 1.0;\n";
|
|
|
|
if (isVertexCase)
|
|
writeUniformComparisons(result, basicUniforms, "v_vtxOut");
|
|
|
|
result << "}\n";
|
|
|
|
return result.str();
|
|
}
|
|
|
|
string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const
|
|
{
|
|
const bool isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH;
|
|
std::ostringstream result;
|
|
|
|
result << "varying mediump float v_vtxOut;\n"
|
|
"\n";
|
|
|
|
if (isFragmentCase)
|
|
writeUniformDefinitions(result);
|
|
|
|
result << "\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" mediump float result = v_vtxOut;\n";
|
|
|
|
if (isFragmentCase)
|
|
writeUniformComparisons(result, basicUniforms, "result");
|
|
|
|
result << " gl_FragColor = vec4(result, result, result, 1.0);\n"
|
|
"}\n";
|
|
|
|
return result.str();
|
|
}
|
|
|
|
void UniformCase::setupTexture (const VarValue& value)
|
|
{
|
|
enableLogging(false);
|
|
|
|
const int width = 32;
|
|
const int height = 32;
|
|
const tcu::Vec4 color = vec4FromPtr(&value.val.samplerV.fillColor[0]);
|
|
|
|
if (value.type == glu::TYPE_SAMPLER_2D)
|
|
{
|
|
glu::Texture2D* texture = new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height);
|
|
tcu::Texture2D& refTexture = texture->getRefTexture();
|
|
m_textures2d.push_back(texture);
|
|
|
|
refTexture.allocLevel(0);
|
|
fillWithColor(refTexture.getLevel(0), color);
|
|
|
|
GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
|
|
m_filledTextureUnits.push_back(value.val.samplerV.unit);
|
|
texture->upload();
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
|
}
|
|
else if (value.type == glu::TYPE_SAMPLER_CUBE)
|
|
{
|
|
DE_ASSERT(width == height);
|
|
|
|
glu::TextureCube* texture = new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width);
|
|
tcu::TextureCube& refTexture = texture->getRefTexture();
|
|
m_texturesCube.push_back(texture);
|
|
|
|
for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
|
|
{
|
|
refTexture.allocLevel((tcu::CubeFace)face, 0);
|
|
fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color);
|
|
}
|
|
|
|
GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit));
|
|
m_filledTextureUnits.push_back(value.val.samplerV.unit);
|
|
texture->upload();
|
|
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
|
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
|
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
enableLogging(true);
|
|
}
|
|
|
|
bool UniformCase::getActiveUniforms (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
GLint numActiveUniforms = 0;
|
|
GLint uniformMaxNameLength = 0;
|
|
vector<char> nameBuffer;
|
|
bool success = true;
|
|
|
|
GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORMS, &numActiveUniforms));
|
|
log << TestLog::Message << "// Number of active uniforms reported: " << numActiveUniforms << TestLog::EndMessage;
|
|
GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength));
|
|
log << TestLog::Message << "// Maximum uniform name length reported: " << uniformMaxNameLength << TestLog::EndMessage;
|
|
nameBuffer.resize(uniformMaxNameLength);
|
|
|
|
for (int unifNdx = 0; unifNdx < numActiveUniforms; unifNdx++)
|
|
{
|
|
GLsizei reportedNameLength = 0;
|
|
GLint reportedSize = -1;
|
|
GLenum reportedTypeGL = GL_NONE;
|
|
|
|
GLU_CHECK_CALL(glGetActiveUniform(programGL, (GLuint)unifNdx, (GLsizei)uniformMaxNameLength, &reportedNameLength, &reportedSize, &reportedTypeGL, &nameBuffer[0]));
|
|
|
|
const glu::DataType reportedType = glu::getDataTypeFromGLType(reportedTypeGL);
|
|
const string reportedNameStr (&nameBuffer[0]);
|
|
|
|
TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type");
|
|
|
|
log << TestLog::Message << "// Got name = " << reportedNameStr << ", name length = " << reportedNameLength << ", size = " << reportedSize << ", type = " << glu::getDataTypeName(reportedType) << TestLog::EndMessage;
|
|
|
|
if ((GLsizei)reportedNameStr.length() != reportedNameLength)
|
|
{
|
|
log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reportedNameStr.length() << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
|
|
if (!deStringBeginsWith(reportedNameStr.c_str(), "gl_")) // Ignore built-in uniforms.
|
|
{
|
|
int referenceNdx;
|
|
for (referenceNdx = 0; referenceNdx < (int)basicUniformReportsRef.size(); referenceNdx++)
|
|
{
|
|
if (basicUniformReportsRef[referenceNdx].name == reportedNameStr)
|
|
break;
|
|
}
|
|
|
|
if (referenceNdx >= (int)basicUniformReportsRef.size())
|
|
{
|
|
log << TestLog::Message << "// FAILURE: invalid non-built-in uniform name reported" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
else
|
|
{
|
|
const BasicUniformReportRef& reference = basicUniformReportsRef[referenceNdx];
|
|
|
|
DE_ASSERT(reference.type != glu::TYPE_LAST);
|
|
DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader));
|
|
DE_ASSERT(reference.minSize <= reference.maxSize);
|
|
|
|
if (BasicUniformReportGL::findWithName(basicUniformReportsDst, reportedNameStr.c_str()) != basicUniformReportsDst.end())
|
|
{
|
|
log << TestLog::Message << "// FAILURE: same uniform name reported twice" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
|
|
basicUniformReportsDst.push_back(BasicUniformReportGL(reportedNameStr.c_str(), reportedNameLength, reportedSize, reportedType, unifNdx));
|
|
|
|
if (reportedType != reference.type)
|
|
{
|
|
log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
if (reportedSize < reference.minSize || reportedSize > reference.maxSize)
|
|
{
|
|
log << TestLog::Message
|
|
<< "// FAILURE: wrong size reported, should be "
|
|
<< (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]")
|
|
<< TestLog::EndMessage;
|
|
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < (int)basicUniformReportsRef.size(); i++)
|
|
{
|
|
const BasicUniformReportRef& expected = basicUniformReportsRef[i];
|
|
if (expected.isUsedInShader && BasicUniformReportGL::findWithName(basicUniformReportsDst, expected.name.c_str()) == basicUniformReportsDst.end())
|
|
{
|
|
log << TestLog::Message << "// FAILURE: uniform with name " << expected.name << " was not reported by GL" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
bool success = true;
|
|
|
|
for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
|
|
{
|
|
const BasicUniform& uniform = basicUniforms[unifNdx];
|
|
const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
|
|
const int location = glGetUniformLocation(programGL, queryName.c_str());
|
|
const int size = glu::getDataTypeScalarSize(uniform.type);
|
|
VarValue value;
|
|
|
|
deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage.
|
|
|
|
if (location == -1)
|
|
{
|
|
value.type = glu::TYPE_INVALID;
|
|
valuesDst.push_back(value);
|
|
if (uniform.isUsedInShader)
|
|
{
|
|
log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
value.type = uniform.type;
|
|
|
|
DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0]));
|
|
DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0]));
|
|
|
|
if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
|
|
GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
|
|
else if (glu::isDataTypeIntOrIVec(uniform.type))
|
|
GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
|
|
else if (glu::isDataTypeBoolOrBVec(uniform.type))
|
|
{
|
|
if (m_features & FEATURE_BOOLEANAPITYPE_INT)
|
|
{
|
|
GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0]));
|
|
for (int i = 0; i < size; i++)
|
|
value.val.boolV[i] = value.val.intV[i] != 0;
|
|
}
|
|
else // Default: use float.
|
|
{
|
|
GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0]));
|
|
for (int i = 0; i < size; i++)
|
|
value.val.boolV[i] = value.val.floatV[i] != 0.0f;
|
|
}
|
|
}
|
|
else if (glu::isDataTypeSampler(uniform.type))
|
|
{
|
|
GLint unit = -1;
|
|
GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit));
|
|
value.val.samplerV.unit = unit;
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
valuesDst.push_back(value);
|
|
|
|
log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool UniformCase::checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
bool success = true;
|
|
|
|
DE_ASSERT(values.size() == basicUniforms.size());
|
|
|
|
for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
|
|
{
|
|
const BasicUniform& uniform = basicUniforms[unifNdx];
|
|
const VarValue& unifValue = values[unifNdx];
|
|
const int valSize = glu::getDataTypeScalarSize(uniform.type);
|
|
|
|
log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
|
|
|
|
if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
|
|
continue;
|
|
|
|
#define CHECK_UNIFORM(VAR_VALUE_MEMBER, ZERO) \
|
|
do \
|
|
{ \
|
|
for (int i = 0; i < valSize; i++) \
|
|
{ \
|
|
if (unifValue.val.VAR_VALUE_MEMBER[i] != (ZERO)) \
|
|
{ \
|
|
log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage; \
|
|
success = false; \
|
|
} \
|
|
} \
|
|
} while (false)
|
|
|
|
if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type))
|
|
CHECK_UNIFORM(floatV, 0.0f);
|
|
else if (glu::isDataTypeIntOrIVec(uniform.type))
|
|
CHECK_UNIFORM(intV, 0);
|
|
else if (glu::isDataTypeBoolOrBVec(uniform.type))
|
|
CHECK_UNIFORM(boolV, false);
|
|
else if (glu::isDataTypeSampler(uniform.type))
|
|
{
|
|
if (unifValue.val.samplerV.unit != 0)
|
|
{
|
|
log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
#undef CHECK_UNIFORM
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
const glu::DataType boolApiType = m_features & FEATURE_BOOLEANAPITYPE_INT ? glu::TYPE_INT
|
|
: glu::TYPE_FLOAT;
|
|
|
|
for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
|
|
{
|
|
const BasicUniform& uniform = basicUniforms[unifNdx];
|
|
const bool isArrayMember = uniform.elemNdx >= 0;
|
|
const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name;
|
|
const int numValuesToAssign = !isArrayMember ? 1
|
|
: m_features & FEATURE_ARRAYASSIGN_FULL ? (uniform.elemNdx == 0 ? uniform.rootSize : 0)
|
|
: m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO ? (uniform.elemNdx % 2 == 0 ? 2 : 0)
|
|
: /* Default: assign array elements separately */ 1;
|
|
|
|
DE_ASSERT(numValuesToAssign >= 0);
|
|
DE_ASSERT(numValuesToAssign == 1 || isArrayMember);
|
|
|
|
if (numValuesToAssign == 0)
|
|
{
|
|
log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glUniform*v() call to the same array" << TestLog::EndMessage;
|
|
continue;
|
|
}
|
|
|
|
const int location = glGetUniformLocation(programGL, queryName.c_str());
|
|
const int typeSize = glu::getDataTypeScalarSize(uniform.type);
|
|
const bool assignByValue = m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1;
|
|
vector<VarValue> valuesToAssign;
|
|
|
|
for (int i = 0; i < numValuesToAssign; i++)
|
|
{
|
|
const string curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name;
|
|
VarValue unifValue;
|
|
|
|
if (isArrayMember)
|
|
{
|
|
const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str());
|
|
if (elemUnif == basicUniforms.end())
|
|
continue;
|
|
unifValue = elemUnif->finalValue;
|
|
}
|
|
else
|
|
unifValue = uniform.finalValue;
|
|
|
|
const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type) ? getRandomBoolRepresentation(unifValue, boolApiType, rnd)
|
|
: glu::isDataTypeSampler(unifValue.type) ? getSamplerUnitValue(unifValue)
|
|
: unifValue;
|
|
|
|
valuesToAssign.push_back(apiValue);
|
|
|
|
if (glu::isDataTypeBoolOrBVec(uniform.type))
|
|
log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage;
|
|
else if (glu::isDataTypeSampler(uniform.type))
|
|
log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage;
|
|
}
|
|
|
|
DE_ASSERT(!valuesToAssign.empty());
|
|
|
|
if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type))
|
|
{
|
|
if (assignByValue)
|
|
{
|
|
const float* const ptr = &valuesToAssign[0].val.floatV[0];
|
|
|
|
switch (typeSize)
|
|
{
|
|
case 1: GLU_CHECK_CALL(glUniform1f(location, ptr[0])); break;
|
|
case 2: GLU_CHECK_CALL(glUniform2f(location, ptr[0], ptr[1])); break;
|
|
case 3: GLU_CHECK_CALL(glUniform3f(location, ptr[0], ptr[1], ptr[2])); break;
|
|
case 4: GLU_CHECK_CALL(glUniform4f(location, ptr[0], ptr[1], ptr[2], ptr[3])); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector<float> buffer(valuesToAssign.size() * typeSize);
|
|
for (int i = 0; i < (int)buffer.size(); i++)
|
|
buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
|
|
|
|
DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0]));
|
|
switch (typeSize)
|
|
{
|
|
case 1: GLU_CHECK_CALL(glUniform1fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 2: GLU_CHECK_CALL(glUniform2fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 3: GLU_CHECK_CALL(glUniform3fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 4: GLU_CHECK_CALL(glUniform4fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
}
|
|
else if (glu::isDataTypeMatrix(valuesToAssign[0].type))
|
|
{
|
|
DE_ASSERT(!assignByValue);
|
|
|
|
vector<float> buffer(valuesToAssign.size() * typeSize);
|
|
for (int i = 0; i < (int)buffer.size(); i++)
|
|
buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize];
|
|
|
|
switch (uniform.type)
|
|
{
|
|
case glu::TYPE_FLOAT_MAT2: GLU_CHECK_CALL(glUniformMatrix2fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
|
|
case glu::TYPE_FLOAT_MAT3: GLU_CHECK_CALL(glUniformMatrix3fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
|
|
case glu::TYPE_FLOAT_MAT4: GLU_CHECK_CALL(glUniformMatrix4fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type))
|
|
{
|
|
if (assignByValue)
|
|
{
|
|
const deInt32* const ptr = &valuesToAssign[0].val.intV[0];
|
|
|
|
switch (typeSize)
|
|
{
|
|
case 1: GLU_CHECK_CALL(glUniform1i(location, ptr[0])); break;
|
|
case 2: GLU_CHECK_CALL(glUniform2i(location, ptr[0], ptr[1])); break;
|
|
case 3: GLU_CHECK_CALL(glUniform3i(location, ptr[0], ptr[1], ptr[2])); break;
|
|
case 4: GLU_CHECK_CALL(glUniform4i(location, ptr[0], ptr[1], ptr[2], ptr[3])); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector<deInt32> buffer(valuesToAssign.size() * typeSize);
|
|
for (int i = 0; i < (int)buffer.size(); i++)
|
|
buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize];
|
|
|
|
DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0]));
|
|
switch (typeSize)
|
|
{
|
|
case 1: GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 2: GLU_CHECK_CALL(glUniform2iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 3: GLU_CHECK_CALL(glUniform3iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
case 4: GLU_CHECK_CALL(glUniform4iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
}
|
|
else if (glu::isDataTypeSampler(valuesToAssign[0].type))
|
|
{
|
|
if (assignByValue)
|
|
GLU_CHECK_CALL(glUniform1i(location, uniform.finalValue.val.samplerV.unit));
|
|
else
|
|
{
|
|
const GLint unit = uniform.finalValue.val.samplerV.unit;
|
|
GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &unit));
|
|
}
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
bool success = true;
|
|
|
|
for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++)
|
|
{
|
|
const BasicUniform& uniform = basicUniforms[unifNdx];
|
|
const VarValue& unifValue = values[unifNdx];
|
|
|
|
log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage;
|
|
|
|
if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1.
|
|
continue;
|
|
|
|
if (!apiVarValueEquals(unifValue, uniform.finalValue))
|
|
{
|
|
log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glUniform*()" << TestLog::EndMessage;
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
const tcu::RenderTarget& renderTarget = m_context.getRenderTarget();
|
|
const int viewportW = de::min(renderTarget.getWidth(), MAX_RENDER_WIDTH);
|
|
const int viewportH = de::min(renderTarget.getHeight(), MAX_RENDER_HEIGHT);
|
|
const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW);
|
|
const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH);
|
|
tcu::Surface renderedImg (viewportW, viewportH);
|
|
|
|
// Assert that no two samplers of different types have the same texture unit - this is an error in GL.
|
|
for (int i = 0; i < (int)basicUniforms.size(); i++)
|
|
{
|
|
if (glu::isDataTypeSampler(basicUniforms[i].type))
|
|
{
|
|
for (int j = 0; j < i; j++)
|
|
{
|
|
if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type)
|
|
DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < (int)basicUniforms.size(); i++)
|
|
{
|
|
if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end())
|
|
{
|
|
log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage;
|
|
setupTexture(basicUniforms[i].finalValue);
|
|
}
|
|
}
|
|
|
|
GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH));
|
|
|
|
{
|
|
static const float position[] =
|
|
{
|
|
-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
|
|
};
|
|
static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
|
|
|
|
const int posLoc = glGetAttribLocation(program.getProgram(), "a_position");
|
|
|
|
glEnableVertexAttribArray(posLoc);
|
|
glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
|
|
|
|
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]));
|
|
}
|
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
|
|
|
|
int numFailedPixels = 0;
|
|
for (int y = 0; y < renderedImg.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < renderedImg.getWidth(); x++)
|
|
{
|
|
if (renderedImg.getPixel(x, y) != tcu::RGBA::white())
|
|
numFailedPixels += 1;
|
|
}
|
|
}
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << TestLog::Image("RenderedImage", "Rendered image", renderedImg);
|
|
log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-white pixels" << TestLog::EndMessage;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
log << TestLog::Message << "Success: got all-white pixels (all uniforms have correct values)" << TestLog::EndMessage;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
UniformCase::IterateResult UniformCase::iterate (void)
|
|
{
|
|
Random rnd (deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed());
|
|
TestLog& log = m_testCtx.getLog();
|
|
vector<BasicUniform> basicUniforms;
|
|
vector<BasicUniformReportRef> basicUniformReportsRef;
|
|
|
|
{
|
|
int samplerUnitCounter = 0;
|
|
for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++)
|
|
generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd);
|
|
}
|
|
|
|
const string vertexSource = generateVertexSource(basicUniforms);
|
|
const string fragmentSource = generateFragmentSource(basicUniforms);
|
|
const ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource));
|
|
|
|
log << program;
|
|
|
|
if (!program.isOk())
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
|
|
return STOP;
|
|
}
|
|
|
|
GLU_CHECK_CALL(glUseProgram(program.getProgram()));
|
|
|
|
const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd);
|
|
m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
|
|
success ? "Passed" : "Failed");
|
|
|
|
return STOP;
|
|
}
|
|
|
|
class UniformInfoQueryCase : public UniformCase
|
|
{
|
|
public:
|
|
UniformInfoQueryCase (Context& context, const char* name, const char* description, CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 additionalFeatures = 0);
|
|
bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
|
|
};
|
|
|
|
UniformInfoQueryCase::UniformInfoQueryCase (Context& context, const char* const name, const char* const description, const CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 additionalFeatures)
|
|
: UniformCase (context, name, description, shaderType, uniformCollection, additionalFeatures)
|
|
{
|
|
}
|
|
|
|
bool UniformInfoQueryCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
|
|
{
|
|
DE_UNREF(basicUniforms);
|
|
DE_UNREF(rnd);
|
|
|
|
const deUint32 programGL = program.getProgram();
|
|
TestLog& log = m_testCtx.getLog();
|
|
vector<BasicUniformReportGL> basicUniformReportsUniform;
|
|
|
|
const ScopedLogSection section(log, "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
|
|
const bool success = getActiveUniforms(basicUniformReportsUniform, basicUniformReportsRef, programGL);
|
|
|
|
if (!success)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
class UniformValueCase : public UniformCase
|
|
{
|
|
public:
|
|
enum ValueToCheck
|
|
{
|
|
VALUETOCHECK_INITIAL = 0, //!< Verify the initial values of the uniforms (i.e. check that they're zero).
|
|
VALUETOCHECK_ASSIGNED, //!< Assign values to uniforms with glUniform*(), and check those.
|
|
|
|
VALUETOCHECK_LAST
|
|
};
|
|
enum CheckMethod
|
|
{
|
|
CHECKMETHOD_GET_UNIFORM = 0, //!< Check values with glGetUniform*().
|
|
CHECKMETHOD_RENDER, //!< Check values by rendering with the value-checking shader.
|
|
|
|
CHECKMETHOD_LAST
|
|
};
|
|
enum AssignMethod
|
|
{
|
|
ASSIGNMETHOD_POINTER = 0,
|
|
ASSIGNMETHOD_VALUE,
|
|
|
|
ASSIGNMETHOD_LAST
|
|
};
|
|
|
|
UniformValueCase (Context& context,
|
|
const char* name,
|
|
const char* description,
|
|
CaseShaderType shaderType,
|
|
const SharedPtr<const UniformCollection>& uniformCollection,
|
|
ValueToCheck valueToCheck,
|
|
CheckMethod checkMethod,
|
|
AssignMethod assignMethod,
|
|
deUint32 additionalFeatures = 0);
|
|
|
|
bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
|
|
|
|
static const char* getValueToCheckName (ValueToCheck valueToCheck);
|
|
static const char* getValueToCheckDescription (ValueToCheck valueToCheck);
|
|
static const char* getCheckMethodName (CheckMethod checkMethod);
|
|
static const char* getCheckMethodDescription (CheckMethod checkMethod);
|
|
static const char* getAssignMethodName (AssignMethod checkMethod);
|
|
static const char* getAssignMethodDescription (AssignMethod checkMethod);
|
|
|
|
private:
|
|
const ValueToCheck m_valueToCheck;
|
|
const CheckMethod m_checkMethod;
|
|
};
|
|
|
|
const char* UniformValueCase::getValueToCheckName (const ValueToCheck valueToCheck)
|
|
{
|
|
switch (valueToCheck)
|
|
{
|
|
case VALUETOCHECK_INITIAL: return "initial";
|
|
case VALUETOCHECK_ASSIGNED: return "assigned";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
const char* UniformValueCase::getValueToCheckDescription (const ValueToCheck valueToCheck)
|
|
{
|
|
switch (valueToCheck)
|
|
{
|
|
case VALUETOCHECK_INITIAL: return "Check initial uniform values (zeros)";
|
|
case VALUETOCHECK_ASSIGNED: return "Check assigned uniform values";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
const char* UniformValueCase::getCheckMethodName (const CheckMethod checkMethod)
|
|
{
|
|
switch (checkMethod)
|
|
{
|
|
case CHECKMETHOD_GET_UNIFORM: return "get_uniform";
|
|
case CHECKMETHOD_RENDER: return "render";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
const char* UniformValueCase::getCheckMethodDescription (const CheckMethod checkMethod)
|
|
{
|
|
switch (checkMethod)
|
|
{
|
|
case CHECKMETHOD_GET_UNIFORM: return "Verify values with glGetUniform*()";
|
|
case CHECKMETHOD_RENDER: return "Verify values by rendering";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
const char* UniformValueCase::getAssignMethodName (const AssignMethod assignMethod)
|
|
{
|
|
switch (assignMethod)
|
|
{
|
|
case ASSIGNMETHOD_POINTER: return "by_pointer";
|
|
case ASSIGNMETHOD_VALUE: return "by_value";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
const char* UniformValueCase::getAssignMethodDescription (const AssignMethod assignMethod)
|
|
{
|
|
switch (assignMethod)
|
|
{
|
|
case ASSIGNMETHOD_POINTER: return "Assign values by-pointer";
|
|
case ASSIGNMETHOD_VALUE: return "Assign values by-value";
|
|
default: DE_ASSERT(false); return DE_NULL;
|
|
}
|
|
}
|
|
|
|
UniformValueCase::UniformValueCase (Context& context,
|
|
const char* const name,
|
|
const char* const description,
|
|
const CaseShaderType shaderType,
|
|
const SharedPtr<const UniformCollection>& uniformCollection,
|
|
const ValueToCheck valueToCheck,
|
|
const CheckMethod checkMethod,
|
|
const AssignMethod assignMethod,
|
|
const deUint32 additionalFeatures)
|
|
: UniformCase (context, name, description, shaderType, uniformCollection,
|
|
(valueToCheck == VALUETOCHECK_INITIAL ? FEATURE_UNIFORMVALUE_ZERO : 0) | (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures)
|
|
, m_valueToCheck (valueToCheck)
|
|
, m_checkMethod (checkMethod)
|
|
{
|
|
DE_ASSERT(!(assignMethod == ASSIGNMETHOD_LAST && valueToCheck == VALUETOCHECK_ASSIGNED));
|
|
}
|
|
|
|
bool UniformValueCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
|
|
{
|
|
DE_UNREF(basicUniformReportsRef);
|
|
|
|
const deUint32 programGL = program.getProgram();
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
|
|
{
|
|
const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
|
|
assignUniforms(basicUniforms, programGL, rnd);
|
|
}
|
|
else
|
|
DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
|
|
|
|
if (m_checkMethod == CHECKMETHOD_GET_UNIFORM)
|
|
{
|
|
vector<VarValue> values;
|
|
|
|
{
|
|
const ScopedLogSection section(log, "GetUniforms", "Uniform value query");
|
|
const bool success = getUniforms(values, basicUniforms, program.getProgram());
|
|
|
|
if (!success)
|
|
return false;
|
|
}
|
|
|
|
if (m_valueToCheck == VALUETOCHECK_ASSIGNED)
|
|
{
|
|
const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values");
|
|
const bool success = compareUniformValues(values, basicUniforms);
|
|
|
|
if (!success)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL);
|
|
const ScopedLogSection section(log, "ValueCheck", "Verify that the uniforms have correct initial values (zeros)");
|
|
const bool success = checkUniformDefaultValues(values, basicUniforms);
|
|
|
|
if (!success)
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER);
|
|
|
|
const ScopedLogSection section(log, "RenderTest", "Render test");
|
|
const bool success = renderTest(basicUniforms, program, rnd);
|
|
|
|
if (!success)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
class RandomUniformCase : public UniformCase
|
|
{
|
|
public:
|
|
RandomUniformCase (Context& m_context, const char* name, const char* description, deUint32 seed);
|
|
|
|
bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd);
|
|
};
|
|
|
|
RandomUniformCase::RandomUniformCase (Context& context, const char* const name, const char* const description, const deUint32 seed)
|
|
: UniformCase (context, name, description, seed ^ (deUint32)context.getTestContext().getCommandLine().getBaseSeed())
|
|
{
|
|
}
|
|
|
|
bool RandomUniformCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd)
|
|
{
|
|
// \note Different sampler types may not be bound to same unit when rendering.
|
|
const bool renderingPossible = (m_features & FEATURE_UNIFORMVALUE_ZERO) == 0 || !m_uniformCollection->containsSeveralSamplerTypes();
|
|
|
|
bool performGetActiveUniforms = rnd.getBool();
|
|
const bool performGetUniforms = rnd.getBool();
|
|
const bool performCheckUniformDefaultValues = performGetUniforms && rnd.getBool();
|
|
const bool performAssignUniforms = rnd.getBool();
|
|
const bool performCompareUniformValues = performGetUniforms && performAssignUniforms && rnd.getBool();
|
|
const bool performRenderTest = renderingPossible && performAssignUniforms && rnd.getBool();
|
|
const deUint32 programGL = program.getProgram();
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
if (!(performGetActiveUniforms || performGetUniforms || performCheckUniformDefaultValues || performAssignUniforms || performCompareUniformValues || performRenderTest))
|
|
performGetActiveUniforms = true; // Do something at least.
|
|
|
|
#define PERFORM_AND_CHECK(CALL, SECTION_NAME, SECTION_DESCRIPTION) \
|
|
do \
|
|
{ \
|
|
const ScopedLogSection section(log, (SECTION_NAME), (SECTION_DESCRIPTION)); \
|
|
const bool success = (CALL); \
|
|
if (!success) \
|
|
return false; \
|
|
} while (false)
|
|
|
|
if (performGetActiveUniforms)
|
|
{
|
|
vector<BasicUniformReportGL> reportsUniform;
|
|
PERFORM_AND_CHECK(getActiveUniforms(reportsUniform, basicUniformReportsRef, programGL), "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()");
|
|
}
|
|
|
|
{
|
|
vector<VarValue> uniformDefaultValues;
|
|
|
|
if (performGetUniforms)
|
|
PERFORM_AND_CHECK(getUniforms(uniformDefaultValues, basicUniforms, programGL), "GetUniformDefaults", "Uniform default value query");
|
|
if (performCheckUniformDefaultValues)
|
|
PERFORM_AND_CHECK(checkUniformDefaultValues(uniformDefaultValues, basicUniforms), "DefaultValueCheck", "Verify that the uniforms have correct initial values (zeros)");
|
|
}
|
|
|
|
{
|
|
vector<VarValue> uniformValues;
|
|
|
|
if (performAssignUniforms)
|
|
{
|
|
const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments");
|
|
assignUniforms(basicUniforms, programGL, rnd);
|
|
}
|
|
if (performCompareUniformValues)
|
|
{
|
|
PERFORM_AND_CHECK(getUniforms(uniformValues, basicUniforms, programGL), "GetUniforms", "Uniform value query");
|
|
PERFORM_AND_CHECK(compareUniformValues(uniformValues, basicUniforms), "ValueCheck", "Verify that the reported values match the assigned values");
|
|
}
|
|
}
|
|
|
|
if (performRenderTest)
|
|
PERFORM_AND_CHECK(renderTest(basicUniforms, program, rnd), "RenderTest", "Render test");
|
|
|
|
#undef PERFORM_AND_CHECK
|
|
|
|
return true;
|
|
}
|
|
|
|
UniformApiTests::UniformApiTests (Context& context)
|
|
: TestCaseGroup(context, "uniform_api", "Uniform API Tests")
|
|
{
|
|
}
|
|
|
|
UniformApiTests::~UniformApiTests (void)
|
|
{
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
// \note Although this is only used in UniformApiTest::init, it needs to be defined here as it's used as a template argument.
|
|
struct UniformCollectionCase
|
|
{
|
|
string namePrefix;
|
|
SharedPtr<const UniformCollection> uniformCollection;
|
|
|
|
UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_)
|
|
: namePrefix (name ? name + string("_") : "")
|
|
, uniformCollection (uniformCollection_)
|
|
{
|
|
}
|
|
};
|
|
|
|
} // anonymous
|
|
|
|
void UniformApiTests::init (void)
|
|
{
|
|
// Generate sets of UniformCollections that are used by several cases.
|
|
|
|
enum
|
|
{
|
|
UNIFORMCOLLECTIONS_BASIC = 0,
|
|
UNIFORMCOLLECTIONS_BASIC_ARRAY,
|
|
UNIFORMCOLLECTIONS_BASIC_STRUCT,
|
|
UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY,
|
|
UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT,
|
|
UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS,
|
|
UNIFORMCOLLECTIONS_MULTIPLE_BASIC,
|
|
UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY,
|
|
UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS,
|
|
|
|
UNIFORMCOLLECTIONS_LAST
|
|
};
|
|
|
|
struct UniformCollectionGroup
|
|
{
|
|
string name;
|
|
vector<UniformCollectionCase> cases;
|
|
} defaultUniformCollections[UNIFORMCOLLECTIONS_LAST];
|
|
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name = "basic";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name = "basic_array";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name = "basic_struct";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name = "struct_in_array";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name = "array_in_struct";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name = "nested_structs_arrays";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name = "multiple_basic";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name = "multiple_basic_array";
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name = "multiple_nested_structs_arrays";
|
|
|
|
for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++)
|
|
{
|
|
const glu::DataType dataType = s_testDataTypes[dataTypeNdx];
|
|
const char* const typeName = glu::getDataTypeName(dataType);
|
|
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType)));
|
|
|
|
if (glu::isDataTypeScalar(dataType) ||
|
|
(glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4) ||
|
|
dataType == glu::TYPE_FLOAT_MAT4 ||
|
|
dataType == glu::TYPE_SAMPLER_2D)
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType)));
|
|
|
|
if (glu::isDataTypeScalar(dataType) ||
|
|
dataType == glu::TYPE_FLOAT_MAT4 ||
|
|
dataType == glu::TYPE_SAMPLER_2D)
|
|
{
|
|
const glu::DataType secondDataType = glu::isDataTypeScalar(dataType) ? glu::getDataTypeVector(dataType, 4)
|
|
: dataType == glu::TYPE_FLOAT_MAT4 ? glu::TYPE_FLOAT_MAT2
|
|
: dataType == glu::TYPE_SAMPLER_2D ? glu::TYPE_SAMPLER_CUBE
|
|
: glu::TYPE_LAST;
|
|
DE_ASSERT(secondDataType != glu::TYPE_LAST);
|
|
const char* const secondTypeName = glu::getDataTypeName(secondDataType);
|
|
const string name = string("") + typeName + "_" + secondTypeName;
|
|
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false)));
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true)));
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false)));
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType)));
|
|
}
|
|
}
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic()));
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray()));
|
|
defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs()));
|
|
|
|
// Info-query cases (check info returned by e.g. glGetActiveUniforms()).
|
|
|
|
{
|
|
TestCaseGroup* const infoQueryGroup = new TestCaseGroup(m_context, "info_query", "Test glGetActiveUniform()");
|
|
addChild(infoQueryGroup);
|
|
|
|
for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
|
|
{
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx];
|
|
TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
|
|
infoQueryGroup->addChild(collectionTestGroup);
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = collectionCase.namePrefix + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
|
|
collectionTestGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Info-querying cases when unused uniforms are present.
|
|
|
|
{
|
|
TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
|
|
infoQueryGroup->addChild(unusedUniformsGroup);
|
|
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
const string collName = collectionCase.namePrefix;
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
unusedUniformsGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
|
|
UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER | UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cases testing uniform values.
|
|
|
|
{
|
|
TestCaseGroup* const valueGroup = new TestCaseGroup(m_context, "value", "Uniform value tests");
|
|
addChild(valueGroup);
|
|
|
|
// Cases checking uniforms' initial values (all must be zeros), with glGetUniform*() or by rendering.
|
|
|
|
{
|
|
TestCaseGroup* const initialValuesGroup = new TestCaseGroup(m_context,
|
|
UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_INITIAL),
|
|
UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_INITIAL));
|
|
valueGroup->addChild(initialValuesGroup);
|
|
|
|
for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
|
|
{
|
|
const UniformValueCase::CheckMethod checkMethod = (UniformValueCase::CheckMethod)checkMethodI;
|
|
TestCaseGroup* const checkMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
|
|
initialValuesGroup->addChild(checkMethodGroup);
|
|
|
|
for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
|
|
{
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx];
|
|
TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
|
|
checkMethodGroup->addChild(collectionTestGroup);
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
const string collName = collectionCase.namePrefix;
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
const bool containsBooleans = uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
|
|
const bool varyBoolApiType = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
|
|
(collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
|
|
const int numBoolVariations = varyBoolApiType ? 2 : 1;
|
|
|
|
if (checkMethod == UniformValueCase::CHECKMETHOD_RENDER && uniformCollection->containsSeveralSamplerTypes())
|
|
continue; // \note Samplers' initial API values (i.e. their texture units) are 0, and no two samplers of different types shall have same unit when rendering.
|
|
|
|
for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
|
|
{
|
|
const deUint32 booleanTypeFeat = booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
|
|
: 0;
|
|
const char* const booleanTypeName = booleanTypeI == 1 ? "int"
|
|
: "float";
|
|
const string nameWithApiType = varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = nameWithApiType + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
|
|
UniformValueCase::VALUETOCHECK_INITIAL, checkMethod, UniformValueCase::ASSIGNMETHOD_LAST, booleanTypeFeat));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cases that first assign values to each uniform, then check the values with glGetUniform*() or by rendering.
|
|
|
|
{
|
|
TestCaseGroup* const assignedValuesGroup = new TestCaseGroup(m_context,
|
|
UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_ASSIGNED),
|
|
UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_ASSIGNED));
|
|
valueGroup->addChild(assignedValuesGroup);
|
|
|
|
for (int assignMethodI = 0; assignMethodI < (int)UniformValueCase::ASSIGNMETHOD_LAST; assignMethodI++)
|
|
{
|
|
const UniformValueCase::AssignMethod assignMethod = (UniformValueCase::AssignMethod)assignMethodI;
|
|
TestCaseGroup* const assignMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getAssignMethodName(assignMethod), UniformValueCase::getAssignMethodDescription(assignMethod));
|
|
assignedValuesGroup->addChild(assignMethodGroup);
|
|
|
|
for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++)
|
|
{
|
|
const UniformValueCase::CheckMethod checkMethod = (UniformValueCase::CheckMethod)checkMethodI;
|
|
TestCaseGroup* const checkMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod));
|
|
assignMethodGroup->addChild(checkMethodGroup);
|
|
|
|
for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++)
|
|
{
|
|
const int numArrayFirstElemNameCases = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1;
|
|
|
|
for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++)
|
|
{
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx];
|
|
const string collectionGroupName = collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets");
|
|
TestCaseGroup* collectionTestGroup = DE_NULL;
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
const string collName = collectionCase.namePrefix;
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
const bool containsBooleans = uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec);
|
|
const bool varyBoolApiType = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans &&
|
|
(collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY);
|
|
const int numBoolVariations = varyBoolApiType ? 2 : 1;
|
|
const bool containsMatrices = uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix);
|
|
|
|
if (containsMatrices && assignMethod != UniformValueCase::ASSIGNMETHOD_POINTER)
|
|
continue;
|
|
|
|
for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++)
|
|
{
|
|
const deUint32 booleanTypeFeat = booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT
|
|
: 0;
|
|
const char* const booleanTypeName = booleanTypeI == 1 ? "int"
|
|
: "float";
|
|
const string nameWithBoolType = varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName;
|
|
const string nameWithMatrixType = nameWithBoolType;
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
const deUint32 arrayFirstElemNameNoIndexFeat = referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX;
|
|
|
|
// skip empty groups by creating groups on demand
|
|
if (!collectionTestGroup)
|
|
{
|
|
collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), "");
|
|
checkMethodGroup->addChild(collectionTestGroup);
|
|
}
|
|
|
|
collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
|
|
UniformValueCase::VALUETOCHECK_ASSIGNED, checkMethod, assignMethod,
|
|
booleanTypeFeat | arrayFirstElemNameNoIndexFeat));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cases assign multiple basic-array elements with one glUniform*v() (i.e. the count parameter is bigger than 1).
|
|
|
|
{
|
|
static const struct
|
|
{
|
|
UniformCase::Feature arrayAssignMode;
|
|
const char* name;
|
|
const char* description;
|
|
} arrayAssignGroups[] =
|
|
{
|
|
{ UniformCase::FEATURE_ARRAYASSIGN_FULL, "basic_array_assign_full", "Assign entire basic-type arrays per glUniform*v() call" },
|
|
{ UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO, "basic_array_assign_partial", "Assign two elements of a basic-type array per glUniform*v() call" }
|
|
};
|
|
|
|
for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++)
|
|
{
|
|
UniformCase::Feature arrayAssignMode = arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode;
|
|
const char* const groupName = arrayAssignGroups[arrayAssignGroupNdx].name;
|
|
const char* const groupDesc = arrayAssignGroups[arrayAssignGroupNdx].description;
|
|
|
|
TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc);
|
|
assignedValuesGroup->addChild(curArrayAssignGroup);
|
|
|
|
static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY };
|
|
|
|
for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++)
|
|
{
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]];
|
|
TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), "");
|
|
curArrayAssignGroup->addChild(collectionTestGroup);
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
const string collName = collectionCase.namePrefix;
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
|
|
UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
|
|
arrayAssignMode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Value checking cases when unused uniforms are present.
|
|
|
|
{
|
|
TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms");
|
|
assignedValuesGroup->addChild(unusedUniformsGroup);
|
|
|
|
const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT];
|
|
|
|
for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++)
|
|
{
|
|
const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx];
|
|
const string collName = collectionCase.namePrefix;
|
|
const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection;
|
|
|
|
for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++)
|
|
{
|
|
const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType);
|
|
unusedUniformsGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection,
|
|
UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER,
|
|
UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Random cases.
|
|
|
|
{
|
|
const int numRandomCases = 100;
|
|
TestCaseGroup* const randomGroup = new TestCaseGroup(m_context, "random", "Random cases");
|
|
addChild(randomGroup);
|
|
|
|
for (int ndx = 0; ndx < numRandomCases; ndx++)
|
|
randomGroup->addChild(new RandomUniformCase(m_context, de::toString(ndx).c_str(), "", (deUint32)ndx));
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles2
|
|
} // deqp
|