/*-------------------------------------------------------------------------
* 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 Basic Layout Binding Tests.
*//*--------------------------------------------------------------------*/
#include "es31fLayoutBindingTests.hpp"
#include "gluShaderProgram.hpp"
#include "gluPixelTransfer.hpp"
#include "gluTextureUtil.hpp"
#include "gluContextInfo.hpp"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"
#include "tcuSurface.hpp"
#include "tcuTestLog.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuRenderTarget.hpp"
#include "deString.h"
#include "deStringUtil.hpp"
#include "deRandom.hpp"
using tcu::TestLog;
using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{
enum TestType
{
TESTTYPE_BINDING_SINGLE = 0,
TESTTYPE_BINDING_MAX,
TESTTYPE_BINDING_MULTIPLE,
TESTTYPE_BINDING_ARRAY,
TESTTYPE_BINDING_MAX_ARRAY,
TESTTYPE_BINDING_LAST,
};
enum ShaderType
{
SHADERTYPE_VERTEX = 0,
SHADERTYPE_FRAGMENT,
SHADERTYPE_TESS_CONTROL,
SHADERTYPE_TESS_EVALUATION,
SHADERTYPE_ALL,
SHADERTYPE_LAST,
};
enum
{
MAX_UNIFORM_MULTIPLE_INSTANCES = 7,
MAX_UNIFORM_ARRAY_SIZE = 7,
};
std::string generateVertexShader (ShaderType shaderType, const std::string& shaderUniformDeclarations, const std::string& shaderBody)
{
static const char* const s_simpleVertexShaderSource = "#version 310 es\n"
"in highp vec4 a_position;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
"}\n";
switch (shaderType)
{
case SHADERTYPE_VERTEX:
case SHADERTYPE_ALL:
{
std::ostringstream vertexShaderSource;
vertexShaderSource << "#version 310 es\n"
<< "in highp vec4 a_position;\n"
<< "out highp vec4 v_color;\n"
<< "uniform highp int u_arrayNdx;\n\n"
<< shaderUniformDeclarations << "\n"
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 color;\n\n"
<< shaderBody << "\n"
<< " v_color = color;\n"
<< " gl_Position = a_position;\n"
<< "}\n";
return vertexShaderSource.str();
}
case SHADERTYPE_FRAGMENT:
case SHADERTYPE_TESS_CONTROL:
case SHADERTYPE_TESS_EVALUATION:
return s_simpleVertexShaderSource;
default:
DE_ASSERT(false);
return "";
}
}
std::string generateFragmentShader (ShaderType shaderType, const std::string& shaderUniformDeclarations, const std::string& shaderBody)
{
static const char* const s_simpleFragmentShaderSource = "#version 310 es\n"
"in highp vec4 v_color;\n"
"layout(location = 0) out highp vec4 fragColor;\n"
"void main (void)\n"
"{\n"
" fragColor = v_color;\n"
"}\n";
switch (shaderType)
{
case SHADERTYPE_VERTEX:
case SHADERTYPE_TESS_CONTROL:
case SHADERTYPE_TESS_EVALUATION:
return s_simpleFragmentShaderSource;
case SHADERTYPE_FRAGMENT:
{
std::ostringstream fragmentShaderSource;
fragmentShaderSource << "#version 310 es\n"
<< "layout(location = 0) out highp vec4 fragColor;\n"
<< "uniform highp int u_arrayNdx;\n\n"
<< shaderUniformDeclarations << "\n"
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 color;\n\n"
<< shaderBody << "\n"
<< " fragColor = color;\n"
<< "}\n";
return fragmentShaderSource.str();
}
case SHADERTYPE_ALL:
{
std::ostringstream fragmentShaderSource;
fragmentShaderSource << "#version 310 es\n"
<< "in highp vec4 v_color;\n"
<< "layout(location = 0) out highp vec4 fragColor;\n"
<< "uniform highp int u_arrayNdx;\n\n"
<< shaderUniformDeclarations << "\n"
<< "void main (void)\n"
<< "{\n"
<< " if (v_color.x > 2.0) discard;\n"
<< " highp vec4 color;\n\n"
<< shaderBody << "\n"
<< " fragColor = color;\n"
<< "}\n";
return fragmentShaderSource.str();
}
default:
DE_ASSERT(false);
return "";
}
}
std::string generateTessControlShader (ShaderType shaderType, const std::string& shaderUniformDeclarations, const std::string& shaderBody)
{
static const char* const s_simpleTessContorlShaderSource = "#version 310 es\n"
"#extension GL_EXT_tessellation_shader : require\n"
"layout (vertices=3) out;\n"
"\n"
"void main (void)\n"
"{\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
switch (shaderType)
{
case SHADERTYPE_VERTEX:
case SHADERTYPE_FRAGMENT:
case SHADERTYPE_TESS_EVALUATION:
return s_simpleTessContorlShaderSource;
case SHADERTYPE_TESS_CONTROL:
case SHADERTYPE_ALL:
{
std::ostringstream tessControlShaderSource;
tessControlShaderSource << "#version 310 es\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout (vertices=3) out;\n"
<< "\n"
<< "uniform highp int u_arrayNdx;\n\n"
<< shaderUniformDeclarations << "\n"
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 color;\n\n"
<< shaderBody << "\n"
<< " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
<< "}\n";
return tessControlShaderSource.str();
}
default:
DE_ASSERT(false);
return "";
}
}
std::string generateTessEvaluationShader (ShaderType shaderType, const std::string& shaderUniformDeclarations, const std::string& shaderBody)
{
static const char* const s_simpleTessEvaluationShaderSource = "#version 310 es\n"
"#extension GL_EXT_tessellation_shader : require\n"
"layout (triangles) in;\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n"
"}\n";
switch (shaderType)
{
case SHADERTYPE_VERTEX:
case SHADERTYPE_FRAGMENT:
case SHADERTYPE_TESS_CONTROL:
return s_simpleTessEvaluationShaderSource;
case SHADERTYPE_TESS_EVALUATION:
case SHADERTYPE_ALL:
{
std::ostringstream tessEvaluationShaderSource;
tessEvaluationShaderSource << "#version 310 es\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout (triangles) in;\n"
<< "\n"
<< "uniform highp int u_arrayNdx;\n\n"
<< shaderUniformDeclarations << "\n"
<< "out mediump vec4 v_color;\n"
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 color;\n\n"
<< shaderBody << "\n"
<< " v_color = color;\n"
<< " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n"
<< "}\n";
return tessEvaluationShaderSource.str();
}
default:
DE_ASSERT(false);
return "";
}
}
std::string getUniformName (const std::string& name, int declNdx)
{
return name + de::toString(declNdx);
}
std::string getUniformName (const std::string& name, int declNdx, int arrNdx)
{
return name + de::toString(declNdx) + "[" + de::toString(arrNdx) + "]";
}
Vec4 getRandomColor (de::Random& rnd)
{
const float r = rnd.getFloat(0.2f, 0.9f);
const float g = rnd.getFloat(0.2f, 0.9f);
const float b = rnd.getFloat(0.2f, 0.9f);
return Vec4(r, g, b, 1.0f);
}
class LayoutBindingRenderCase : public TestCase
{
public:
enum
{
MAX_TEST_RENDER_WIDTH = 256,
MAX_TEST_RENDER_HEIGHT = 256,
TEST_TEXTURE_SIZE = 1,
};
LayoutBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
glw::GLenum maxBindingPointEnum,
glw::GLenum maxVertexUnitsEnum,
glw::GLenum maxFragmentUnitsEnum,
glw::GLenum maxCombinedUnitsEnum,
const std::string& uniformName);
virtual ~LayoutBindingRenderCase (void);
virtual void init (void);
virtual void deinit (void);
int getRenderWidth (void) const { return de::min((int)MAX_TEST_RENDER_WIDTH, m_context.getRenderTarget().getWidth()); }
int getRenderHeight (void) const { return de::min((int)MAX_TEST_RENDER_HEIGHT, m_context.getRenderTarget().getHeight()); }
protected:
virtual glu::ShaderProgram* generateShaders (void) const = 0;
void initRenderState (void);
bool drawAndVerifyResult (const Vec4& expectedColor);
void setTestResult (bool queryTestPassed, bool imageTestPassed);
const glu::ShaderProgram* m_program;
const ShaderType m_shaderType;
const TestType m_testType;
const std::string m_uniformName;
const glw::GLenum m_maxBindingPointEnum;
const glw::GLenum m_maxVertexUnitsEnum;
const glw::GLenum m_maxFragmentUnitsEnum;
const glw::GLenum m_maxCombinedUnitsEnum;
glw::GLuint m_vertexBuffer;
glw::GLuint m_indexBuffer;
glw::GLint m_shaderProgramLoc;
glw::GLint m_shaderProgramPosLoc;
glw::GLint m_shaderProgramArrayNdxLoc;
glw::GLint m_numBindings;
std::vector<glw::GLint> m_bindings;
private:
void initBindingPoints (int minBindingPoint, int numBindingPoints);
};
LayoutBindingRenderCase::LayoutBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
glw::GLenum maxBindingPointEnum,
glw::GLenum maxVertexUnitsEnum,
glw::GLenum maxFragmentUnitsEnum,
glw::GLenum maxCombinedUnitsEnum,
const std::string& uniformName)
: TestCase (context, name, desc)
, m_program (DE_NULL)
, m_shaderType (shaderType)
, m_testType (testType)
, m_uniformName (uniformName)
, m_maxBindingPointEnum (maxBindingPointEnum)
, m_maxVertexUnitsEnum (maxVertexUnitsEnum)
, m_maxFragmentUnitsEnum (maxFragmentUnitsEnum)
, m_maxCombinedUnitsEnum (maxCombinedUnitsEnum)
, m_vertexBuffer (0)
, m_indexBuffer (0)
, m_shaderProgramLoc (0)
, m_shaderProgramPosLoc (0)
, m_shaderProgramArrayNdxLoc (0)
, m_numBindings (0)
{
}
LayoutBindingRenderCase::~LayoutBindingRenderCase (void)
{
deinit();
}
void LayoutBindingRenderCase::init (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
{
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
glw::GLint numBindingPoints = 0; // Number of available binding points
glw::GLint maxVertexUnits = 0; // Available uniforms in the vertex shader
glw::GLint maxFragmentUnits = 0; // Available uniforms in the fragment shader
glw::GLint maxCombinedUnits = 0; // Available uniforms in all the shader stages combined
glw::GLint maxUnits = 0; // Maximum available uniforms for this test
gl.getIntegerv(m_maxVertexUnitsEnum, &maxVertexUnits);
gl.getIntegerv(m_maxFragmentUnitsEnum, &maxFragmentUnits);
gl.getIntegerv(m_maxCombinedUnitsEnum, &maxCombinedUnits);
gl.getIntegerv(m_maxBindingPointEnum, &numBindingPoints);
GLU_EXPECT_NO_ERROR(gl.getError(), "Querying available uniform numbers failed");
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the vertex shader: " << maxVertexUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the fragment shader: " << maxFragmentUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum combined units for uniform type: " << maxCombinedUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum binding point for uniform type: " << numBindingPoints-1 << tcu::TestLog::EndMessage;
// Select maximum number of uniforms used for the test
switch (m_shaderType)
{
case SHADERTYPE_VERTEX:
maxUnits = maxVertexUnits;
break;
case SHADERTYPE_FRAGMENT:
maxUnits = maxFragmentUnits;
break;
case SHADERTYPE_ALL:
maxUnits = maxCombinedUnits/2;
break;
default:
DE_ASSERT(false);
}
// Select the number of uniforms (= bindings) used for this test
switch (m_testType)
{
case TESTTYPE_BINDING_SINGLE:
case TESTTYPE_BINDING_MAX:
m_numBindings = 1;
break;
case TESTTYPE_BINDING_MULTIPLE:
if (maxUnits < 2)
throw tcu::NotSupportedError("Not enough uniforms available for test");
m_numBindings = rnd.getInt(2, deMin32(MAX_UNIFORM_MULTIPLE_INSTANCES, maxUnits));
break;
case TESTTYPE_BINDING_ARRAY:
case TESTTYPE_BINDING_MAX_ARRAY:
if (maxUnits < 2)
throw tcu::NotSupportedError("Not enough uniforms available for test");
m_numBindings = rnd.getInt(2, deMin32(MAX_UNIFORM_ARRAY_SIZE, maxUnits));
break;
default:
DE_ASSERT(false);
}
// Check that we have enough uniforms in different shaders to perform the tests
if ( ((m_shaderType == SHADERTYPE_VERTEX) || (m_shaderType == SHADERTYPE_ALL)) && (maxVertexUnits < m_numBindings) )
throw tcu::NotSupportedError("Vertex shader: not enough uniforms available for test");
if ( ((m_shaderType == SHADERTYPE_FRAGMENT) || (m_shaderType == SHADERTYPE_ALL)) && (maxFragmentUnits < m_numBindings) )
throw tcu::NotSupportedError("Fragment shader: not enough uniforms available for test");
if ( (m_shaderType == SHADERTYPE_ALL) && (maxCombinedUnits < m_numBindings*2) )
throw tcu::NotSupportedError("Not enough uniforms available for test");
// Check that we have enough binding points to perform the tests
if (numBindingPoints < m_numBindings)
throw tcu::NotSupportedError("Not enough binding points available for test");
// Initialize the binding points i.e. populate the two binding point vectors
initBindingPoints(0, numBindingPoints);
}
// Generate the shader program - note: this must be done after deciding the binding points
DE_ASSERT(!m_program);
m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shaders" << tcu::TestLog::EndMessage;
m_program = generateShaders();
m_testCtx.getLog() << *m_program;
if (!m_program->isOk())
throw tcu::TestError("Shader compile failed");
// Setup vertex and index buffers
{
// Get attribute and uniform locations
const deUint32 program = m_program->getProgram();
m_shaderProgramPosLoc = gl.getAttribLocation(program, "a_position");
m_shaderProgramArrayNdxLoc = gl.getUniformLocation(program, "u_arrayNdx");
m_vertexBuffer = 0;
m_indexBuffer = 0;
// Setup buffers so that we render one quad covering the whole viewport
const Vec3 vertices[] =
{
Vec3(-1.0f, -1.0f, +1.0f),
Vec3(+1.0f, -1.0f, +1.0f),
Vec3(+1.0f, +1.0f, +1.0f),
Vec3(-1.0f, +1.0f, +1.0f),
};
const deUint16 indices[] =
{
0, 1, 2,
0, 2, 3,
};
TCU_CHECK((m_shaderProgramPosLoc >= 0) && (m_shaderProgramArrayNdxLoc >= 0));
// Generate and bind index buffer
gl.genBuffers(1, &m_indexBuffer);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (DE_LENGTH_OF_ARRAY(indices)*(glw::GLsizeiptr)sizeof(indices[0])), &indices[0], GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Index buffer setup failed");
// Generate and bind vertex buffer
gl.genBuffers(1, &m_vertexBuffer);
gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
gl.bufferData(GL_ARRAY_BUFFER, (DE_LENGTH_OF_ARRAY(vertices)*(glw::GLsizeiptr)sizeof(vertices[0])), &vertices[0], GL_STATIC_DRAW);
gl.enableVertexAttribArray(m_shaderProgramPosLoc);
gl.vertexAttribPointer(m_shaderProgramPosLoc, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "Vertex buffer setup failed");
}
}
void LayoutBindingRenderCase::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
if (m_shaderProgramPosLoc)
m_context.getRenderContext().getFunctions().disableVertexAttribArray(m_shaderProgramPosLoc);
if (m_vertexBuffer)
{
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vertexBuffer);
m_context.getRenderContext().getFunctions().bindBuffer(GL_ARRAY_BUFFER, 0);
}
if (m_indexBuffer)
{
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBuffer);
m_context.getRenderContext().getFunctions().bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
void LayoutBindingRenderCase::initBindingPoints (int minBindingPoint, int numBindingPoints)
{
de::Random rnd(deStringHash(getName()) ^ 0xff23a4);
switch (m_testType)
{
case TESTTYPE_BINDING_SINGLE:
{
const int bpoint = rnd.getInt(minBindingPoint, numBindingPoints-1);
m_bindings.push_back(bpoint);
break;
}
case TESTTYPE_BINDING_MAX:
m_bindings.push_back(numBindingPoints-1);
break;
case TESTTYPE_BINDING_MULTIPLE:
{
// Choose multiple unique binding points from the low and high end of available binding points
std::vector<deUint32> lowBindingPoints;
std::vector<deUint32> highBindingPoints;
for (int bpoint = 0; bpoint < numBindingPoints/2; ++bpoint)
lowBindingPoints.push_back(bpoint);
for (int bpoint = numBindingPoints/2; bpoint < numBindingPoints; ++bpoint)
highBindingPoints.push_back(bpoint);
rnd.shuffle(lowBindingPoints.begin(), lowBindingPoints.end());
rnd.shuffle(highBindingPoints.begin(), highBindingPoints.end());
for (int ndx = 0; ndx < m_numBindings; ++ndx)
{
if (ndx%2 == 0)
{
const int bpoint = lowBindingPoints.back();
lowBindingPoints.pop_back();
m_bindings.push_back(bpoint);
}
else
{
const int bpoint = highBindingPoints.back();
highBindingPoints.pop_back();
m_bindings.push_back(bpoint);
}
}
break;
}
case TESTTYPE_BINDING_ARRAY:
{
const glw::GLint binding = rnd.getInt(minBindingPoint, numBindingPoints-m_numBindings);
for (int ndx = 0; ndx < m_numBindings; ++ndx)
m_bindings.push_back(binding+ndx);
break;
}
case TESTTYPE_BINDING_MAX_ARRAY:
{
const glw::GLint binding = numBindingPoints-m_numBindings;
for (int ndx = 0; ndx < m_numBindings; ++ndx)
m_bindings.push_back(binding+ndx);
break;
}
default:
DE_ASSERT(false);
}
}
void LayoutBindingRenderCase::initRenderState (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(m_program->getProgram());
gl.viewport(0, 0, getRenderWidth(), getRenderHeight());
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state");
}
bool LayoutBindingRenderCase::drawAndVerifyResult (const Vec4& expectedColor)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
tcu::Surface reference (getRenderWidth(), getRenderHeight());
// the point of these test is to check layout_binding. For this purpose, we can use quite
// large thresholds.
const tcu::RGBA surfaceThreshold = m_context.getRenderContext().getRenderTarget().getPixelFormat().getColorThreshold();
const tcu::RGBA compareThreshold = tcu::RGBA(de::clamp(2 * surfaceThreshold.getRed(), 0, 255),
de::clamp(2 * surfaceThreshold.getGreen(), 0, 255),
de::clamp(2 * surfaceThreshold.getBlue(), 0, 255),
de::clamp(2 * surfaceThreshold.getAlpha(), 0, 255));
gl.clear(GL_COLOR_BUFFER_BIT);
// Draw
gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "Drawing failed");
// Verify
tcu::Surface result(getRenderWidth(), getRenderHeight());
m_testCtx.getLog() << TestLog::Message << "Reading pixels" << TestLog::EndMessage;
glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
tcu::clear(reference.getAccess(), expectedColor);
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image, fragment output color is " << expectedColor << tcu::TestLog::EndMessage;
return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Render result", "Result verification", reference, result, compareThreshold, tcu::COMPARE_LOG_RESULT);
}
void LayoutBindingRenderCase::setTestResult (bool queryTestPassed, bool imageTestPassed)
{
if (queryTestPassed && imageTestPassed)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else if (!queryTestPassed && !imageTestPassed)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "One or more binding point queries and image comparisons failed");
else if (!queryTestPassed)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "One or more binding point queries failed");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "One or more image comparisons failed");
}
class LayoutBindingNegativeCase : public TestCase
{
public:
enum ErrorType
{
ERRORTYPE_OVER_MAX_UNITS = 0,
ERRORTYPE_LESS_THAN_ZERO,
ERRORTYPE_CONTRADICTORY,
ERRORTYPE_LAST,
};
LayoutBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum maxBindingPointEnum,
glw::GLenum maxVertexUnitsEnum,
glw::GLenum maxFragmentUnitsEnum,
glw::GLenum maxTessCtrlUnitsEnum,
glw::GLenum maxTessEvalUnitsEnum,
glw::GLenum maxCombinedUnitsEnum,
const std::string& uniformName);
virtual ~LayoutBindingNegativeCase (void);
virtual void init (void);
virtual void deinit (void);
virtual IterateResult iterate (void);
protected:
virtual glu::ShaderProgram* generateShaders (void) const = 0;
const glu::ShaderProgram* m_program;
const ShaderType m_shaderType;
const TestType m_testType;
const ErrorType m_errorType;
const glw::GLenum m_maxBindingPointEnum;
const glw::GLenum m_maxVertexUnitsEnum;
const glw::GLenum m_maxFragmentUnitsEnum;
const glw::GLenum m_maxTessCtrlUnitsEnum;
const glw::GLenum m_maxTessEvalUnitsEnum;
const glw::GLenum m_maxCombinedUnitsEnum;
const std::string m_uniformName;
glw::GLint m_numBindings;
std::vector<glw::GLint> m_vertexShaderBinding;
std::vector<glw::GLint> m_fragmentShaderBinding;
std::vector<glw::GLint> m_tessCtrlShaderBinding;
std::vector<glw::GLint> m_tessEvalShaderBinding;
bool m_tessSupport;
private:
void initBindingPoints (int minBindingPoint, int numBindingPoints);
};
LayoutBindingNegativeCase::LayoutBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum maxBindingPointEnum,
glw::GLenum maxVertexUnitsEnum,
glw::GLenum maxTessCtrlUnitsEnum,
glw::GLenum maxTessEvalUnitsEnum,
glw::GLenum maxFragmentUnitsEnum,
glw::GLenum maxCombinedUnitsEnum,
const std::string& uniformName)
: TestCase (context, name, desc)
, m_program (DE_NULL)
, m_shaderType (shaderType)
, m_testType (testType)
, m_errorType (errorType)
, m_maxBindingPointEnum (maxBindingPointEnum)
, m_maxVertexUnitsEnum (maxVertexUnitsEnum)
, m_maxFragmentUnitsEnum (maxFragmentUnitsEnum)
, m_maxTessCtrlUnitsEnum (maxTessCtrlUnitsEnum)
, m_maxTessEvalUnitsEnum (maxTessEvalUnitsEnum)
, m_maxCombinedUnitsEnum (maxCombinedUnitsEnum)
, m_uniformName (uniformName)
, m_numBindings (0)
, m_tessSupport (false)
{
}
LayoutBindingNegativeCase::~LayoutBindingNegativeCase (void)
{
deinit();
}
void LayoutBindingNegativeCase::init (void)
{
// Decide appropriate binding points for the vertex and fragment shaders
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
glw::GLint numBindingPoints = 0; // Number of binding points
glw::GLint maxVertexUnits = 0; // Available uniforms in the vertex shader
glw::GLint maxFragmentUnits = 0; // Available uniforms in the fragment shader
glw::GLint maxCombinedUnits = 0; // Available uniforms in all the shader stages combined
glw::GLint maxTessCtrlUnits = 0; // Available uniforms in tessellation control shader
glw::GLint maxTessEvalUnits = 0; // Available uniforms in tessellation evaluation shader
glw::GLint maxUnits = 0; // Maximum available uniforms for this test
m_tessSupport = m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader")
|| contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
if (!m_tessSupport && (m_shaderType == SHADERTYPE_TESS_EVALUATION || m_shaderType == SHADERTYPE_TESS_CONTROL))
TCU_THROW(NotSupportedError, "Tesselation shaders not supported");
int numShaderStages = m_tessSupport ? 4 : 2;
gl.getIntegerv(m_maxVertexUnitsEnum, &maxVertexUnits);
gl.getIntegerv(m_maxFragmentUnitsEnum, &maxFragmentUnits);
if (m_tessSupport)
{
gl.getIntegerv(m_maxTessCtrlUnitsEnum, &maxTessCtrlUnits);
gl.getIntegerv(m_maxTessEvalUnitsEnum, &maxTessEvalUnits);
}
gl.getIntegerv(m_maxCombinedUnitsEnum, &maxCombinedUnits);
gl.getIntegerv(m_maxBindingPointEnum, &numBindingPoints);
GLU_EXPECT_NO_ERROR(gl.getError(), "Querying available uniform numbers failed");
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the vertex shader: " << maxVertexUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the fragment shader: " << maxFragmentUnits << tcu::TestLog::EndMessage;
if (m_tessSupport)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the tessellation control shader: " << maxTessCtrlUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum units for uniform type in the tessellation evaluation shader: " << maxTessCtrlUnits << tcu::TestLog::EndMessage;
}
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum combined units for uniform type: " << maxCombinedUnits << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Maximum binding point for uniform type: " << numBindingPoints-1 << tcu::TestLog::EndMessage;
// Select maximum number of uniforms used for the test
switch (m_shaderType)
{
case SHADERTYPE_VERTEX:
maxUnits = maxVertexUnits;
break;
case SHADERTYPE_FRAGMENT:
maxUnits = maxFragmentUnits;
break;
case SHADERTYPE_ALL:
maxUnits = de::min(de::min(de::min(maxVertexUnits, maxFragmentUnits), de::min(maxTessCtrlUnits, maxTessEvalUnits)), maxCombinedUnits/numShaderStages);
break;
case SHADERTYPE_TESS_CONTROL:
maxUnits = maxTessCtrlUnits;
break;
case SHADERTYPE_TESS_EVALUATION:
maxUnits = maxTessEvalUnits;
break;
default:
DE_ASSERT(false);
}
// Select the number of uniforms (= bindings) used for this test
switch (m_testType)
{
case TESTTYPE_BINDING_SINGLE:
case TESTTYPE_BINDING_MAX:
m_numBindings = 1;
break;
case TESTTYPE_BINDING_MULTIPLE:
case TESTTYPE_BINDING_ARRAY:
case TESTTYPE_BINDING_MAX_ARRAY:
if (m_errorType == ERRORTYPE_CONTRADICTORY)
{
// leave room for contradictory case
if (maxUnits < 3)
TCU_THROW(NotSupportedError, "Not enough uniforms available for test");
m_numBindings = rnd.getInt(2, deMin32(MAX_UNIFORM_ARRAY_SIZE, maxUnits-1));
}
else
{
if (maxUnits < 2)
TCU_THROW(NotSupportedError, "Not enough uniforms available for test");
m_numBindings = rnd.getInt(2, deMin32(MAX_UNIFORM_ARRAY_SIZE, maxUnits));
}
break;
default:
DE_ASSERT(false);
}
// Check that we have enough uniforms in different shaders to perform the tests
if (((m_shaderType == SHADERTYPE_VERTEX) || (m_shaderType == SHADERTYPE_ALL)) && (maxVertexUnits < m_numBindings) )
TCU_THROW(NotSupportedError, "Vertex shader: not enough uniforms available for test");
if (((m_shaderType == SHADERTYPE_FRAGMENT) || (m_shaderType == SHADERTYPE_ALL)) && (maxFragmentUnits < m_numBindings) )
TCU_THROW(NotSupportedError, "Fragment shader: not enough uniforms available for test");
if (m_tessSupport && ((m_shaderType == SHADERTYPE_TESS_CONTROL) || (m_shaderType == SHADERTYPE_ALL)) && (maxTessCtrlUnits < m_numBindings) )
TCU_THROW(NotSupportedError, "Tessellation control shader: not enough uniforms available for test");
if (m_tessSupport && ((m_shaderType == SHADERTYPE_TESS_EVALUATION) || (m_shaderType == SHADERTYPE_ALL)) && (maxTessEvalUnits < m_numBindings) )
TCU_THROW(NotSupportedError, "Tessellation evaluation shader: not enough uniforms available for test");
if ((m_shaderType == SHADERTYPE_ALL) && (maxCombinedUnits < m_numBindings*numShaderStages) )
TCU_THROW(NotSupportedError, "Not enough uniforms available for test");
// Check that we have enough binding points to perform the tests
if (numBindingPoints < m_numBindings)
TCU_THROW(NotSupportedError, "Not enough binding points available for test");
if (m_errorType == ERRORTYPE_CONTRADICTORY && numBindingPoints == m_numBindings)
TCU_THROW(NotSupportedError, "Not enough binding points available for test");
// Initialize the binding points i.e. populate the two binding point vectors
initBindingPoints(0, numBindingPoints);
// Generate the shader program - note: this must be done after deciding the binding points
DE_ASSERT(!m_program);
m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shaders" << tcu::TestLog::EndMessage;
m_program = generateShaders();
m_testCtx.getLog() << *m_program;
}
void LayoutBindingNegativeCase::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
}
TestCase::IterateResult LayoutBindingNegativeCase::iterate (void)
{
bool pass = false;
std::string failMessage;
switch (m_errorType)
{
case ERRORTYPE_CONTRADICTORY: // Contradictory binding points should cause a link-time error
if (!(m_program->getProgramInfo()).linkOk)
pass = true;
failMessage = "Test failed - expected a link-time error";
break;
case ERRORTYPE_LESS_THAN_ZERO: // Out of bounds binding points should cause a compile-time error
case ERRORTYPE_OVER_MAX_UNITS:
if (m_tessSupport)
{
if (!(m_program->getShaderInfo(glu::SHADERTYPE_VERTEX)).compileOk
|| !(m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk)
|| !(m_program->getShaderInfo(glu::SHADERTYPE_TESSELLATION_CONTROL).compileOk)
|| !(m_program->getShaderInfo(glu::SHADERTYPE_TESSELLATION_EVALUATION)).compileOk)
pass = true;
}
else
{
if (!(m_program->getShaderInfo(glu::SHADERTYPE_VERTEX)).compileOk
|| !(m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk))
pass = true;
}
failMessage = "Test failed - expected a compile-time error";
break;
default:
DE_ASSERT(false);
}
if (pass)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failMessage.c_str());
return STOP;
}
void LayoutBindingNegativeCase::initBindingPoints (int minBindingPoint, int numBindingPoints)
{
de::Random rnd(deStringHash(getName()) ^ 0xff23a4);
switch (m_errorType)
{
case ERRORTYPE_OVER_MAX_UNITS: // Select a binding point that is 1 over the maximum
{
m_vertexShaderBinding.push_back(numBindingPoints+1-m_numBindings);
m_fragmentShaderBinding.push_back(numBindingPoints+1-m_numBindings);
m_tessCtrlShaderBinding.push_back(numBindingPoints+1-m_numBindings);
m_tessEvalShaderBinding.push_back(numBindingPoints+1-m_numBindings);
break;
}
case ERRORTYPE_LESS_THAN_ZERO: // Select a random negative binding point
{
const glw::GLint binding = -rnd.getInt(1, m_numBindings);
m_vertexShaderBinding.push_back(binding);
m_fragmentShaderBinding.push_back(binding);
m_tessCtrlShaderBinding.push_back(binding);
m_tessEvalShaderBinding.push_back(binding);
break;
}
case ERRORTYPE_CONTRADICTORY: // Select two valid, but contradictory binding points
{
m_vertexShaderBinding.push_back(minBindingPoint);
m_fragmentShaderBinding.push_back((minBindingPoint+1)%numBindingPoints);
m_tessCtrlShaderBinding.push_back((minBindingPoint+2)%numBindingPoints);
m_tessEvalShaderBinding.push_back((minBindingPoint+3)%numBindingPoints);
DE_ASSERT(m_vertexShaderBinding.back() != m_fragmentShaderBinding.back());
DE_ASSERT(m_fragmentShaderBinding.back() != m_tessEvalShaderBinding.back());
DE_ASSERT(m_tessEvalShaderBinding.back() != m_tessCtrlShaderBinding.back());
DE_ASSERT(m_tessCtrlShaderBinding.back() != m_vertexShaderBinding.back());
DE_ASSERT(m_vertexShaderBinding.back() != m_tessEvalShaderBinding.back());
DE_ASSERT(m_tessCtrlShaderBinding.back() != m_fragmentShaderBinding.back());
break;
}
default:
DE_ASSERT(false);
}
// In case we are testing with multiple uniforms populate the rest of the binding points
for (int ndx = 1; ndx < m_numBindings; ++ndx)
{
m_vertexShaderBinding.push_back(m_vertexShaderBinding.front()+ndx);
m_fragmentShaderBinding.push_back(m_fragmentShaderBinding.front()+ndx);
m_tessCtrlShaderBinding.push_back(m_tessCtrlShaderBinding.front()+ndx);
m_tessEvalShaderBinding.push_back(m_tessCtrlShaderBinding.front()+ndx);
}
}
class SamplerBindingRenderCase : public LayoutBindingRenderCase
{
public:
SamplerBindingRenderCase (Context& context, const char* name, const char* desc, ShaderType shaderType, TestType testType, glw::GLenum samplerType, glw::GLenum textureType);
~SamplerBindingRenderCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
glu::ShaderProgram* generateShaders (void) const;
glu::DataType getSamplerTexCoordType (void) const;
void initializeTexture (glw::GLint bindingPoint, glw::GLint textureName, const Vec4& color) const;
const glw::GLenum m_samplerType;
const glw::GLenum m_textureType;
std::vector<glw::GLuint> m_textures;
std::vector<Vec4> m_textureColors;
};
SamplerBindingRenderCase::SamplerBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
glw::GLenum samplerType,
glw::GLenum textureType)
: LayoutBindingRenderCase (context, name, desc, shaderType, testType, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GL_MAX_TEXTURE_IMAGE_UNITS, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, "u_sampler")
, m_samplerType (samplerType)
, m_textureType (textureType)
{
}
SamplerBindingRenderCase::~SamplerBindingRenderCase (void)
{
deinit();
}
void SamplerBindingRenderCase::init (void)
{
LayoutBindingRenderCase::init();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
// Initialize texture resources
m_textures = std::vector<glw::GLuint>(m_numBindings, 0);
// Texture colors
for (int texNdx = 0; texNdx < (int)m_textures.size(); ++texNdx)
m_textureColors.push_back(getRandomColor(rnd));
// Textures
gl.genTextures((glw::GLsizei)m_textures.size(), &m_textures[0]);
for (int texNdx = 0; texNdx < (int)m_textures.size(); ++texNdx)
initializeTexture(m_bindings[texNdx], m_textures[texNdx], m_textureColors[texNdx]);
gl.activeTexture(GL_TEXTURE0);
}
void SamplerBindingRenderCase::deinit(void)
{
LayoutBindingRenderCase::deinit();
// Clean up texture data
for (int i = 0; i < (int)m_textures.size(); ++i)
{
if (m_textures[i])
{
m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textures[i]);
m_context.getRenderContext().getFunctions().bindTexture(m_textureType, 0);
}
}
}
TestCase::IterateResult SamplerBindingRenderCase::iterate (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const int iterations = m_numBindings;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
bool imageTestPassed = true;
bool queryTestPassed = true;
// Set the viewport and enable the shader program
initRenderState();
for (int iterNdx = 0; iterNdx < iterations; ++iterNdx)
{
// Set the uniform value indicating the current array index
gl.uniform1i(m_shaderProgramArrayNdxLoc, iterNdx);
// Query binding point
const std::string name = arrayInstance ? getUniformName(m_uniformName, 0, iterNdx) : getUniformName(m_uniformName, iterNdx);
const glw::GLint binding = m_bindings[iterNdx];
glw::GLint val = -1;
gl.getUniformiv(m_program->getProgram(), gl.getUniformLocation(m_program->getProgram(), name.c_str()), &val);
m_testCtx.getLog() << tcu::TestLog::Message << "Querying binding point for " << name << ": " << val << " == " << binding << tcu::TestLog::EndMessage;
GLU_EXPECT_NO_ERROR(gl.getError(), "Binding point query failed");
// Draw and verify
if (val != binding)
queryTestPassed = false;
if (!drawAndVerifyResult(m_textureColors[iterNdx]))
imageTestPassed = false;
}
setTestResult(queryTestPassed, imageTestPassed);
return STOP;
}
glu::ShaderProgram* SamplerBindingRenderCase::generateShaders (void) const
{
std::ostringstream shaderUniformDecl;
std::ostringstream shaderBody;
const std::string texCoordType = glu::getDataTypeName(getSamplerTexCoordType());
const std::string samplerType = glu::getDataTypeName(glu::getDataTypeFromGLType(m_samplerType));
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY) ? true : false;
const int numDeclarations = arrayInstance ? 1 : m_numBindings;
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
shaderUniformDecl << "layout(binding = " << m_bindings[declNdx] << ") uniform highp " << samplerType << " "
<< (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings; ++bindNdx)
{
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = texture(" << (arrayInstance ? getUniformName(m_uniformName, 0, bindNdx) : getUniformName(m_uniformName, bindNdx)) << ", " << texCoordType << "(0.5));\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str())));
}
void SamplerBindingRenderCase::initializeTexture (glw::GLint bindingPoint, glw::GLint textureName, const Vec4& color) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.activeTexture(GL_TEXTURE0 + bindingPoint);
gl.bindTexture(m_textureType, textureName);
gl.texParameteri(m_textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
switch (m_textureType)
{
case GL_TEXTURE_2D:
{
tcu::TextureLevel level(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
tcu::clear(level.getAccess(), color);
glu::texImage2D(m_context.getRenderContext(), m_textureType, 0, GL_RGBA8, level.getAccess());
break;
}
case GL_TEXTURE_3D:
{
tcu::TextureLevel level(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
tcu::clear(level.getAccess(), color);
glu::texImage3D(m_context.getRenderContext(), m_textureType, 0, GL_RGBA8, level.getAccess());
break;
}
default:
DE_ASSERT(false);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "Texture initialization failed");
}
glu::DataType SamplerBindingRenderCase::getSamplerTexCoordType (void) const
{
switch (m_samplerType)
{
case GL_SAMPLER_2D:
return glu::TYPE_FLOAT_VEC2;
case GL_SAMPLER_3D:
return glu::TYPE_FLOAT_VEC3;
default:
DE_ASSERT(false);
return glu::TYPE_INVALID;
}
}
class SamplerBindingNegativeCase : public LayoutBindingNegativeCase
{
public:
SamplerBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum samplerType);
~SamplerBindingNegativeCase (void);
private:
glu::ShaderProgram* generateShaders (void) const;
glu::DataType getSamplerTexCoordType (void) const;
const glw::GLenum m_samplerType;
};
SamplerBindingNegativeCase::SamplerBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum samplerType)
: LayoutBindingNegativeCase (context,
name,
desc,
shaderType,
testType,
errorType,
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,
GL_MAX_TEXTURE_IMAGE_UNITS,
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
"u_sampler")
, m_samplerType (samplerType)
{
}
SamplerBindingNegativeCase::~SamplerBindingNegativeCase (void)
{
LayoutBindingNegativeCase::deinit();
}
glu::ShaderProgram* SamplerBindingNegativeCase::generateShaders (void) const
{
std::ostringstream vertexUniformDecl;
std::ostringstream fragmentUniformDecl;
std::ostringstream tessCtrlUniformDecl;
std::ostringstream tessEvalUniformDecl;
std::ostringstream shaderBody;
const std::string texCoordType = glu::getDataTypeName(getSamplerTexCoordType());
const std::string samplerType = glu::getDataTypeName(glu::getDataTypeFromGLType(m_samplerType));
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = arrayInstance ? 1 : m_numBindings;
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
vertexUniformDecl << "layout(binding = " << m_vertexShaderBinding[declNdx] << ") uniform highp " << samplerType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
fragmentUniformDecl << "layout(binding = " << m_fragmentShaderBinding[declNdx] << ") uniform highp " << samplerType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
tessCtrlUniformDecl << "layout(binding = " << m_tessCtrlShaderBinding[declNdx] << ") uniform highp " << samplerType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
tessEvalUniformDecl << "layout(binding = " << m_tessEvalShaderBinding[declNdx] << ") uniform highp " << samplerType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings; ++bindNdx)
{
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = texture(" << (arrayInstance ? getUniformName(m_uniformName, 0, bindNdx) : getUniformName(m_uniformName, bindNdx)) << ", " << texCoordType << "(0.5));\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
glu::ProgramSources sources = glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, vertexUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, fragmentUniformDecl.str(), shaderBody.str()));
if (m_tessSupport)
sources << glu::TessellationControlSource(generateTessControlShader(m_shaderType, tessCtrlUniformDecl.str(), shaderBody.str()))
<< glu::TessellationEvaluationSource(generateTessEvaluationShader(m_shaderType, tessEvalUniformDecl.str(), shaderBody.str()));
return new glu::ShaderProgram(m_context.getRenderContext(), sources);
}
glu::DataType SamplerBindingNegativeCase::getSamplerTexCoordType(void) const
{
switch (m_samplerType)
{
case GL_SAMPLER_2D:
return glu::TYPE_FLOAT_VEC2;
case GL_SAMPLER_3D:
return glu::TYPE_FLOAT_VEC3;
default:
DE_ASSERT(false);
return glu::TYPE_INVALID;
}
}
class ImageBindingRenderCase : public LayoutBindingRenderCase
{
public:
ImageBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
glw::GLenum imageType,
glw::GLenum textureType);
~ImageBindingRenderCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
glu::ShaderProgram* generateShaders (void) const;
void initializeImage (glw::GLint imageBindingPoint, glw::GLint textureBindingPoint, glw::GLint textureName, const Vec4& color) const;
glu::DataType getImageTexCoordType (void) const;
const glw::GLenum m_imageType;
const glw::GLenum m_textureType;
std::vector<glw::GLuint> m_textures;
std::vector<Vec4> m_textureColors;
};
ImageBindingRenderCase::ImageBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
glw::GLenum imageType,
glw::GLenum textureType)
: LayoutBindingRenderCase (context, name, desc, shaderType, testType, GL_MAX_IMAGE_UNITS, GL_MAX_VERTEX_IMAGE_UNIFORMS, GL_MAX_FRAGMENT_IMAGE_UNIFORMS, GL_MAX_COMBINED_IMAGE_UNIFORMS, "u_image")
, m_imageType (imageType)
, m_textureType (textureType)
{
}
ImageBindingRenderCase::~ImageBindingRenderCase (void)
{
deinit();
}
void ImageBindingRenderCase::init (void)
{
LayoutBindingRenderCase::init();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
// Initialize image / texture resources
m_textures = std::vector<glw::GLuint>(m_numBindings, 0);
// Texture colors
for (int texNdx = 0; texNdx < (int)m_textures.size(); ++texNdx)
m_textureColors.push_back(getRandomColor(rnd));
// Image textures
gl.genTextures(m_numBindings, &m_textures[0]);
for (int texNdx = 0; texNdx < (int)m_textures.size(); ++texNdx)
initializeImage(m_bindings[texNdx], texNdx, m_textures[texNdx], m_textureColors[texNdx]);
}
void ImageBindingRenderCase::deinit (void)
{
LayoutBindingRenderCase::deinit();
// Clean up texture data
for (int texNdx = 0; texNdx < (int)m_textures.size(); ++texNdx)
{
if (m_textures[texNdx])
{
m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textures[texNdx]);
m_context.getRenderContext().getFunctions().bindTexture(m_textureType, 0);
}
}
}
TestCase::IterateResult ImageBindingRenderCase::iterate (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const int iterations = m_numBindings;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
bool queryTestPassed = true;
bool imageTestPassed = true;
// Set the viewport and enable the shader program
initRenderState();
for (int iterNdx = 0; iterNdx < iterations; ++iterNdx)
{
// Set the uniform value indicating the current array index
gl.uniform1i(m_shaderProgramArrayNdxLoc, iterNdx);
const std::string name = (arrayInstance ? getUniformName(m_uniformName, 0, iterNdx) : getUniformName(m_uniformName, iterNdx));
const glw::GLint binding = m_bindings[iterNdx];
glw::GLint val = -1;
gl.getUniformiv(m_program->getProgram(), gl.getUniformLocation(m_program->getProgram(), name.c_str()), &val);
m_testCtx.getLog() << tcu::TestLog::Message << "Querying binding point for " << name << ": " << val << " == " << binding << tcu::TestLog::EndMessage;
GLU_EXPECT_NO_ERROR(gl.getError(), "Binding point query failed");
// Draw and verify
if (val != binding)
queryTestPassed = false;
if (!drawAndVerifyResult(m_textureColors[iterNdx]))
imageTestPassed = false;
}
setTestResult(queryTestPassed, imageTestPassed);
return STOP;
}
void ImageBindingRenderCase::initializeImage (glw::GLint imageBindingPoint, glw::GLint textureBindingPoint, glw::GLint textureName, const Vec4& color) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.activeTexture(GL_TEXTURE0 + textureBindingPoint);
gl.bindTexture(m_textureType, textureName);
gl.texParameteri(m_textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
switch (m_textureType)
{
case GL_TEXTURE_2D:
{
tcu::TextureLevel level(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
tcu::clear(level.getAccess(), color);
gl.texStorage2D(m_textureType, 1, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
gl.texSubImage2D(m_textureType, 0, 0, 0, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, level.getAccess().getDataPtr());
break;
}
case GL_TEXTURE_3D:
{
tcu::TextureLevel level(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
tcu::clear(level.getAccess(), color);
gl.texStorage3D(m_textureType, 1, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE);
gl.texSubImage3D(m_textureType, 0, 0, 0, 0, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, level.getAccess().getDataPtr());
break;
}
default:
DE_ASSERT(false);
}
gl.bindTexture(m_textureType, 0);
gl.bindImageTexture(imageBindingPoint, textureName, 0, GL_TRUE, 0, GL_READ_ONLY, GL_RGBA8);
GLU_EXPECT_NO_ERROR(gl.getError(), "Image initialization failed");
}
glu::ShaderProgram* ImageBindingRenderCase::generateShaders (void) const
{
std::ostringstream shaderUniformDecl;
std::ostringstream shaderBody;
const std::string texCoordType = glu::getDataTypeName(getImageTexCoordType());
const std::string imageType = glu::getDataTypeName(glu::getDataTypeFromGLType(m_imageType));
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY) ? true : false;
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
shaderUniformDecl << "layout(rgba8, binding = " << m_bindings[declNdx] << ") uniform readonly highp " << imageType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings; ++bindNdx)
{
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = imageLoad(" << (arrayInstance ? getUniformName(m_uniformName, 0, bindNdx) : getUniformName(m_uniformName, bindNdx)) << ", " << texCoordType << "(0));\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str())));
}
glu::DataType ImageBindingRenderCase::getImageTexCoordType(void) const
{
switch (m_imageType)
{
case GL_IMAGE_2D:
return glu::TYPE_INT_VEC2;
case GL_IMAGE_3D:
return glu::TYPE_INT_VEC3;
default:
DE_ASSERT(false);
return glu::TYPE_INVALID;
}
}
class ImageBindingNegativeCase : public LayoutBindingNegativeCase
{
public:
ImageBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum imageType);
~ImageBindingNegativeCase (void);
private:
glu::ShaderProgram* generateShaders (void) const;
glu::DataType getImageTexCoordType (void) const;
const glw::GLenum m_imageType;
};
ImageBindingNegativeCase::ImageBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType,
glw::GLenum imageType)
: LayoutBindingNegativeCase (context,
name,
desc,
shaderType,
testType,
errorType,
GL_MAX_IMAGE_UNITS,
GL_MAX_VERTEX_IMAGE_UNIFORMS,
GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,
GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,
GL_MAX_FRAGMENT_IMAGE_UNIFORMS,
GL_MAX_COMBINED_IMAGE_UNIFORMS,
"u_image")
, m_imageType (imageType)
{
}
ImageBindingNegativeCase::~ImageBindingNegativeCase (void)
{
deinit();
}
glu::ShaderProgram* ImageBindingNegativeCase::generateShaders (void) const
{
std::ostringstream vertexUniformDecl;
std::ostringstream fragmentUniformDecl;
std::ostringstream tessCtrlUniformDecl;
std::ostringstream tessEvalUniformDecl;
std::ostringstream shaderBody;
const std::string texCoordType = glu::getDataTypeName(getImageTexCoordType());
const std::string imageType = glu::getDataTypeName(glu::getDataTypeFromGLType(m_imageType));
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
vertexUniformDecl << "layout(rgba8, binding = " << m_vertexShaderBinding[declNdx] << ") uniform readonly highp " << imageType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
fragmentUniformDecl << "layout(rgba8, binding = " << m_fragmentShaderBinding[declNdx] << ") uniform readonly highp " << imageType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
tessCtrlUniformDecl << "layout(rgba8, binding = " << m_tessCtrlShaderBinding[declNdx] << ") uniform readonly highp " << imageType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
tessEvalUniformDecl << "layout(rgba8, binding = " << m_tessEvalShaderBinding[declNdx] << ") uniform readonly highp " << imageType
<< " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings; ++bindNdx)
{
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = imageLoad(" << (arrayInstance ? getUniformName(m_uniformName, 0, bindNdx) : getUniformName(m_uniformName, bindNdx)) << ", " << texCoordType << "(0));\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
glu::ProgramSources sources = glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, vertexUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, fragmentUniformDecl.str(), shaderBody.str()));
if (m_tessSupport)
sources << glu::TessellationControlSource(generateTessControlShader(m_shaderType, tessCtrlUniformDecl.str(), shaderBody.str()))
<< glu::TessellationEvaluationSource(generateTessEvaluationShader(m_shaderType, tessEvalUniformDecl.str(), shaderBody.str()));
return new glu::ShaderProgram(m_context.getRenderContext(), sources);
}
glu::DataType ImageBindingNegativeCase::getImageTexCoordType(void) const
{
switch (m_imageType)
{
case GL_IMAGE_2D:
return glu::TYPE_INT_VEC2;
case GL_IMAGE_3D:
return glu::TYPE_INT_VEC3;
default:
DE_ASSERT(false);
return glu::TYPE_INVALID;
}
}
class UBOBindingRenderCase : public LayoutBindingRenderCase
{
public:
UBOBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType);
~UBOBindingRenderCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
glu::ShaderProgram* generateShaders (void) const;
std::vector<deUint32> m_buffers;
std::vector<Vec4> m_expectedColors;
};
UBOBindingRenderCase::UBOBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType)
: LayoutBindingRenderCase (context, name, desc, shaderType, testType, GL_MAX_UNIFORM_BUFFER_BINDINGS, GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, GL_MAX_COMBINED_UNIFORM_BLOCKS, "ColorBlock")
{
}
UBOBindingRenderCase::~UBOBindingRenderCase (void)
{
deinit();
}
void UBOBindingRenderCase::init (void)
{
LayoutBindingRenderCase::init();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
// Initialize UBOs and related data
m_buffers = std::vector<glw::GLuint>(m_numBindings, 0);
gl.genBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
m_expectedColors.push_back(getRandomColor(rnd));
m_expectedColors.push_back(getRandomColor(rnd));
}
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
gl.bindBuffer(GL_UNIFORM_BUFFER, m_buffers[bufNdx]);
gl.bufferData(GL_UNIFORM_BUFFER, 2*sizeof(Vec4), &(m_expectedColors[2*bufNdx]), GL_STATIC_DRAW);
gl.bindBufferBase(GL_UNIFORM_BUFFER, m_bindings[bufNdx], m_buffers[bufNdx]);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "UBO setup failed");
}
void UBOBindingRenderCase::deinit (void)
{
LayoutBindingRenderCase::deinit();
// Clean up UBO data
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
if (m_buffers[bufNdx])
{
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffers[bufNdx]);
m_context.getRenderContext().getFunctions().bindBuffer(GL_UNIFORM_BUFFER, 0);
}
}
}
TestCase::IterateResult UBOBindingRenderCase::iterate (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const int iterations = m_numBindings;
const glw::GLenum prop = GL_BUFFER_BINDING;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
bool queryTestPassed = true;
bool imageTestPassed = true;
// Set the viewport and enable the shader program
initRenderState();
for (int iterNdx = 0; iterNdx < iterations; ++iterNdx)
{
// Query binding point
const std::string name = (arrayInstance ? getUniformName(m_uniformName, 0, iterNdx) : getUniformName(m_uniformName, iterNdx));
const glw::GLint binding = m_bindings[iterNdx];
glw::GLint val = -1;
gl.getProgramResourceiv(m_program->getProgram(), GL_UNIFORM_BLOCK, gl.getProgramResourceIndex(m_program->getProgram(), GL_UNIFORM_BLOCK, name.c_str() ), 1, &prop, 1, DE_NULL, &val);
m_testCtx.getLog() << tcu::TestLog::Message << "Querying binding point for " << name << ": " << val << " == " << binding << tcu::TestLog::EndMessage;
GLU_EXPECT_NO_ERROR(gl.getError(), "Binding point query failed");
if (val != binding)
queryTestPassed = false;
// Draw twice to render both colors within the UBO
for (int drawCycle = 0; drawCycle < 2; ++drawCycle)
{
// Set the uniform indicating the array index to be used and set the expected color
const int arrayNdx = iterNdx*2 + drawCycle;
gl.uniform1i(m_shaderProgramArrayNdxLoc, arrayNdx);
if (!drawAndVerifyResult(m_expectedColors[arrayNdx]))
imageTestPassed = false;
}
}
setTestResult(queryTestPassed, imageTestPassed);
return STOP;
}
glu::ShaderProgram* UBOBindingRenderCase::generateShaders (void) const
{
std::ostringstream shaderUniformDecl;
std::ostringstream shaderBody;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
shaderUniformDecl << "layout(std140, binding = " << m_bindings[declNdx] << ") uniform "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings*2; ++bindNdx) // Multiply by two to cover cases for both colors for each UBO
{
const std::string uname = (arrayInstance ? getUniformName("colors", 0, bindNdx/2) : getUniformName("colors", bindNdx/2));
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = " << uname << (bindNdx%2 == 0 ? ".color1" : ".color2") << ";\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str())));
}
class UBOBindingNegativeCase : public LayoutBindingNegativeCase
{
public:
UBOBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType);
~UBOBindingNegativeCase (void);
private:
glu::ShaderProgram* generateShaders (void) const;
};
UBOBindingNegativeCase::UBOBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType)
: LayoutBindingNegativeCase(context,
name,
desc,
shaderType,
testType,
errorType,
GL_MAX_UNIFORM_BUFFER_BINDINGS,
GL_MAX_VERTEX_UNIFORM_BLOCKS,
GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,
GL_MAX_FRAGMENT_UNIFORM_BLOCKS,
GL_MAX_COMBINED_UNIFORM_BLOCKS,
"ColorBlock")
{
}
UBOBindingNegativeCase::~UBOBindingNegativeCase (void)
{
deinit();
}
glu::ShaderProgram* UBOBindingNegativeCase::generateShaders (void) const
{
std::ostringstream vertexUniformDecl;
std::ostringstream fragmentUniformDecl;
std::ostringstream tessCtrlUniformDecl;
std::ostringstream tessEvalUniformDecl;
std::ostringstream shaderBody;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
vertexUniformDecl << "layout(std140, binding = " << m_vertexShaderBinding[declNdx] << ") uniform "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
fragmentUniformDecl << "layout(std140, binding = " << m_fragmentShaderBinding[declNdx] << ") uniform "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
tessCtrlUniformDecl << "layout(std140, binding = " << m_tessCtrlShaderBinding[declNdx] << ") uniform "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
tessEvalUniformDecl << "layout(std140, binding = " << m_tessCtrlShaderBinding[declNdx] << ") uniform "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings*2; ++bindNdx) // Multiply by two to cover cases for both colors for each UBO
{
const std::string uname = (arrayInstance ? getUniformName("colors", 0, bindNdx/2) : getUniformName("colors", bindNdx/2));
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = " << uname << (bindNdx%2 == 0 ? ".color1" : ".color2") << ";\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
glu::ProgramSources sources = glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, vertexUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, fragmentUniformDecl.str(), shaderBody.str()));
if (m_tessSupport)
sources << glu::TessellationControlSource(generateTessControlShader(m_shaderType, tessCtrlUniformDecl.str(), shaderBody.str()))
<< glu::TessellationEvaluationSource(generateTessEvaluationShader(m_shaderType, tessEvalUniformDecl.str(), shaderBody.str()));
return new glu::ShaderProgram(m_context.getRenderContext(), sources);
}
class SSBOBindingRenderCase : public LayoutBindingRenderCase
{
public:
SSBOBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType);
~SSBOBindingRenderCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
glu::ShaderProgram* generateShaders (void) const;
std::vector<glw::GLuint> m_buffers;
std::vector<Vec4> m_expectedColors;
};
SSBOBindingRenderCase::SSBOBindingRenderCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType)
: LayoutBindingRenderCase (context, name, desc, shaderType, testType, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, "ColorBuffer")
{
}
SSBOBindingRenderCase::~SSBOBindingRenderCase (void)
{
deinit();
}
void SSBOBindingRenderCase::init (void)
{
LayoutBindingRenderCase::init();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
// Initialize SSBOs and related data
m_buffers = std::vector<glw::GLuint>(m_numBindings, 0);
gl.genBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
m_expectedColors.push_back(getRandomColor(rnd));
m_expectedColors.push_back(getRandomColor(rnd));
}
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffers[bufNdx]);
gl.bufferData(GL_SHADER_STORAGE_BUFFER, 2*sizeof(Vec4), &(m_expectedColors[2*bufNdx]), GL_STATIC_DRAW);
gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, m_bindings[bufNdx], m_buffers[bufNdx]);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "SSBO setup failed");
}
void SSBOBindingRenderCase::deinit (void)
{
LayoutBindingRenderCase::deinit();
// Clean up SSBO data
for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx)
{
if (m_buffers[bufNdx])
{
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffers[bufNdx]);
m_context.getRenderContext().getFunctions().bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
m_buffers[bufNdx] = 0;
}
}
}
TestCase::IterateResult SSBOBindingRenderCase::iterate (void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const int iterations = m_numBindings;
const glw::GLenum prop = GL_BUFFER_BINDING;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
bool queryTestPassed = true;
bool imageTestPassed = true;
initRenderState();
for (int iterNdx = 0; iterNdx < iterations; ++iterNdx)
{
// Query binding point
const std::string name = (arrayInstance ? getUniformName(m_uniformName, 0, iterNdx) : getUniformName(m_uniformName, iterNdx));
const glw::GLint binding = m_bindings[iterNdx];
glw::GLint val = -1;
gl.getProgramResourceiv(m_program->getProgram(), GL_SHADER_STORAGE_BLOCK, gl.getProgramResourceIndex(m_program->getProgram(), GL_SHADER_STORAGE_BLOCK, name.c_str() ), 1, &prop, 1, DE_NULL, &val);
m_testCtx.getLog() << tcu::TestLog::Message << "Querying binding point for " << name << ": " << val << " == " << binding << tcu::TestLog::EndMessage;
GLU_EXPECT_NO_ERROR(gl.getError(), "Binding point query failed");
if (val != binding)
queryTestPassed = false;
// Draw twice to render both colors within the SSBO
for (int drawCycle = 0; drawCycle < 2; ++drawCycle)
{
// Set the uniform indicating the array index to be used and set the expected color
const int arrayNdx = iterNdx*2 + drawCycle;
gl.uniform1i(m_shaderProgramArrayNdxLoc, arrayNdx);
if (!drawAndVerifyResult(m_expectedColors[arrayNdx]))
imageTestPassed = false;
}
}
setTestResult(queryTestPassed, imageTestPassed);
return STOP;
}
glu::ShaderProgram* SSBOBindingRenderCase::generateShaders (void) const
{
std::ostringstream shaderUniformDecl;
std::ostringstream shaderBody;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
shaderUniformDecl << "layout(std140, binding = " << m_bindings[declNdx] << ") buffer "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings*2; ++bindNdx) // Multiply by two to cover cases for both colors for each UBO
{
const std::string uname = (arrayInstance ? getUniformName("colors", 0, bindNdx/2) : getUniformName("colors", bindNdx/2));
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = " << uname << (bindNdx%2 == 0 ? ".color1" : ".color2") << ";\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, shaderUniformDecl.str(), shaderBody.str())));
}
class SSBOBindingNegativeCase : public LayoutBindingNegativeCase
{
public:
SSBOBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType);
~SSBOBindingNegativeCase (void);
private:
glu::ShaderProgram* generateShaders (void) const;
};
SSBOBindingNegativeCase::SSBOBindingNegativeCase (Context& context,
const char* name,
const char* desc,
ShaderType shaderType,
TestType testType,
ErrorType errorType)
: LayoutBindingNegativeCase(context,
name,
desc,
shaderType,
testType,
errorType,
GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,
"ColorBuffer")
{
}
SSBOBindingNegativeCase::~SSBOBindingNegativeCase (void)
{
deinit();
}
glu::ShaderProgram* SSBOBindingNegativeCase::generateShaders (void) const
{
std::ostringstream vertexUniformDecl;
std::ostringstream fragmentUniformDecl;
std::ostringstream tessCtrlUniformDecl;
std::ostringstream tessEvalUniformDecl;
std::ostringstream shaderBody;
const bool arrayInstance = (m_testType == TESTTYPE_BINDING_ARRAY || m_testType == TESTTYPE_BINDING_MAX_ARRAY);
const int numDeclarations = (arrayInstance ? 1 : m_numBindings);
// Generate the uniform declarations for the vertex and fragment shaders
for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
{
vertexUniformDecl << "layout(std140, binding = " << m_vertexShaderBinding[declNdx] << ") buffer "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
fragmentUniformDecl << "layout(std140, binding = " << m_fragmentShaderBinding[declNdx] << ") buffer "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
tessCtrlUniformDecl << "layout(std140, binding = " << m_tessCtrlShaderBinding[declNdx] << ") buffer "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
tessEvalUniformDecl << "layout(std140, binding = " << m_tessEvalShaderBinding[declNdx] << ") buffer "
<< getUniformName(m_uniformName, declNdx) << "\n"
<< "{\n"
<< " highp vec4 color1;\n"
<< " highp vec4 color2;\n"
<< "} " << (arrayInstance ? getUniformName("colors", declNdx, m_numBindings) : getUniformName("colors", declNdx)) << ";\n";
}
// Generate the shader body for the vertex and fragment shaders
for (int bindNdx = 0; bindNdx < m_numBindings*2; ++bindNdx) // Multiply by two to cover cases for both colors for each UBO
{
const std::string uname = (arrayInstance ? getUniformName("colors", 0, bindNdx/2) : getUniformName("colors", bindNdx/2));
shaderBody << " " << (bindNdx == 0 ? "if" : "else if") << " (u_arrayNdx == " << de::toString(bindNdx) << ")\n"
<< " {\n"
<< " color = " << uname << (bindNdx%2 == 0 ? ".color1" : ".color2") << ";\n"
<< " }\n";
}
shaderBody << " else\n"
<< " {\n"
<< " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< " }\n";
glu::ProgramSources sources = glu::ProgramSources()
<< glu::VertexSource(generateVertexShader(m_shaderType, vertexUniformDecl.str(), shaderBody.str()))
<< glu::FragmentSource(generateFragmentShader(m_shaderType, fragmentUniformDecl.str(), shaderBody.str()));
if (m_tessSupport)
sources << glu::TessellationControlSource(generateTessControlShader(m_shaderType, tessCtrlUniformDecl.str(), shaderBody.str()))
<< glu::TessellationEvaluationSource(generateTessEvaluationShader(m_shaderType, tessEvalUniformDecl.str(), shaderBody.str()));
return new glu::ShaderProgram(m_context.getRenderContext(), sources);
}
} // Anonymous
LayoutBindingTests::LayoutBindingTests (Context& context)
: TestCaseGroup (context, "layout_binding", "Layout binding tests")
{
}
LayoutBindingTests::~LayoutBindingTests (void)
{
}
void LayoutBindingTests::init (void)
{
// Render test groups
tcu::TestCaseGroup* const samplerBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Test sampler layout binding");
tcu::TestCaseGroup* const sampler2dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler2d", "Test sampler2d layout binding");
tcu::TestCaseGroup* const sampler3dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler3d", "Test sampler3d layout binding");
tcu::TestCaseGroup* const imageBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image", "Test image layout binding");
tcu::TestCaseGroup* const image2dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image2d", "Test image2d layout binding");
tcu::TestCaseGroup* const image3dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image3d", "Test image3d layout binding");
tcu::TestCaseGroup* const UBOBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Test UBO layout binding");
tcu::TestCaseGroup* const SSBOBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Test SSBO layout binding");
// Negative test groups
tcu::TestCaseGroup* const negativeBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Test layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeSamplerBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Test sampler layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeSampler2dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler2d", "Test sampler2d layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeSampler3dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "sampler3d", "Test sampler3d layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeImageBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image", "Test image layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeImage2dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image2d", "Test image2d layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeImage3dBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "image3d", "Test image3d layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeUBOBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Test UBO layout binding with invalid bindings");
tcu::TestCaseGroup* const negativeSSBOBindingTestGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Test SSBO layout binding with invalid bindings");
static const struct RenderTestType
{
ShaderType shaderType;
TestType testType;
std::string name;
std::string descPostfix;
} s_renderTestTypes[] =
{
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_SINGLE, "vertex_binding_single", "a single instance" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_MAX, "vertex_binding_max", "maximum binding point" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_MULTIPLE, "vertex_binding_multiple", "multiple instances"},
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_ARRAY, "vertex_binding_array", "an array instance" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_MAX_ARRAY, "vertex_binding_max_array", "an array instance with maximum binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_SINGLE, "fragment_binding_single", "a single instance" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_MAX, "fragment_binding_max", "maximum binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_MULTIPLE, "fragment_binding_multiple", "multiple instances"},
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_ARRAY, "fragment_binding_array", "an array instance" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_MAX_ARRAY, "fragment_binding_max_array", "an array instance with maximum binding point" },
};
static const struct NegativeTestType
{
ShaderType shaderType;
TestType testType;
LayoutBindingNegativeCase::ErrorType errorType;
std::string name;
std::string descPostfix;
} s_negativeTestTypes[] =
{
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "vertex_binding_over_max", "over maximum binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "fragment_binding_over_max", "over maximum binding point" },
{ SHADERTYPE_TESS_CONTROL, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "tess_control_binding_over_max", "over maximum binding point" },
{ SHADERTYPE_TESS_EVALUATION, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "tess_evaluation_binding_over_max", "over maximum binding point" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "vertex_binding_neg", "negative binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "fragment_binding_neg", "negative binding point" },
{ SHADERTYPE_TESS_CONTROL, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "tess_control_binding_neg", "negative binding point" },
{ SHADERTYPE_TESS_EVALUATION, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "tess_evaluation_binding_neg", "negative binding point" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "vertex_binding_over_max_array", "over maximum binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "fragment_binding_over_max_array", "over maximum binding point" },
{ SHADERTYPE_TESS_CONTROL, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "tess_control_binding_over_max_array", "over maximum binding point" },
{ SHADERTYPE_TESS_EVALUATION, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_OVER_MAX_UNITS, "tess_evaluation_binding_over_max_array", "over maximum binding point" },
{ SHADERTYPE_VERTEX, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "vertex_binding_neg_array", "negative binding point" },
{ SHADERTYPE_FRAGMENT, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "fragment_binding_neg_array", "negative binding point" },
{ SHADERTYPE_TESS_CONTROL, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "tess_control_binding_neg_array", "negative binding point" },
{ SHADERTYPE_TESS_EVALUATION, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_LESS_THAN_ZERO, "tess_evaluation_binding_neg_array", "negative binding point" },
{ SHADERTYPE_ALL, TESTTYPE_BINDING_SINGLE, LayoutBindingNegativeCase::ERRORTYPE_CONTRADICTORY, "binding_contradictory", "contradictory binding points" },
{ SHADERTYPE_ALL, TESTTYPE_BINDING_ARRAY, LayoutBindingNegativeCase::ERRORTYPE_CONTRADICTORY, "binding_contradictory_array", "contradictory binding points" },
};
// Render tests
for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_renderTestTypes); ++testNdx)
{
const RenderTestType& test = s_renderTestTypes[testNdx];
// Render sampler binding tests
sampler2dBindingTestGroup->addChild(new SamplerBindingRenderCase(m_context, test.name.c_str(), ("Sampler2D layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType, GL_SAMPLER_2D, GL_TEXTURE_2D));
sampler3dBindingTestGroup->addChild(new SamplerBindingRenderCase(m_context, test.name.c_str(), ("Sampler3D layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType, GL_SAMPLER_3D, GL_TEXTURE_3D));
// Render image binding tests
image2dBindingTestGroup->addChild(new ImageBindingRenderCase(m_context, test.name.c_str(), ("Image2D layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType, GL_IMAGE_2D, GL_TEXTURE_2D));
image3dBindingTestGroup->addChild(new ImageBindingRenderCase(m_context, test.name.c_str(), ("Image3D layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType, GL_IMAGE_3D, GL_TEXTURE_3D));
// Render UBO binding tests
UBOBindingTestGroup->addChild(new UBOBindingRenderCase(m_context, test.name.c_str(), ("UBO layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType));
// Render SSBO binding tests
SSBOBindingTestGroup->addChild(new SSBOBindingRenderCase(m_context, test.name.c_str(), ("SSBO layout binding with " + test.descPostfix).c_str(), test.shaderType, test.testType));
}
// Negative binding tests
for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_negativeTestTypes); ++testNdx)
{
const NegativeTestType& test = s_negativeTestTypes[testNdx];
// Negative sampler binding tests
negativeSampler2dBindingTestGroup->addChild(new SamplerBindingNegativeCase(m_context, test.name.c_str(), ("Invalid sampler2d layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType, GL_SAMPLER_2D));
negativeSampler3dBindingTestGroup->addChild(new SamplerBindingNegativeCase(m_context, test.name.c_str(), ("Invalid sampler3d layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType, GL_SAMPLER_3D));
// Negative image binding tests
negativeImage2dBindingTestGroup->addChild(new ImageBindingNegativeCase(m_context, test.name.c_str(), ("Invalid image2d layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType, GL_IMAGE_2D));
negativeImage3dBindingTestGroup->addChild(new ImageBindingNegativeCase(m_context, test.name.c_str(), ("Invalid image3d layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType, GL_IMAGE_3D));
// Negative UBO binding tests
negativeUBOBindingTestGroup->addChild(new UBOBindingNegativeCase(m_context, test.name.c_str(), ("Invalid UBO layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType));
// Negative SSBO binding tests
negativeSSBOBindingTestGroup->addChild(new SSBOBindingNegativeCase(m_context, test.name.c_str(), ("Invalid SSBO layout binding using " + test.descPostfix).c_str(), test.shaderType, test.testType, test.errorType));
}
samplerBindingTestGroup->addChild(sampler2dBindingTestGroup);
samplerBindingTestGroup->addChild(sampler3dBindingTestGroup);
imageBindingTestGroup->addChild(image2dBindingTestGroup);
imageBindingTestGroup->addChild(image3dBindingTestGroup);
negativeSamplerBindingTestGroup->addChild(negativeSampler2dBindingTestGroup);
negativeSamplerBindingTestGroup->addChild(negativeSampler3dBindingTestGroup);
negativeImageBindingTestGroup->addChild(negativeImage2dBindingTestGroup);
negativeImageBindingTestGroup->addChild(negativeImage3dBindingTestGroup);
negativeBindingTestGroup->addChild(negativeSamplerBindingTestGroup);
negativeBindingTestGroup->addChild(negativeUBOBindingTestGroup);
negativeBindingTestGroup->addChild(negativeSSBOBindingTestGroup);
negativeBindingTestGroup->addChild(negativeImageBindingTestGroup);
addChild(samplerBindingTestGroup);
addChild(UBOBindingTestGroup);
addChild(SSBOBindingTestGroup);
addChild(imageBindingTestGroup);
addChild(negativeBindingTestGroup);
}
} // Functional
} // gles31
} // deqp