blob: 93e8a4850e1c6ef4c8bdeb8e29286172078f65d1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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_vao;
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_vao(0)
, 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 uint32_t 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 uint16_t indices[] = {
0, 1, 2, 0, 2, 3,
};
TCU_CHECK((m_shaderProgramPosLoc >= 0) && (m_shaderProgramArrayNdxLoc >= 0));
// Generate and bind vao
if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
{
gl.genVertexArrays(1, &m_vao);
gl.bindVertexArray(m_vao);
}
// 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_vao)
m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
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<uint32_t> lowBindingPoints;
std::vector<uint32_t> 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)) ||
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
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<uint32_t> 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);
}
} // namespace
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);
}
} // namespace Functional
} // namespace gles31
} // namespace deqp