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.
1080 lines
36 KiB
1080 lines
36 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 3.1 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 Explicit uniform location tests
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31fUniformLocationTests.hpp"
|
|
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuTextureUtil.hpp"
|
|
#include "tcuVectorUtil.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
|
|
#include "glsShaderLibrary.hpp"
|
|
#include "glsTextureTestUtil.hpp"
|
|
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluTexture.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "gluVarType.hpp"
|
|
#include "gluVarTypeUtil.hpp"
|
|
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "sglrContextUtil.hpp"
|
|
|
|
#include "deStringUtil.hpp"
|
|
#include "deUniquePtr.hpp"
|
|
#include "deString.h"
|
|
#include "deRandom.hpp"
|
|
#include "deInt32.h"
|
|
|
|
#include <set>
|
|
#include <map>
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles31
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace
|
|
{
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
using std::map;
|
|
using de::UniquePtr;
|
|
using glu::VarType;
|
|
|
|
struct UniformInfo
|
|
{
|
|
enum ShaderStage
|
|
{
|
|
SHADERSTAGE_NONE = 0,
|
|
SHADERSTAGE_VERTEX = (1<<0),
|
|
SHADERSTAGE_FRAGMENT= (1<<1),
|
|
SHADERSTAGE_BOTH = (SHADERSTAGE_VERTEX | SHADERSTAGE_FRAGMENT),
|
|
};
|
|
|
|
VarType type;
|
|
ShaderStage declareLocation; // support declarations with/without layout qualifiers, needed for linkage testing
|
|
ShaderStage layoutLocation;
|
|
ShaderStage checkLocation;
|
|
int location; // -1 for unset
|
|
|
|
UniformInfo (VarType type_, ShaderStage declareLocation_, ShaderStage layoutLocation_, ShaderStage checkLocation_, int location_ = -1)
|
|
: type (type_)
|
|
, declareLocation (declareLocation_)
|
|
, layoutLocation (layoutLocation_)
|
|
, checkLocation (checkLocation_)
|
|
, location (location_)
|
|
{
|
|
}
|
|
};
|
|
|
|
class UniformLocationCase : public tcu::TestCase
|
|
{
|
|
public:
|
|
UniformLocationCase (tcu::TestContext& context,
|
|
glu::RenderContext& renderContext,
|
|
const char* name,
|
|
const char* desc,
|
|
const vector<UniformInfo>& uniformInfo);
|
|
virtual ~UniformLocationCase (void) {}
|
|
|
|
virtual IterateResult iterate (void);
|
|
|
|
protected:
|
|
IterateResult run (const vector<UniformInfo>& uniformList);
|
|
static glu::ProgramSources genShaderSources (const vector<UniformInfo>& uniformList);
|
|
bool verifyLocations (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
|
|
void render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
|
|
static bool verifyResult (const tcu::ConstPixelBufferAccess& access);
|
|
|
|
static float getExpectedValue (glu::DataType type, int id, const char* name);
|
|
|
|
de::MovePtr<glu::Texture2D> createTexture (glu::DataType samplerType, float redChannelValue, int binding);
|
|
|
|
glu::RenderContext& m_renderCtx;
|
|
|
|
const vector<UniformInfo> m_uniformInfo;
|
|
|
|
enum
|
|
{
|
|
RENDER_SIZE = 16
|
|
};
|
|
};
|
|
|
|
string getUniformName (int ndx, const glu::VarType& type, const glu::TypeComponentVector& path)
|
|
{
|
|
std::ostringstream buff;
|
|
buff << "uni" << ndx << glu::TypeAccessFormat(type, path);
|
|
|
|
return buff.str();
|
|
}
|
|
|
|
string getFirstComponentName (const glu::VarType& type)
|
|
{
|
|
std::ostringstream buff;
|
|
if (glu::isDataTypeVector(type.getBasicType()))
|
|
buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).component(0).getPath());
|
|
else if (glu::isDataTypeMatrix(type.getBasicType()))
|
|
buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).column(0).component(0).getPath());
|
|
|
|
return buff.str();
|
|
}
|
|
|
|
UniformLocationCase::UniformLocationCase (tcu::TestContext& context,
|
|
glu::RenderContext& renderContext,
|
|
const char* name,
|
|
const char* desc,
|
|
const vector<UniformInfo>& uniformInfo)
|
|
: TestCase (context, name, desc)
|
|
, m_renderCtx (renderContext)
|
|
, m_uniformInfo (uniformInfo)
|
|
{
|
|
}
|
|
|
|
// [from, to]
|
|
std::vector<int> shuffledRange (int from, int to, int seed)
|
|
{
|
|
const int count = to - from;
|
|
|
|
vector<int> retval (count);
|
|
de::Random rng (seed);
|
|
|
|
DE_ASSERT(count > 0);
|
|
|
|
for (int ndx = 0; ndx < count; ndx++)
|
|
retval[ndx] = ndx + from;
|
|
|
|
rng.shuffle(retval.begin(), retval.end());
|
|
return retval;
|
|
}
|
|
|
|
glu::DataType getDataTypeSamplerSampleType (glu::DataType type)
|
|
{
|
|
using namespace glu;
|
|
|
|
if (type >= TYPE_SAMPLER_1D && type <= TYPE_SAMPLER_3D)
|
|
return TYPE_FLOAT_VEC4;
|
|
else if (type >= TYPE_INT_SAMPLER_1D && type <= TYPE_INT_SAMPLER_3D)
|
|
return TYPE_INT_VEC4;
|
|
else if (type >= TYPE_UINT_SAMPLER_1D && type <= TYPE_UINT_SAMPLER_3D)
|
|
return TYPE_UINT_VEC4;
|
|
else if (type >= TYPE_SAMPLER_1D_SHADOW && type <= TYPE_SAMPLER_2D_ARRAY_SHADOW)
|
|
return TYPE_FLOAT;
|
|
else
|
|
DE_FATAL("Unknown sampler type");
|
|
|
|
return TYPE_INVALID;
|
|
}
|
|
|
|
// A (hopefully) unique value for a uniform. For multi-component types creates only one value. Values are in the range [0,1] for floats, [-128, 127] for ints, [0,255] for uints and 0/1 for booleans. Samplers are treated according to the types they return.
|
|
float UniformLocationCase::getExpectedValue (glu::DataType type, int id, const char* name)
|
|
{
|
|
const deUint32 hash = deStringHash(name) + deInt32Hash(id);
|
|
|
|
glu::DataType adjustedType = type;
|
|
|
|
if (glu::isDataTypeSampler(type))
|
|
adjustedType = getDataTypeSamplerSampleType(type);
|
|
|
|
if (glu::isDataTypeIntOrIVec(adjustedType))
|
|
return float(hash%128);
|
|
else if (glu::isDataTypeUintOrUVec(adjustedType))
|
|
return float(hash%255);
|
|
else if (glu::isDataTypeFloatOrVec(adjustedType))
|
|
return float(hash%255)/255.0f;
|
|
else if (glu::isDataTypeBoolOrBVec(adjustedType))
|
|
return float(hash%2);
|
|
else
|
|
DE_FATAL("Unkown primitive type");
|
|
|
|
return glu::TYPE_INVALID;
|
|
}
|
|
|
|
UniformLocationCase::IterateResult UniformLocationCase::iterate (void)
|
|
{
|
|
return run(m_uniformInfo);
|
|
}
|
|
|
|
UniformLocationCase::IterateResult UniformLocationCase::run (const vector<UniformInfo>& uniformList)
|
|
{
|
|
using gls::TextureTestUtil::RandomViewport;
|
|
|
|
const glu::ProgramSources sources = genShaderSources(uniformList);
|
|
const glu::ShaderProgram program (m_renderCtx, sources);
|
|
const int baseSeed = m_testCtx.getCommandLine().getBaseSeed();
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const RandomViewport viewport (m_renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()) + baseSeed);
|
|
|
|
tcu::Surface rendered (RENDER_SIZE, RENDER_SIZE);
|
|
|
|
if (!verifyLocations(program, uniformList))
|
|
return STOP;
|
|
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
|
|
render(program, uniformList);
|
|
|
|
glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
|
|
|
|
if (!verifyResult(rendered.getAccess()))
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader produced incorrect result");
|
|
return STOP;
|
|
}
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
return STOP;
|
|
}
|
|
|
|
glu::ProgramSources UniformLocationCase::genShaderSources (const vector<UniformInfo>& uniformList)
|
|
{
|
|
std::ostringstream vertDecl, vertMain, fragDecl, fragMain;
|
|
|
|
vertDecl << "#version 310 es\n"
|
|
<< "precision highp float;\n"
|
|
<< "precision highp int;\n"
|
|
<< "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
|
|
<< "in highp vec4 a_position;\n"
|
|
<< "out highp vec4 v_color;\n";
|
|
fragDecl << "#version 310 es\n\n"
|
|
<< "precision highp float;\n"
|
|
<< "precision highp int;\n"
|
|
<< "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
|
|
<< "in highp vec4 v_color;\n"
|
|
<< "layout(location = 0) out mediump vec4 o_color;\n\n";
|
|
|
|
vertMain << "void main()\n{\n"
|
|
<< " gl_Position = a_position;\n"
|
|
<< " v_color = vec4(1.0);\n";
|
|
|
|
fragMain << "void main()\n{\n"
|
|
<< " o_color = v_color;\n";
|
|
|
|
std::set<const glu::StructType*> declaredStructs;
|
|
|
|
// Declare uniforms
|
|
for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
|
|
{
|
|
const UniformInfo& uniformInfo = uniformList[uniformNdx];
|
|
|
|
const bool declareInVert = (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
|
|
const bool declareInFrag = (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
|
|
const bool layoutInVert = (uniformInfo.layoutLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
|
|
const bool layoutInFrag = (uniformInfo.layoutLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
|
|
const bool checkInVert = (uniformInfo.checkLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
|
|
const bool checkInFrag = (uniformInfo.checkLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
|
|
|
|
const string layout = uniformInfo.location >= 0 ? "layout(location = " + de::toString(uniformInfo.location) + ") " : "";
|
|
const string uniName = "uni" + de::toString(uniformNdx);
|
|
|
|
int location = uniformInfo.location;
|
|
int subTypeIndex = 0;
|
|
|
|
DE_ASSERT((declareInVert && layoutInVert) || !layoutInVert); // Cannot have layout without declaration
|
|
DE_ASSERT((declareInFrag && layoutInFrag) || !layoutInFrag);
|
|
DE_ASSERT(location<0 || (layoutInVert || layoutInFrag)); // Cannot have location without layout
|
|
|
|
// struct definitions
|
|
if (uniformInfo.type.isStructType())
|
|
{
|
|
const glu::StructType* const structType = uniformInfo.type.getStructPtr();
|
|
if (!declaredStructs.count(structType))
|
|
{
|
|
if (declareInVert)
|
|
vertDecl << glu::declare(structType, 0) << ";\n";
|
|
|
|
if (declareInFrag)
|
|
fragDecl << glu::declare(structType, 0) << ";\n";
|
|
|
|
declaredStructs.insert(structType);
|
|
}
|
|
}
|
|
|
|
if (declareInVert)
|
|
vertDecl << "uniform " << (layoutInVert ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
|
|
|
|
if (declareInFrag)
|
|
fragDecl << "uniform " << (layoutInFrag ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
|
|
|
|
// Anything that needs to be done for each enclosed primitive type
|
|
for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
|
|
{
|
|
const glu::VarType subType = glu::getVarType(uniformInfo.type, subTypeIter.getPath());
|
|
const glu::DataType scalarType = glu::getDataTypeScalarType(subType.getBasicType());
|
|
const char* const typeName = glu::getDataTypeName(scalarType);
|
|
const string expectValue = de::floatToString(getExpectedValue(scalarType, location >= 0 ? location+subTypeIndex : -1, typeName), 3);
|
|
|
|
if (glu::isDataTypeSampler(scalarType))
|
|
{
|
|
if (checkInVert)
|
|
vertMain << " v_color.rgb *= verify(float( texture(" << uniName
|
|
<< glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
|
|
<< ", vec2(0.5)).r), " << expectValue << ");\n";
|
|
if (checkInFrag)
|
|
fragMain << " o_color.rgb *= verify(float( texture(" << uniName
|
|
<< glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
|
|
<< ", vec2(0.5)).r), " << expectValue << ");\n";
|
|
}
|
|
else
|
|
{
|
|
if (checkInVert)
|
|
vertMain << " v_color.rgb *= verify(float(" << uniName
|
|
<< glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
|
|
<< getFirstComponentName(subType) << "), " << expectValue << ");\n";
|
|
if (checkInFrag)
|
|
fragMain << " o_color.rgb *= verify(float(" << uniName
|
|
<< glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
|
|
<< getFirstComponentName(subType) << "), " << expectValue << ");\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
vertMain << "}\n";
|
|
fragMain << "}\n";
|
|
|
|
return glu::makeVtxFragSources(vertDecl.str() + vertMain.str(), fragDecl.str() + fragMain.str());
|
|
}
|
|
|
|
bool UniformLocationCase::verifyLocations (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
|
|
{
|
|
using tcu::TestLog;
|
|
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const bool vertexOk = program.getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk;
|
|
const bool fragmentOk = program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk;
|
|
const bool linkOk = program.getProgramInfo().linkOk;
|
|
const deUint32 programID = program.getProgram();
|
|
|
|
TestLog& log = m_testCtx.getLog();
|
|
std::set<int> usedLocations;
|
|
|
|
log << program;
|
|
|
|
if (!vertexOk || !fragmentOk || !linkOk)
|
|
{
|
|
log << TestLog::Message << "ERROR: shader failed to compile/link" << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader failed to compile/link");
|
|
return false;
|
|
}
|
|
|
|
for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
|
|
{
|
|
const UniformInfo& uniformInfo = uniformList[uniformNdx];
|
|
int subTypeIndex = 0;
|
|
|
|
for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
|
|
{
|
|
const string name = getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
|
|
const int gotLoc = gl.getUniformLocation(programID, name.c_str());
|
|
const int expectLoc = uniformInfo.location >= 0 ? uniformInfo.location+subTypeIndex : -1;
|
|
|
|
if (expectLoc >= 0)
|
|
{
|
|
if (uniformInfo.checkLocation == 0 && gotLoc == -1)
|
|
continue;
|
|
|
|
if (gotLoc != expectLoc)
|
|
{
|
|
log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " when it should have been in " << expectLoc << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
|
|
return false;
|
|
}
|
|
|
|
if (usedLocations.find(expectLoc) != usedLocations.end())
|
|
{
|
|
log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc << " but it has already been used" << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
|
|
return false;
|
|
}
|
|
|
|
usedLocations.insert(expectLoc);
|
|
}
|
|
else if (gotLoc >= 0)
|
|
{
|
|
if (usedLocations.count(gotLoc))
|
|
{
|
|
log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " which has already been used" << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
|
|
return false;
|
|
}
|
|
|
|
usedLocations.insert(gotLoc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Check that shader output is white (or very close to it)
|
|
bool UniformLocationCase::verifyResult (const tcu::ConstPixelBufferAccess& access)
|
|
{
|
|
using tcu::Vec4;
|
|
|
|
const Vec4 threshold (0.1f, 0.1f, 0.1f, 0.1f);
|
|
const Vec4 reference (1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
for (int y = 0; y < access.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < access.getWidth(); x++)
|
|
{
|
|
const Vec4 diff = abs(access.getPixel(x, y) - reference);
|
|
|
|
if (!boolAll(lessThanEqual(diff, threshold)))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// get a 4 channel 8 bits each texture format that is usable by the given sampler type
|
|
deUint32 getTextureFormat (glu::DataType samplerType)
|
|
{
|
|
using namespace glu;
|
|
|
|
switch (samplerType)
|
|
{
|
|
case TYPE_SAMPLER_1D:
|
|
case TYPE_SAMPLER_2D:
|
|
case TYPE_SAMPLER_CUBE:
|
|
case TYPE_SAMPLER_2D_ARRAY:
|
|
case TYPE_SAMPLER_3D:
|
|
return GL_RGBA8;
|
|
|
|
case TYPE_INT_SAMPLER_1D:
|
|
case TYPE_INT_SAMPLER_2D:
|
|
case TYPE_INT_SAMPLER_CUBE:
|
|
case TYPE_INT_SAMPLER_2D_ARRAY:
|
|
case TYPE_INT_SAMPLER_3D:
|
|
return GL_RGBA8I;
|
|
|
|
case TYPE_UINT_SAMPLER_1D:
|
|
case TYPE_UINT_SAMPLER_2D:
|
|
case TYPE_UINT_SAMPLER_CUBE:
|
|
case TYPE_UINT_SAMPLER_2D_ARRAY:
|
|
case TYPE_UINT_SAMPLER_3D:
|
|
return GL_RGBA8UI;
|
|
|
|
default:
|
|
DE_FATAL("Unsupported (sampler) type");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// create a texture suitable for sampling by the given sampler type and bind it
|
|
de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture (glu::DataType samplerType, float redChannelValue, int binding)
|
|
{
|
|
using namespace glu;
|
|
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
const deUint32 format = getTextureFormat(samplerType);
|
|
de::MovePtr<Texture2D> tex;
|
|
|
|
tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
|
|
|
|
tex->getRefTexture().allocLevel(0);
|
|
|
|
if (format == GL_RGBA8I || format == GL_RGBA8UI)
|
|
tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
|
|
else
|
|
tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
|
|
|
|
gl.activeTexture(GL_TEXTURE0 + binding);
|
|
tex->upload();
|
|
|
|
gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
|
|
|
|
return tex;
|
|
}
|
|
|
|
void UniformLocationCase::render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
|
|
{
|
|
using glu::Texture2D;
|
|
using de::MovePtr;
|
|
typedef vector<Texture2D*> TextureList;
|
|
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const deUint32 programID = program.getProgram();
|
|
const deInt32 posLoc = gl.getAttribLocation(programID, "a_position");
|
|
|
|
// Vertex data.
|
|
const float position[] =
|
|
{
|
|
-1.0f, -1.0f, 0.1f, 1.0f,
|
|
-1.0f, 1.0f, 0.1f, 1.0f,
|
|
1.0f, -1.0f, 0.1f, 1.0f,
|
|
1.0f, 1.0f, 0.1f, 1.0f
|
|
};
|
|
const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
|
|
|
|
// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
|
|
float floatBuf[16] = {0.0f};
|
|
deInt32 intBuf[4] = {0};
|
|
deUint32 uintBuf[4] = {0};
|
|
|
|
TextureList texList;
|
|
|
|
TCU_CHECK(posLoc >= 0);
|
|
gl.useProgram(programID);
|
|
|
|
try
|
|
{
|
|
|
|
// Set uniforms
|
|
for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
|
|
{
|
|
const UniformInfo& uniformInfo = uniformList[uniformNdx];
|
|
int expectedLocation = uniformInfo.location;
|
|
|
|
for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
|
|
{
|
|
const glu::VarType type = glu::getVarType(uniformInfo.type, subTypeIter.getPath());
|
|
const string name = getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
|
|
const int gotLoc = gl.getUniformLocation(programID, name.c_str());
|
|
const glu::DataType scalarType = glu::getDataTypeScalarType(type.getBasicType());
|
|
const char* const typeName = glu::getDataTypeName(scalarType);
|
|
const float expectedValue = getExpectedValue(scalarType, expectedLocation, typeName);
|
|
|
|
if (glu::isDataTypeSampler(scalarType))
|
|
{
|
|
const int binding = (int)texList.size();
|
|
|
|
texList.push_back(createTexture(scalarType, expectedValue, binding).release());
|
|
gl.uniform1i(gotLoc, binding);
|
|
}
|
|
else if(gotLoc >= 0)
|
|
{
|
|
floatBuf[0] = expectedValue;
|
|
intBuf[0] = int(expectedValue);
|
|
uintBuf[0] = deUint32(expectedValue);
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
|
|
|
|
switch (type.getBasicType())
|
|
{
|
|
case glu::TYPE_FLOAT: gl.uniform1fv(gotLoc, 1, floatBuf); break;
|
|
case glu::TYPE_FLOAT_VEC2: gl.uniform2fv(gotLoc, 1, floatBuf); break;
|
|
case glu::TYPE_FLOAT_VEC3: gl.uniform3fv(gotLoc, 1, floatBuf); break;
|
|
case glu::TYPE_FLOAT_VEC4: gl.uniform4fv(gotLoc, 1, floatBuf); break;
|
|
|
|
case glu::TYPE_INT: gl.uniform1iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_INT_VEC2: gl.uniform2iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_INT_VEC3: gl.uniform3iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_INT_VEC4: gl.uniform4iv(gotLoc, 1, intBuf); break;
|
|
|
|
case glu::TYPE_UINT: gl.uniform1uiv(gotLoc, 1, uintBuf); break;
|
|
case glu::TYPE_UINT_VEC2: gl.uniform2uiv(gotLoc, 1, uintBuf); break;
|
|
case glu::TYPE_UINT_VEC3: gl.uniform3uiv(gotLoc, 1, uintBuf); break;
|
|
case glu::TYPE_UINT_VEC4: gl.uniform4uiv(gotLoc, 1, uintBuf); break;
|
|
|
|
case glu::TYPE_BOOL: gl.uniform1iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_BOOL_VEC2: gl.uniform2iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_BOOL_VEC3: gl.uniform3iv(gotLoc, 1, intBuf); break;
|
|
case glu::TYPE_BOOL_VEC4: gl.uniform4iv(gotLoc, 1, intBuf); break;
|
|
|
|
case glu::TYPE_FLOAT_MAT2: gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf); break;
|
|
|
|
case glu::TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT3: gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf); break;
|
|
|
|
case glu::TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf); break;
|
|
case glu::TYPE_FLOAT_MAT4: gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
expectedLocation += expectedLocation>=0;
|
|
}
|
|
}
|
|
|
|
gl.enableVertexAttribArray(posLoc);
|
|
gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
|
|
|
|
gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
|
|
|
|
gl.disableVertexAttribArray(posLoc);
|
|
}
|
|
catch(...)
|
|
{
|
|
for (int i = 0; i < int(texList.size()); i++)
|
|
delete texList[i];
|
|
|
|
throw;
|
|
}
|
|
|
|
for (int i = 0; i < int(texList.size()); i++)
|
|
delete texList[i];
|
|
}
|
|
|
|
class MaxUniformLocationCase : public UniformLocationCase
|
|
{
|
|
public:
|
|
MaxUniformLocationCase (tcu::TestContext& context,
|
|
glu::RenderContext& renderContext,
|
|
const char* name,
|
|
const char* desc,
|
|
const vector<UniformInfo>& uniformInfo);
|
|
virtual ~MaxUniformLocationCase (void) {}
|
|
virtual IterateResult iterate (void);
|
|
};
|
|
|
|
MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext& context,
|
|
glu::RenderContext& renderContext,
|
|
const char* name,
|
|
const char* desc,
|
|
const vector<UniformInfo>& uniformInfo)
|
|
: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
|
|
{
|
|
DE_ASSERT(!uniformInfo.empty());
|
|
}
|
|
|
|
UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
|
|
{
|
|
int maxLocation = 1024;
|
|
vector<UniformInfo> uniformInfo = m_uniformInfo;
|
|
|
|
m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
|
|
|
|
uniformInfo[0].location = maxLocation-1;
|
|
|
|
return UniformLocationCase::run(uniformInfo);
|
|
}
|
|
|
|
} // Anonymous
|
|
|
|
UniformLocationTests::UniformLocationTests (Context& context)
|
|
: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
|
|
{
|
|
}
|
|
|
|
UniformLocationTests::~UniformLocationTests (void)
|
|
{
|
|
for (int i = 0; i < int(structTypes.size()); i++)
|
|
delete structTypes[i];
|
|
}
|
|
|
|
glu::VarType createVarType (glu::DataType type)
|
|
{
|
|
return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
|
|
}
|
|
|
|
void UniformLocationTests::init (void)
|
|
{
|
|
using namespace glu;
|
|
|
|
const UniformInfo::ShaderStage checkStages[] = { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
|
|
const char* stageNames[] = {"vertex", "fragment"};
|
|
const int maxLocations = 1024;
|
|
const int baseSeed = m_context.getTestContext().getCommandLine().getBaseSeed();
|
|
|
|
const DataType primitiveTypes[] =
|
|
{
|
|
TYPE_FLOAT,
|
|
TYPE_FLOAT_VEC2,
|
|
TYPE_FLOAT_VEC3,
|
|
TYPE_FLOAT_VEC4,
|
|
|
|
TYPE_INT,
|
|
TYPE_INT_VEC2,
|
|
TYPE_INT_VEC3,
|
|
TYPE_INT_VEC4,
|
|
|
|
TYPE_UINT,
|
|
TYPE_UINT_VEC2,
|
|
TYPE_UINT_VEC3,
|
|
TYPE_UINT_VEC4,
|
|
|
|
TYPE_BOOL,
|
|
TYPE_BOOL_VEC2,
|
|
TYPE_BOOL_VEC3,
|
|
TYPE_BOOL_VEC4,
|
|
|
|
TYPE_FLOAT_MAT2,
|
|
TYPE_FLOAT_MAT2X3,
|
|
TYPE_FLOAT_MAT2X4,
|
|
TYPE_FLOAT_MAT3X2,
|
|
TYPE_FLOAT_MAT3,
|
|
TYPE_FLOAT_MAT3X4,
|
|
TYPE_FLOAT_MAT4X2,
|
|
TYPE_FLOAT_MAT4X3,
|
|
TYPE_FLOAT_MAT4,
|
|
|
|
TYPE_SAMPLER_2D,
|
|
TYPE_INT_SAMPLER_2D,
|
|
TYPE_UINT_SAMPLER_2D,
|
|
};
|
|
|
|
const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
|
|
DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
|
|
|
|
// Primitive type cases with trivial linkage
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
|
|
de::Random rng (baseSeed + 0x1001);
|
|
addChild(group);
|
|
|
|
for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
|
|
{
|
|
const DataType type = primitiveTypes[primitiveNdx];
|
|
|
|
for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
|
|
{
|
|
const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
|
|
|
|
vector<UniformInfo> config;
|
|
|
|
UniformInfo uniform (createVarType(type),
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
rng.getInt(0, maxLocations-1));
|
|
|
|
config.push_back(uniform);
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Arrays
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
|
|
de::Random rng (baseSeed + 0x2001);
|
|
addChild(group);
|
|
|
|
for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
|
|
{
|
|
const DataType type = primitiveTypes[primitiveNdx];
|
|
|
|
for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
|
|
{
|
|
|
|
const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
|
|
|
|
vector<UniformInfo> config;
|
|
|
|
UniformInfo uniform (VarType(createVarType(type), 8),
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
rng.getInt(0, maxLocations-1-8));
|
|
|
|
config.push_back(uniform);
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nested Arrays
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
|
|
de::Random rng (baseSeed + 0x3001);
|
|
addChild(group);
|
|
|
|
for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
|
|
{
|
|
const DataType type = primitiveTypes[primitiveNdx];
|
|
|
|
for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
|
|
{
|
|
const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
|
|
// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
|
|
const int arraySize = (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
|
|
|
|
vector<UniformInfo> config;
|
|
|
|
UniformInfo uniform (VarType(VarType(createVarType(type), arraySize), arraySize),
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
rng.getInt(0, maxLocations-1-arraySize*arraySize));
|
|
|
|
config.push_back(uniform);
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Structs
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
|
|
de::Random rng (baseSeed + 0x4001);
|
|
addChild(group);
|
|
|
|
for (int caseNdx = 0; caseNdx < 16; caseNdx++)
|
|
{
|
|
typedef UniformInfo::ShaderStage Stage;
|
|
|
|
const string name = "case_" + de::toString(caseNdx);
|
|
|
|
const Stage layoutLoc = Stage(rng.getUint32()&0x3);
|
|
const Stage declareLoc = Stage((rng.getUint32()&0x3) | layoutLoc);
|
|
const Stage verifyLoc = Stage((rng.getUint32()&0x3) & declareLoc);
|
|
const int location = layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
|
|
|
|
StructType* structProto = new StructType("S");
|
|
|
|
structTypes.push_back(structProto);
|
|
|
|
structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
|
|
{
|
|
vector<UniformInfo> config;
|
|
|
|
config.push_back(UniformInfo(VarType(structProto),
|
|
declareLoc,
|
|
layoutLoc,
|
|
verifyLoc,
|
|
location));
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nested Structs
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
|
|
de::Random rng (baseSeed + 0x5001);
|
|
|
|
addChild(group);
|
|
|
|
for (int caseNdx = 0; caseNdx < 16; caseNdx++)
|
|
{
|
|
typedef UniformInfo::ShaderStage Stage;
|
|
|
|
const string name = "case_" + de::toString(caseNdx);
|
|
const int baseLoc = rng.getInt(0, maxLocations-1-60);
|
|
|
|
// Structs need to be added in the order of their declaration
|
|
const Stage layoutLocs[]=
|
|
{
|
|
Stage(rng.getUint32()&0x3),
|
|
Stage(rng.getUint32()&0x3),
|
|
Stage(rng.getUint32()&0x3),
|
|
Stage(rng.getUint32()&0x3),
|
|
};
|
|
|
|
const deUint32 tempDecl[] =
|
|
{
|
|
(rng.getUint32()&0x3) | layoutLocs[0],
|
|
(rng.getUint32()&0x3) | layoutLocs[1],
|
|
(rng.getUint32()&0x3) | layoutLocs[2],
|
|
(rng.getUint32()&0x3) | layoutLocs[3],
|
|
};
|
|
|
|
// Component structs need to be declared if anything using them is declared
|
|
const Stage declareLocs[] =
|
|
{
|
|
Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
|
|
Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
|
|
Stage(tempDecl[2] | tempDecl[3]),
|
|
Stage(tempDecl[3]),
|
|
};
|
|
|
|
const Stage verifyLocs[] =
|
|
{
|
|
Stage(rng.getUint32()&0x3 & declareLocs[0]),
|
|
Stage(rng.getUint32()&0x3 & declareLocs[1]),
|
|
Stage(rng.getUint32()&0x3 & declareLocs[2]),
|
|
Stage(rng.getUint32()&0x3 & declareLocs[3]),
|
|
};
|
|
|
|
StructType* testTypes[] =
|
|
{
|
|
new StructType("Type0"),
|
|
new StructType("Type1"),
|
|
new StructType("Type2"),
|
|
new StructType("Type3"),
|
|
};
|
|
|
|
structTypes.push_back(testTypes[0]);
|
|
structTypes.push_back(testTypes[1]);
|
|
structTypes.push_back(testTypes[2]);
|
|
structTypes.push_back(testTypes[3]);
|
|
|
|
testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
|
|
testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
|
|
testTypes[2]->addMember("a", VarType(testTypes[0]));
|
|
testTypes[2]->addMember("b", VarType(testTypes[1]));
|
|
testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
|
|
|
|
testTypes[3]->addMember("a", VarType(testTypes[2]));
|
|
|
|
{
|
|
vector<UniformInfo> config;
|
|
|
|
config.push_back(UniformInfo(VarType(testTypes[0]),
|
|
declareLocs[0],
|
|
layoutLocs[0],
|
|
verifyLocs[0],
|
|
layoutLocs[0] ? baseLoc : -1));
|
|
|
|
config.push_back(UniformInfo(VarType(testTypes[1]),
|
|
declareLocs[1],
|
|
layoutLocs[1],
|
|
verifyLocs[1],
|
|
layoutLocs[1] ? baseLoc+5 : -1));
|
|
|
|
config.push_back(UniformInfo(VarType(testTypes[2]),
|
|
declareLocs[2],
|
|
layoutLocs[2],
|
|
verifyLocs[2],
|
|
layoutLocs[2] ? baseLoc+16 : -1));
|
|
|
|
config.push_back(UniformInfo(VarType(testTypes[3]),
|
|
declareLocs[3],
|
|
layoutLocs[3],
|
|
verifyLocs[3],
|
|
layoutLocs[3] ? baseLoc+27 : -1));
|
|
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Min/Max location
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
|
|
|
|
addChild(group);
|
|
|
|
for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
|
|
{
|
|
const DataType type = primitiveTypes[primitiveNdx];
|
|
|
|
for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
|
|
{
|
|
const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
|
|
vector<UniformInfo> config;
|
|
|
|
config.push_back(UniformInfo(createVarType(type),
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
checkStages[stageNdx],
|
|
0));
|
|
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
|
|
|
|
group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Link
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
|
|
de::Random rng (baseSeed + 0x82e1);
|
|
|
|
addChild(group);
|
|
|
|
for (int caseNdx = 0; caseNdx < 10; caseNdx++)
|
|
{
|
|
const string name = "case_" + de::toString(caseNdx);
|
|
vector<UniformInfo> config;
|
|
|
|
vector<int> locations = shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
|
|
|
|
for (int count = 0; count < 32; count++)
|
|
{
|
|
typedef UniformInfo::ShaderStage Stage;
|
|
|
|
const Stage layoutLoc = Stage(rng.getUint32()&0x3);
|
|
const Stage declareLoc = Stage((rng.getUint32()&0x3) | layoutLoc);
|
|
const Stage verifyLoc = Stage((rng.getUint32()&0x3) & declareLoc);
|
|
|
|
const UniformInfo uniform (createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
|
|
declareLoc,
|
|
layoutLoc,
|
|
verifyLoc,
|
|
(layoutLoc!=0) ? locations.back() : -1);
|
|
|
|
config.push_back(uniform);
|
|
locations.pop_back();
|
|
}
|
|
group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
|
|
}
|
|
}
|
|
|
|
// Negative
|
|
{
|
|
de::MovePtr<tcu::TestCaseGroup> negativeGroup (new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"));
|
|
|
|
{
|
|
de::MovePtr<tcu::TestCaseGroup> es31Group (new tcu::TestCaseGroup(m_testCtx, "es31", "GLSL ES 3.1 Negative tests"));
|
|
gls::ShaderLibrary shaderLibrary (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
|
|
const vector<TestNode*> negativeCases = shaderLibrary.loadShaderFile("shaders/es31/uniform_location.test");
|
|
|
|
for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
|
|
es31Group->addChild(negativeCases[ndx]);
|
|
|
|
negativeGroup->addChild(es31Group.release());
|
|
}
|
|
|
|
{
|
|
de::MovePtr<tcu::TestCaseGroup> es32Group (new tcu::TestCaseGroup(m_testCtx, "es32", "GLSL ES 3.2 Negative tests"));
|
|
gls::ShaderLibrary shaderLibrary (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
|
|
const vector<TestNode*> negativeCases = shaderLibrary.loadShaderFile("shaders/es32/uniform_location.test");
|
|
|
|
for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
|
|
es32Group->addChild(negativeCases[ndx]);
|
|
|
|
negativeGroup->addChild(es32Group.release());
|
|
}
|
|
|
|
addChild(negativeGroup.release());
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles31
|
|
} // deqp
|