blob: d6f9a41b1c38394fa8044f54f81bed91340612fb [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2015-2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief
*/ /*-------------------------------------------------------------------*/
/**
* \file gl4cMultiBindTests.cpp
* \brief Implements conformance tests for "Multi Bind" functionality.
*/ /*-------------------------------------------------------------------*/
#include "gl4cMultiBindTests.hpp"
#include "gluDefs.hpp"
#include "gluStrUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <string>
#define DEBUG_ENBALE_MESSAGE_CALLBACK 0
#if DEBUG_ENBALE_MESSAGE_CALLBACK
#include <iomanip>
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
using namespace glw;
namespace gl4cts
{
namespace MultiBind
{
#if DEBUG_ENBALE_MESSAGE_CALLBACK
/** Debuging procedure. Logs parameters.
*
* @param source As specified in GL spec.
* @param type As specified in GL spec.
* @param id As specified in GL spec.
* @param severity As specified in GL spec.
* @param ignored
* @param message As specified in GL spec.
* @param info Pointer to instance of deqp::Context used by test.
*/
void GLW_APIENTRY debug_proc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /* length */,
const GLchar* message, void* info)
{
deqp::Context* ctx = (deqp::Context*)info;
const GLchar* source_str = "Unknown";
const GLchar* type_str = "Unknown";
const GLchar* severity_str = "Unknown";
switch (source)
{
case GL_DEBUG_SOURCE_API:
source_str = "API";
break;
case GL_DEBUG_SOURCE_APPLICATION:
source_str = "APP";
break;
case GL_DEBUG_SOURCE_OTHER:
source_str = "OTR";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
source_str = "COM";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
source_str = "3RD";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
source_str = "WS";
break;
default:
break;
}
switch (type)
{
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
type_str = "DEPRECATED_BEHAVIOR";
break;
case GL_DEBUG_TYPE_ERROR:
type_str = "ERROR";
break;
case GL_DEBUG_TYPE_MARKER:
type_str = "MARKER";
break;
case GL_DEBUG_TYPE_OTHER:
type_str = "OTHER";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
type_str = "PERFORMANCE";
break;
case GL_DEBUG_TYPE_POP_GROUP:
type_str = "POP_GROUP";
break;
case GL_DEBUG_TYPE_PORTABILITY:
type_str = "PORTABILITY";
break;
case GL_DEBUG_TYPE_PUSH_GROUP:
type_str = "PUSH_GROUP";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
type_str = "UNDEFINED_BEHAVIOR";
break;
default:
break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
severity_str = "H";
break;
case GL_DEBUG_SEVERITY_LOW:
severity_str = "L";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
severity_str = "M";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severity_str = "N";
break;
default:
break;
}
ctx->getTestContext().getLog() << tcu::TestLog::Message << "DEBUG_INFO: " << std::setw(3) << source_str << "|"
<< severity_str << "|" << std::setw(18) << type_str << "|" << std::setw(12) << id
<< ": " << message << tcu::TestLog::EndMessage;
}
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
/** Represents buffer instance
* Provides basic buffer functionality
**/
class Buffer
{
public:
/* Public methods */
/* Ctr & Dtr */
Buffer();
~Buffer();
/* Init & Release */
void Init(deqp::Context& context);
void InitData(deqp::Context& context, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
const glw::GLvoid* data);
void Release();
/* Functionality */
void Bind() const;
void BindBase(glw::GLuint index) const;
/* Public static routines */
/* Functionality */
static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target);
static void BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index);
static void Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
const glw::GLvoid* data);
static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
static void SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
glw::GLvoid* data);
/* Public fields */
glw::GLuint m_id;
/* Public constants */
static const glw::GLuint m_invalid_id;
private:
/* Private enums */
/* Private fields */
deqp::Context* m_context;
glw::GLenum m_target;
};
/** Represents framebuffer
* Provides basic functionality
**/
class Framebuffer
{
public:
/* Public methods */
/* Ctr & Dtr */
Framebuffer(deqp::Context& context);
~Framebuffer();
/* Init & Release */
void Release();
/* Public static routines */
static void AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height);
static void Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id);
static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
/* Public fields */
glw::GLuint m_id;
/* Public constants */
static const glw::GLuint m_invalid_id;
private:
/* Private fields */
deqp::Context& m_context;
};
/** Represents shader instance.
* Provides basic functionality for shaders.
**/
class Shader
{
public:
/* Public methods */
/* Ctr & Dtr */
Shader(deqp::Context& context);
~Shader();
/* Init & Realese */
void Init(glw::GLenum stage, const std::string& source);
void Release();
/* Public static routines */
/* Functionality */
static void Compile(const glw::Functions& gl, glw::GLuint id);
static void Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id);
static void Source(const glw::Functions& gl, glw::GLuint id, const std::string& source);
/* Public fields */
glw::GLuint m_id;
/* Public constants */
static const glw::GLuint m_invalid_id;
private:
/* Private fields */
deqp::Context& m_context;
};
/** Represents program instance.
* Provides basic functionality
**/
class Program
{
public:
/* Public methods */
/* Ctr & Dtr */
Program(deqp::Context& context);
~Program();
/* Init & Release */
void Init(const std::string& compute_shader, const std::string& fragment_shader, const std::string& geometry_shader,
const std::string& tesselation_control_shader, const std::string& tesselation_evaluation_shader,
const std::string& vertex_shader);
void Release();
/* Functionality */
void Use() const;
/* Public static routines */
/* Functionality */
static void Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id);
static void Create(const glw::Functions& gl, glw::GLuint& out_id);
static void Link(const glw::Functions& gl, glw::GLuint id);
static void Use(const glw::Functions& gl, glw::GLuint id);
/* Public fields */
glw::GLuint m_id;
Shader m_compute;
Shader m_fragment;
Shader m_geometry;
Shader m_tess_ctrl;
Shader m_tess_eval;
Shader m_vertex;
/* Public constants */
static const glw::GLuint m_invalid_id;
private:
/* Private fields */
deqp::Context& m_context;
};
/** Represents texture instance
**/
class Texture
{
public:
/* Public methods */
/* Ctr & Dtr */
Texture();
~Texture();
/* Init & Release */
void Init(deqp::Context& context);
void InitBuffer(deqp::Context& context, glw::GLenum internal_format, glw::GLuint buffer_id);
void InitStorage(deqp::Context& context, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error = false);
void Release();
/* Public static routines */
/* Functionality */
static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target);
static void CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
glw::GLsizei image_size, const glw::GLvoid* data);
static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
static void GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
glw::GLenum type, glw::GLvoid* out_data);
static void GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
glw::GLint* param);
static void Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
const glw::GLvoid* data);
static void Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error);
static void SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
glw::GLenum type, const glw::GLvoid* pixels);
/* Public fields */
glw::GLuint m_id;
/* Public constants */
static const glw::GLuint m_invalid_id;
private:
/* Private fields */
deqp::Context* m_context;
};
/* Buffer constants */
const GLuint Buffer::m_invalid_id = -1;
/** Constructor.
*
**/
Buffer::Buffer() : m_id(m_invalid_id), m_context(0), m_target(GL_ARRAY_BUFFER)
{
}
/** Destructor
*
**/
Buffer::~Buffer()
{
Release();
m_context = 0;
}
/** Initialize buffer instance
*
* @param context CTS context.
**/
void Buffer::Init(deqp::Context& context)
{
Release();
m_context = &context;
}
/** Initialize buffer instance with some data
*
* @param context CTS context.
* @param target Buffer target
* @param usage Buffer usage enum
* @param size <size> parameter
* @param data <data> parameter
**/
void Buffer::InitData(deqp::Context& context, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
const glw::GLvoid* data)
{
Init(context);
m_target = target;
const Functions& gl = m_context->getRenderContext().getFunctions();
Generate(gl, m_id);
Bind(gl, m_id, m_target);
Data(gl, m_target, usage, size, data);
}
/** Release buffer instance
*
**/
void Buffer::Release()
{
if (m_invalid_id != m_id)
{
const Functions& gl = m_context->getRenderContext().getFunctions();
gl.deleteBuffers(1, &m_id);
m_id = m_invalid_id;
}
}
/** Binds buffer to its target
*
**/
void Buffer::Bind() const
{
if (m_invalid_id == m_id)
{
return;
}
const Functions& gl = m_context->getRenderContext().getFunctions();
Bind(gl, m_id, m_target);
}
/** Binds indexed buffer
*
* @param index <index> parameter
**/
void Buffer::BindBase(glw::GLuint index) const
{
if (m_invalid_id == m_id)
{
return;
}
const Functions& gl = m_context->getRenderContext().getFunctions();
BindBase(gl, m_id, m_target, index);
}
/** Bind buffer to given target
*
* @param gl GL functions
* @param id Id of buffer
* @param target Buffer target
**/
void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
{
gl.bindBuffer(target, id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
}
/** Binds indexed buffer
*
* @param gl GL functions
* @param id Id of buffer
* @param target Buffer target
* @param index <index> parameter
**/
void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index)
{
gl.bindBufferBase(target, index, id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
}
/** Allocate memory for buffer and sends initial content
*
* @param gl GL functions
* @param target Buffer target
* @param usage Buffer usage enum
* @param size <size> parameter
* @param data <data> parameter
**/
void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
const glw::GLvoid* data)
{
gl.bufferData(target, size, data, usage);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
}
/** Generate buffer
*
* @param gl GL functions
* @param out_id Id of buffer
**/
void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
{
GLuint id = m_invalid_id;
gl.genBuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
if (m_invalid_id == id)
{
TCU_FAIL("Got invalid id");
}
out_id = id;
}
/** Update range of buffer
*
* @param gl GL functions
* @param target Buffer target
* @param offset Offset in buffer
* @param size <size> parameter
* @param data <data> parameter
**/
void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
glw::GLvoid* data)
{
gl.bufferSubData(target, offset, size, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData");
}
/* Framebuffer constants */
const GLuint Framebuffer::m_invalid_id = -1;
/** Constructor.
*
* @param context CTS context.
**/
Framebuffer::Framebuffer(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
{
/* Nothing to done here */
}
/** Destructor
*
**/
Framebuffer::~Framebuffer()
{
Release();
}
/** Release texture instance
*
**/
void Framebuffer::Release()
{
if (m_invalid_id != m_id)
{
const Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteFramebuffers(1, &m_id);
m_id = m_invalid_id;
}
}
/** Attach texture to specified attachment
*
* @param gl GL functions
* @param target Framebuffer target
* @param attachment Attachment
* @param texture_id Texture id
* @param level Level of mipmap
* @param width Texture width
* @param height Texture height
**/
void Framebuffer::AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height)
{
gl.framebufferTexture(target, attachment, texture_id, level);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
gl.viewport(0 /* x */, 0 /* y */, width, height);
GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
}
/** Binds framebuffer to DRAW_FRAMEBUFFER
*
* @param gl GL functions
* @param target Framebuffer target
* @param id ID of framebuffer
**/
void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id)
{
gl.bindFramebuffer(target, id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
}
/** Generate framebuffer
*
**/
void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
{
GLuint id = m_invalid_id;
gl.genFramebuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
if (m_invalid_id == id)
{
TCU_FAIL("Invalid id");
}
out_id = id;
}
/* Program constants */
const GLuint Program::m_invalid_id = 0;
/** Constructor.
*
* @param context CTS context.
**/
Program::Program(deqp::Context& context)
: m_id(m_invalid_id)
, m_compute(context)
, m_fragment(context)
, m_geometry(context)
, m_tess_ctrl(context)
, m_tess_eval(context)
, m_vertex(context)
, m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Program::~Program()
{
Release();
}
/** Initialize program instance
*
* @param compute_shader Compute shader source code
* @param fragment_shader Fragment shader source code
* @param geometry_shader Geometry shader source code
* @param tesselation_control_shader Tesselation control shader source code
* @param tesselation_evaluation_shader Tesselation evaluation shader source code
* @param vertex_shader Vertex shader source code
**/
void Program::Init(const std::string& compute_shader, const std::string& fragment_shader,
const std::string& geometry_shader, const std::string& tesselation_control_shader,
const std::string& tesselation_evaluation_shader, const std::string& vertex_shader)
{
/* Delete previous program */
Release();
/* GL entry points */
const Functions& gl = m_context.getRenderContext().getFunctions();
/* Initialize shaders */
m_compute.Init(GL_COMPUTE_SHADER, compute_shader);
m_fragment.Init(GL_FRAGMENT_SHADER, fragment_shader);
m_geometry.Init(GL_GEOMETRY_SHADER, geometry_shader);
m_tess_ctrl.Init(GL_TESS_CONTROL_SHADER, tesselation_control_shader);
m_tess_eval.Init(GL_TESS_EVALUATION_SHADER, tesselation_evaluation_shader);
m_vertex.Init(GL_VERTEX_SHADER, vertex_shader);
/* Create program, set up transform feedback and attach shaders */
Create(gl, m_id);
Attach(gl, m_id, m_compute.m_id);
Attach(gl, m_id, m_fragment.m_id);
Attach(gl, m_id, m_geometry.m_id);
Attach(gl, m_id, m_tess_ctrl.m_id);
Attach(gl, m_id, m_tess_eval.m_id);
Attach(gl, m_id, m_vertex.m_id);
/* Link program */
Link(gl, m_id);
}
/** Release program instance
*
**/
void Program::Release()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
if (m_invalid_id != m_id)
{
Use(gl, m_invalid_id);
gl.deleteProgram(m_id);
m_id = m_invalid_id;
}
m_compute.Release();
m_fragment.Release();
m_geometry.Release();
m_tess_ctrl.Release();
m_tess_eval.Release();
m_vertex.Release();
}
/** Set program as active
*
**/
void Program::Use() const
{
const Functions& gl = m_context.getRenderContext().getFunctions();
Use(gl, m_id);
}
/** Attach shader to program
*
* @param gl GL functions
* @param program_id Id of program
* @param shader_id Id of shader
**/
void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id)
{
/* Sanity checks */
if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id))
{
return;
}
gl.attachShader(program_id, shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
/** Create program instance
*
* @param gl GL functions
* @param out_id Id of program
**/
void Program::Create(const glw::Functions& gl, glw::GLuint& out_id)
{
const GLuint id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
if (m_invalid_id == id)
{
TCU_FAIL("Failed to create program");
}
out_id = id;
}
/** Link program
*
* @param gl GL functions
* @param id Id of program
**/
void Program::Link(const glw::Functions& gl, glw::GLuint id)
{
GLint status = GL_FALSE;
gl.linkProgram(id);
GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
/* Get link status */
gl.getProgramiv(id, GL_LINK_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
/* Log link error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::string message;
/* Get error log length */
gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
message.resize(length, 0);
/* Get error log */
gl.getProgramInfoLog(id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
TCU_FAIL(message.c_str());
}
}
/** Use program
*
* @param gl GL functions
* @param id Id of program
**/
void Program::Use(const glw::Functions& gl, glw::GLuint id)
{
gl.useProgram(id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
}
/* Shader's constants */
const GLuint Shader::m_invalid_id = 0;
/** Constructor.
*
* @param context CTS context.
**/
Shader::Shader(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Shader::~Shader()
{
Release();
}
/** Initialize shader instance
*
* @param stage Shader stage
* @param source Source code
**/
void Shader::Init(glw::GLenum stage, const std::string& source)
{
if (true == source.empty())
{
/* No source == no shader */
return;
}
/* Delete any previous shader */
Release();
/* Create, set source and compile */
const Functions& gl = m_context.getRenderContext().getFunctions();
Create(gl, stage, m_id);
Source(gl, m_id, source);
Compile(gl, m_id);
}
/** Release shader instance
*
**/
void Shader::Release()
{
if (m_invalid_id != m_id)
{
const Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteShader(m_id);
m_id = m_invalid_id;
}
}
/** Compile shader
*
* @param gl GL functions
* @param id Shader id
**/
void Shader::Compile(const glw::Functions& gl, glw::GLuint id)
{
GLint status = GL_FALSE;
/* Compile */
gl.compileShader(id);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
/* Get compilation status */
gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Log compilation error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::string message;
/* Error log length */
gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Prepare storage */
message.resize(length, 0);
/* Get error log */
gl.getShaderInfoLog(id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
TCU_FAIL(message.c_str());
}
}
/** Create shader
*
* @param gl GL functions
* @param stage Shader stage
* @param out_id Shader id
**/
void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id)
{
const GLuint id = gl.createShader(stage);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
if (m_invalid_id == id)
{
TCU_FAIL("Failed to create shader");
}
out_id = id;
}
/** Set shader's source code
*
* @param gl GL functions
* @param id Shader id
* @param source Shader source code
**/
void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source)
{
const GLchar* code = source.c_str();
gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
}
/* Texture static fields */
const GLuint Texture::m_invalid_id = -1;
/** Constructor.
*
**/
Texture::Texture() : m_id(m_invalid_id), m_context(0)
{
/* Nothing to done here */
}
/** Destructor
*
**/
Texture::~Texture()
{
Release();
}
/** Initialize texture instance
*
* @param context Test context
**/
void Texture::Init(deqp::Context& context)
{
Release();
m_context = &context;
}
/** Initialize texture instance as texture buffer
*
* @param context Test context
* @param internal_format Internal format of texture
* @param buufer_id ID of buffer that will be used as storage
**/
void Texture::InitBuffer(deqp::Context& context, glw::GLenum internal_format, glw::GLuint buffer_id)
{
Init(context);
const Functions& gl = m_context->getRenderContext().getFunctions();
Generate(gl, m_id);
Bind(gl, m_id, GL_TEXTURE_BUFFER);
Buffer::Bind(gl, buffer_id, GL_TEXTURE_BUFFER);
gl.texBuffer(GL_TEXTURE_BUFFER, internal_format, buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexBuffer");
}
/** Initialize texture instance with storage
*
* @param context Test context
* @param target Texture target
* @param levels Number of levels
* @param internal_format Internal format of texture
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
**/
void Texture::InitStorage(deqp::Context& context, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error)
{
Init(context);
const Functions& gl = m_context->getRenderContext().getFunctions();
Generate(gl, m_id);
Bind(gl, m_id, target);
Storage(gl, target, levels, internal_format, width, height, depth, allow_error);
}
/** Release texture instance
*
* @param context CTS context.
**/
void Texture::Release()
{
if (m_invalid_id != m_id)
{
const Functions& gl = m_context->getRenderContext().getFunctions();
gl.deleteTextures(1, &m_id);
m_id = m_invalid_id;
}
}
/** Bind texture to target
*
* @param gl GL functions
* @param id Id of texture
* @param tex_type Type of texture
**/
void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
{
gl.bindTexture(target, id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
}
/** Set contents of compressed texture
*
* @param gl GL functions
* @param target Texture target
* @param level Mipmap level
* @param internal_format Format of data
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
* @param image_size Size of data
* @param data Buffer with image data
**/
void Texture::CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
glw::GLsizei image_size, const glw::GLvoid* data)
{
switch (target)
{
case GL_TEXTURE_1D:
gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D");
break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE:
gl.compressedTexImage2D(target, level, internal_format, width, height, 0 /* border */, image_size, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
break;
case GL_TEXTURE_CUBE_MAP:
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */,
image_size, data);
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */,
image_size, data);
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */,
image_size, data);
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */,
image_size, data);
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */,
image_size, data);
gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */,
image_size, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
gl.compressedTexImage3D(target, level, internal_format, width, height, depth, 0 /* border */, image_size, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage3D");
break;
default:
TCU_FAIL("Invliad enum");
}
}
/** Generate texture instance
*
* @param gl GL functions
* @param out_id Id of texture
**/
void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id)
{
GLuint id = m_invalid_id;
gl.genTextures(1, &id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
if (m_invalid_id == id)
{
TCU_FAIL("Invalid id");
}
out_id = id;
}
/** Get texture data
*
* @param gl GL functions
* @param target Texture target
* @param format Format of data
* @param type Type of data
* @param out_data Buffer for data
**/
void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
glw::GLenum type, glw::GLvoid* out_data)
{
gl.getTexImage(target, level, format, type, out_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
}
/** Generate texture instance
*
* @param gl GL functions
* @param target Texture target
* @param level Mipmap level
* @param pname Parameter to query
* @param param Result of query
**/
void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
glw::GLint* param)
{
gl.getTexLevelParameteriv(target, level, pname, param);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv");
}
/** Set contents of texture
*
* @param gl GL functions
* @param target Texture target
* @param level Mipmap level
* @param internal_format Format of data
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
* @param format Format of data
* @param type Type of data
* @param data Buffer with image data
**/
void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
const glw::GLvoid* data)
{
switch (target)
{
case GL_TEXTURE_1D:
gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D");
break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE:
gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
break;
case GL_TEXTURE_CUBE_MAP:
gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format,
type, data);
gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format,
type, data);
gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format,
type, data);
gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format,
type, data);
gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format,
type, data);
gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format,
type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D");
break;
default:
TCU_FAIL("Invliad enum");
}
}
/** Allocate storage for texture
*
* @param gl GL functions
* @param target Texture target
* @param levels Number of levels
* @param internal_format Internal format of texture
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
**/
void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error)
{
switch (target)
{
case GL_TEXTURE_1D:
gl.texStorage1D(target, levels, internal_format, width);
if (!allow_error)
{
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D");
}
break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE:
case GL_TEXTURE_CUBE_MAP:
gl.texStorage2D(target, levels, internal_format, width, height);
if (!allow_error)
{
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
}
break;
case GL_TEXTURE_2D_MULTISAMPLE:
gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
if (!allow_error)
{
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
}
break;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
gl.texStorage3DMultisample(target, levels, internal_format, width, height, depth, GL_FALSE);
if (!allow_error)
{
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3DMultisample");
}
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
gl.texStorage3D(target, levels, internal_format, width, height, depth);
if (!allow_error)
{
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
}
break;
default:
TCU_FAIL("Invliad enum");
}
}
/** Set contents of texture
*
* @param gl GL functions
* @param target Texture target
* @param level Mipmap level
* @param x X offset
* @param y Y offset
* @param z Z offset
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
* @param format Format of data
* @param type Type of data
* @param pixels Buffer with image data
**/
void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
glw::GLenum type, const glw::GLvoid* pixels)
{
switch (target)
{
case GL_TEXTURE_1D:
gl.texSubImage1D(target, level, x, width, format, type, pixels);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D");
break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE:
gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
break;
case GL_TEXTURE_CUBE_MAP:
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels);
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels);
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels);
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels);
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels);
gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
break;
default:
TCU_FAIL("Invliad enum");
}
}
/* Gather info about buffer target */
struct bufferTargetInfo
{
GLenum m_target;
GLenum m_pname_alignment;
GLenum m_pname_binding;
GLenum m_pname_max;
GLenum m_pname_max_size;
};
/* Gather info about texture target */
struct textureTargetInfo
{
GLenum m_target;
GLenum m_pname_binding;
const GLchar* m_name;
};
/* Collects information about buffers */
static const bufferTargetInfo s_buffer_infos[] = {
{ GL_ATOMIC_COUNTER_BUFFER, 0, GL_ATOMIC_COUNTER_BUFFER_BINDING, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE },
{
GL_TRANSFORM_FEEDBACK_BUFFER, 0, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS,
GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
},
{ GL_UNIFORM_BUFFER, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, GL_UNIFORM_BUFFER_BINDING, GL_MAX_UNIFORM_BUFFER_BINDINGS,
GL_MAX_UNIFORM_BLOCK_SIZE },
{ GL_SHADER_STORAGE_BUFFER, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, GL_SHADER_STORAGE_BUFFER_BINDING,
GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, GL_MAX_SHADER_STORAGE_BLOCK_SIZE },
};
static const size_t s_n_buffer_tragets = sizeof(s_buffer_infos) / sizeof(s_buffer_infos[0]);
/* Collects information about textures */
static const textureTargetInfo s_texture_infos[] = {
{ GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D, "1D" },
{ GL_TEXTURE_1D_ARRAY, GL_TEXTURE_BINDING_1D_ARRAY, "1D_ARRAY" },
{ GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, "2D" },
{ GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BINDING_2D_ARRAY, "2D_ARRAY" },
{ GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D, "3D" },
{ GL_TEXTURE_BUFFER, GL_TEXTURE_BINDING_BUFFER, "BUFFER" },
{ GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP, "CUBE" },
{ GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, "CUBE_ARRAY" },
{ GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE, "RECTANGLE" },
{ GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_BINDING_2D_MULTISAMPLE, "2D_MS" },
{ GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, "2D_MS_ARRAY" }
};
static const size_t s_n_texture_tragets = sizeof(s_texture_infos) / sizeof(s_texture_infos[0]);
/** Macro, verifies generated error, logs error message and throws failure
*
* @param expected_error Expected error value
* @param error_message Message logged if generated error is not the expected one
**/
#define CHECK_ERROR(expected_error, error_message) \
do { \
GLenum generated_error = gl.getError(); \
\
if (expected_error != generated_error) \
{ \
m_context.getTestContext().getLog() \
<< tcu::TestLog::Message << "File: " << __FILE__ << ", line: " << __LINE__ \
<< ". Got wrong error: " << glu::getErrorStr(generated_error) \
<< ", expected: " << glu::getErrorStr(expected_error) << ", message: " << error_message \
<< tcu::TestLog::EndMessage; \
TCU_FAIL("Invalid error generated"); \
} \
} while (0)
/* Prototypes */
void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string);
/** Checks binding
*
* @param context Test contex
* @param pname Pname of binding
* @param index Index of binding
* @param target_name Name of target
* @param expected_value Expected value of binding
**/
void checkBinding(deqp::Context& context, GLenum pname, GLuint index, const std::string& target_name,
GLint expected_value)
{
const Functions& gl = context.getRenderContext().getFunctions();
GLint binding = -1;
gl.getIntegeri_v(pname, index, &binding);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegeri_v");
if (binding != expected_value)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
<< ", expected: " << expected_value << ". Target: " << target_name
<< " at index: " << index << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid binding");
}
}
/** Checks bindings for given texture unit
*
* @param context Test contex
* @param pname Binding pname of <expected_value>
* @param index Index of texture unit
* @param expected_value Expected value of binding at <pname> target
**/
void checkTextureBinding(deqp::Context& context, GLenum pname, GLuint index, GLint expected_value)
{
const Functions& gl = context.getRenderContext().getFunctions();
for (size_t i = 0; i < s_n_texture_tragets; ++i)
{
const GLenum pname_binding = s_texture_infos[i].m_pname_binding;
const GLchar* target_name = s_texture_infos[i].m_name;
GLint binding = -1;
GLint value = 0;
gl.getIntegeri_v(pname_binding, index, &binding);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegeri_v");
if (pname_binding == pname)
{
value = (GLint)expected_value;
}
if (binding != value)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
<< ", expected: " << expected_value << ". Target: " << target_name
<< " at index: " << index << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid binding");
}
}
}
/** Checks binding
*
* @param context Test context
* @param index Index of binding
* @param expected_value Expected value of binding
**/
void checkVertexAttribBinding(deqp::Context& context, GLuint index, GLint expected_value)
{
const Functions& gl = context.getRenderContext().getFunctions();
GLint binding = -1;
gl.getVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &binding);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetVertexAttribiv");
if (binding != expected_value)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
<< ", expected: " << expected_value << ". Target: Vertex attribute"
<< " at index: " << index << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid binding");
}
}
/** Fills MS texture with specified value
*
* @param context Test context
* @param texture_id Index of binding
* @param value Value for texture
* @param is_array Selects if array target should be used
**/
void fillMSTexture(deqp::Context& context, GLuint texture_id, GLuint value, bool is_array)
{
/* */
static const GLchar* cs = "#version 430 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"layout (location = 0) writeonly uniform IMAGE uni_image;\n"
"\n"
"layout (location = 1) uniform uint uni_value;\n"
"\n"
"void main()\n"
"{\n"
" const POINT;\n"
"\n"
" imageStore(uni_image, point, 0, uvec4(uni_value, 0, 0, 0));\n"
"}\n"
"\n";
static const GLchar* array_image = "uimage2DMSArray";
static const GLchar* array_point = "ivec3 point = ivec3(gl_WorkGroupID.x, gl_WorkGroupID.y, 0)";
static const GLchar* regular_image = "uimage2DMS";
static const GLchar* regular_point = "ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y)";
/* */
const Functions& gl = context.getRenderContext().getFunctions();
const GLchar* image = (true == is_array) ? array_image : regular_image;
const GLchar* point = (true == is_array) ? array_point : regular_point;
size_t position = 0;
std::string source = cs;
/* */
replaceToken("IMAGE", position, image, source);
replaceToken("POINT", position, point, source);
/* */
Program program(context);
program.Init(source.c_str(), "", "", "", "", "");
program.Use();
/* */
if (true == is_array)
{
gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_TRUE /* layered */, 0 /* layer */,
GL_WRITE_ONLY, GL_R32UI);
}
else
{
gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
GL_WRITE_ONLY, GL_R32UI);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
gl.uniform1i(0 /* location */, 0 /* image unit*/);
GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
gl.uniform1ui(1 /* location */, value /* uni_value */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1ui");
/* */
gl.dispatchCompute(6, 6, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
}
/** Get texture binding pname for given index
*
* @param index Index of texture target
*
* @return Pname
**/
GLenum getBinding(GLuint index)
{
if (index < s_n_texture_tragets)
{
return s_texture_infos[index].m_pname_binding;
}
else
{
return GL_TEXTURE_BINDING_2D;
}
}
/** Get texture target for given index
*
* @param index Index of texture target
*
* @return Target
**/
GLenum getTarget(GLuint index)
{
if (index < s_n_texture_tragets)
{
return s_texture_infos[index].m_target;
}
else
{
return GL_TEXTURE_2D;
}
}
/** Replace first occurance of <token> with <text> in <string> starting at <search_posistion>
*
* @param token Token string
* @param search_position Position at which find will start, it is updated to position at which replaced text ends
* @param text String that will be used as replacement for <token>
* @param string String to work on
**/
void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string)
{
const size_t text_length = strlen(text);
const size_t token_length = strlen(token);
const size_t token_position = string.find(token, search_position);
string.replace(token_position, token_length, text, text_length);
search_position = token_position + text_length;
}
/** Constructor
*
* @param context Test context
**/
ErrorsBindBuffersTest::ErrorsBindBuffersTest(deqp::Context& context)
: TestCase(context, "errors_bind_buffers", "Verifies that proper errors are generated by buffer binding routines")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ErrorsBindBuffersTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
/* - INVALID_ENUM when <target> is not valid; */
{
static const GLintptr buffer_size = 16;
static const GLsizei count = 1;
static const GLuint first = 0;
static const GLintptr offset = 4;
static const GLintptr size = buffer_size - offset;
Buffer buffer;
buffer.InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
gl.bindBuffersBase(GL_ARRAY_BUFFER, first, count, &buffer.m_id);
CHECK_ERROR(GL_INVALID_ENUM, "BindBuffersBase with invalid <target>");
gl.bindBuffersRange(GL_ARRAY_BUFFER, first, count, &buffer.m_id, &offset, &size);
CHECK_ERROR(GL_INVALID_ENUM, "BindBuffersRange with invalid <target>");
}
for (size_t i = 0; i < s_n_buffer_tragets; ++i)
{
static const GLsizei n_buffers = 4;
const GLenum pname_alignment = s_buffer_infos[i].m_pname_alignment;
const GLenum pname_max = s_buffer_infos[i].m_pname_max;
const GLenum target = s_buffer_infos[i].m_target;
const std::string& target_name = glu::getBufferTargetStr(target).toString();
GLintptr buffer_size = 16;
GLsizei count = n_buffers;
GLuint first = 0;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLintptr offset = 4; /* ATOMIC and XFB require alignment of 4 */
GLint offset_alignment = 1;
GLint max_buffers = 0;
GLintptr size = buffer_size - offset;
size_t validated_index = n_buffers - 1;
/* Get alignment */
if (0 != pname_alignment)
{
gl.getIntegerv(pname_alignment, &offset_alignment);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
buffer_size += offset_alignment;
offset = offset_alignment;
size = buffer_size - offset;
}
/* Get max */
gl.getIntegerv(pname_max, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Select count so <first + count> does not exceed max.
* Validated index shall be in the specified range.
*/
if (n_buffers > max_buffers)
{
count = max_buffers;
validated_index = max_buffers - 1;
}
/* Storage */
Buffer buffer[n_buffers];
GLuint buffer_ids[n_buffers];
GLintptr offsets[n_buffers];
GLintptr sizes[n_buffers];
/* Prepare buffers */
for (size_t j = 0; j < n_buffers; ++j)
{
buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
buffer_ids[j] = buffer[j].m_id;
offsets[j] = offset;
sizes[j] = size;
}
/* - INVALID_OPERATION when <first> + <count> is greater than allowed limit; */
{
GLsizei t_count = n_buffers;
GLuint t_first = 0;
/* Select first so <first + count> exceeds max, avoid negative first */
if (n_buffers <= max_buffers)
{
t_first = max_buffers - n_buffers + 1;
}
else
{
t_count = max_buffers + 1;
/* first = 0; */
}
/* Test */
gl.bindBuffersBase(target, t_first, t_count, buffer_ids);
CHECK_ERROR(GL_INVALID_OPERATION,
"BindBuffersBase with invalid <first> + <count>, target: " << target_name);
gl.bindBuffersRange(target, t_first, t_count, buffer_ids, offsets, sizes);
CHECK_ERROR(GL_INVALID_OPERATION,
"BindBuffersRange with invalid <first> + <count>, target: " << target_name);
}
/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
* existing buffer;
*/
{
GLuint t_buffer_ids[n_buffers];
memcpy(t_buffer_ids, buffer_ids, sizeof(buffer_ids));
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isBuffer(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Invalidate the entry */
t_buffer_ids[validated_index] = invalid_id;
/* Test */
gl.bindBuffersBase(target, first, count, t_buffer_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersBase with invalid buffer id, target: " << target_name);
gl.bindBuffersRange(target, first, count, t_buffer_ids, offsets, sizes);
CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersRange with invalid buffer id, target: " << target_name);
}
/* - INVALID_VALUE if any value in <offsets> is less than zero; */
{
GLintptr t_offsets[n_buffers];
GLintptr t_sizes[n_buffers];
memcpy(t_offsets, offsets, sizeof(offsets));
memcpy(t_sizes, sizes, sizeof(sizes));
/* Invalidate the entry */
t_offsets[validated_index] = -1;
t_sizes[validated_index] = -1;
/* Test */
gl.bindBuffersRange(target, first, count, buffer_ids, t_offsets, sizes);
CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with negative offset, target: " << target_name);
/* Test */
gl.bindBuffersRange(target, first, count, buffer_ids, offsets, t_sizes);
CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with negative size, target: " << target_name);
}
/* - INVALID_VALUE if any pair of <offsets> and <sizes> exceeds limits. */
{
GLintptr t_offsets[n_buffers];
GLintptr t_sizes[n_buffers];
memcpy(t_offsets, offsets, sizeof(offsets));
memcpy(t_sizes, sizes, sizeof(sizes));
/* Invalidate the entry */
t_offsets[validated_index] -= 1; /* Not aligned by required value */
t_sizes[validated_index] = size - 1; /* Not aligned by required value */
/* Test */
gl.bindBuffersRange(target, first, count, buffer_ids, t_offsets, sizes);
CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with invalid <offset>, target: " << target_name);
/* Test */
if (GL_TRANSFORM_FEEDBACK_BUFFER == target)
{
gl.bindBuffersRange(target, first, count, buffer_ids, offsets, t_sizes);
CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with invalid <size>, target: " << target_name);
}
}
}
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
ErrorsBindTexturesTest::ErrorsBindTexturesTest(deqp::Context& context)
: TestCase(context, "errors_bind_textures", "Verifies that proper errors are generated by texture binding routines")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ErrorsBindTexturesTest::iterate()
{
static const GLuint depth = 8;
static const GLuint height = 8;
static const GLsizei n_textures = 4;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLsizei count = n_textures;
GLuint first = 0;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_textures = 0;
size_t validated_index = n_textures - 1;
/* Get max */
gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Select count so <first + count> does not exceed max.
* Validated index shall be in the specified range.
*/
if (n_textures > max_textures)
{
count = max_textures;
validated_index = max_textures - 1;
}
/* Storage */
Texture texture[n_textures];
GLuint texture_ids[n_textures];
/* Prepare textures */
texture[0].InitStorage(m_context, GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, width, height, depth);
texture[1].InitStorage(m_context, GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_RGBA8, width, height, depth);
texture[2].InitStorage(m_context, GL_TEXTURE_1D_ARRAY, 1 /* levels */, GL_RGBA8, width, height, depth);
texture[3].InitStorage(m_context, GL_TEXTURE_3D, 1 /* levels */, GL_RGBA8, width, height, depth);
for (size_t i = 0; i < n_textures; ++i)
{
texture_ids[i] = texture[i].m_id;
}
/* - INVALID_OPERATION when <first> + <count> exceed limits; */
{
GLsizei t_count = n_textures;
GLuint t_first = 0;
/* Select first so <first + count> exceeds max, avoid negative first */
if (n_textures <= max_textures)
{
t_first = max_textures - n_textures + 1;
}
else
{
t_count = max_textures + 1;
/* first = 0; */
}
/* Test */
gl.bindTextures(t_first, t_count, texture_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid <first> + <count>");
}
/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
* existing buffer;
*/
{
GLuint t_texture_ids[n_textures];
memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isTexture(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Invalidate the entry */
t_texture_ids[validated_index] = invalid_id;
/* Test */
gl.bindTextures(first, count, t_texture_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid texture id");
}
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
ErrorsBindSamplersTest::ErrorsBindSamplersTest(deqp::Context& context)
: TestCase(context, "errors_bind_samplers", "Verifies that proper errors are generated by sampler binding routines")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ErrorsBindSamplersTest::iterate()
{
static const GLsizei n_samplers = 4;
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLsizei count = n_samplers;
GLuint first = 0;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_samplers = 0;
size_t validated_index = n_samplers - 1;
/* Get max */
gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_samplers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Select count so <first + count> does not exceed max.
* Validated index shall be in the specified range.
*/
if (n_samplers > max_samplers)
{
count = max_samplers;
validated_index = max_samplers - 1;
}
/* Storage */
GLuint sampler_ids[n_samplers];
/* Prepare samplers */
gl.genSamplers(n_samplers, sampler_ids);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
try
{
/* - INVALID_OPERATION when <first> + <count> exceed limits; */
{
GLsizei t_count = n_samplers;
GLuint t_first = 0;
/* Select first so <first + count> exceeds max, avoid negative first */
if (n_samplers <= max_samplers)
{
t_first = max_samplers - n_samplers + 1;
}
else
{
t_count = max_samplers + 1;
/* first = 0; */
}
/* Test */
gl.bindSamplers(t_first, t_count, sampler_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid <first> + <count>");
}
/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
* existing buffer;
*/
{
GLuint t_sampler_ids[n_samplers];
memcpy(t_sampler_ids, sampler_ids, sizeof(sampler_ids));
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isTexture(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Invalidate the entry */
t_sampler_ids[validated_index] = invalid_id;
/* Test */
gl.bindTextures(first, count, t_sampler_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid sampler id");
}
}
catch (const std::exception&)
{
gl.deleteSamplers(n_samplers, sampler_ids);
TCU_FAIL("Invalid error generated");
}
/* Delete samplers */
gl.deleteSamplers(n_samplers, sampler_ids);
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
ErrorsBindImageTexturesTest::ErrorsBindImageTexturesTest(deqp::Context& context)
: TestCase(context, "errors_bind_image_textures",
"Verifies that proper errors are generated by image binding routines")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ErrorsBindImageTexturesTest::iterate()
{
static const GLuint depth = 8;
static const GLuint height = 8;
static const GLsizei n_textures = 4;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLsizei count = n_textures;
GLuint first = 0;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_textures = 0;
size_t validated_index = n_textures - 1;
/* Get max */
gl.getIntegerv(GL_MAX_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Select count so <first + count> does not exceed max.
* Validated index shall be in the specified range.
*/
if (n_textures > max_textures)
{
count = max_textures;
validated_index = max_textures - 1;
}
/* Storage */
Texture texture[n_textures];
GLuint texture_ids[n_textures];
/* Prepare textures */
texture[0].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
texture[1].InitStorage(m_context, GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, depth);
texture[2].InitStorage(m_context, GL_TEXTURE_1D_ARRAY, 1, GL_RGBA8, width, height, depth);
texture[3].InitStorage(m_context, GL_TEXTURE_3D, 1, GL_RGBA8, width, height, depth);
for (size_t i = 0; i < n_textures; ++i)
{
texture_ids[i] = texture[i].m_id;
}
/* - INVALID_OPERATION when <first> + <count> exceed limits; */
{
GLsizei t_count = n_textures;
GLuint t_first = 0;
/* Select first so <first + count> exceeds max, avoid negative first */
if (n_textures <= max_textures)
{
t_first = max_textures - n_textures + 1;
}
else
{
t_count = max_textures + 1;
/* first = 0; */
}
/* Test */
gl.bindImageTextures(t_first, t_count, texture_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid <first> + <count>");
}
/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
* existing buffer;
*/
{
GLuint t_texture_ids[n_textures];
memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isTexture(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Invalidate the entry */
t_texture_ids[validated_index] = invalid_id;
/* Test */
gl.bindImageTextures(first, count, t_texture_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid texture id");
}
/* - INVALID_OPERATION if any entry found in <textures> has invalid internal
* format at level 0;
*/
{
GLuint t_texture_ids[n_textures];
memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
/* Prepare texture with invalid format */
Texture t_texture;
t_texture.Init(m_context);
t_texture.Generate(gl, t_texture.m_id);
t_texture.Bind(gl, t_texture.m_id, GL_TEXTURE_2D);
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGB9_E5, width, 0);
CHECK_ERROR(GL_INVALID_VALUE, "texStorage2D has height set to 0");
/* Invalidate the entry */
t_texture_ids[validated_index] = t_texture.m_id;
/* Test */
gl.bindImageTextures(first, count, t_texture_ids);
CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid internal format");
}
/* - INVALID_VALUE when any entry in <textures> has any of dimensions equal
* to 0 at level 0.
*/
{
GLuint t_texture_ids[n_textures];
memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
/* Prepare texture with invalid format */
Texture t_texture;
t_texture.InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGB9_E5, width, 0, depth, true);
/* Invalidate the entry */
t_texture_ids[validated_index] = t_texture.m_id;
/* Test */
gl.bindImageTextures(first, count, t_texture_ids);
CHECK_ERROR(GL_INVALID_VALUE, "BindImageTextures with 2D texture that has height set to 0");
}
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
ErrorsBindVertexBuffersTest::ErrorsBindVertexBuffersTest(deqp::Context& context)
: TestCase(context, "errors_bind_vertex_buffers",
"Verifies that proper errors are generated by vertex buffer binding routines")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ErrorsBindVertexBuffersTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
static const GLsizei n_buffers = 4;
static const GLsizei stride = 4;
GLintptr buffer_size = 16;
GLsizei count = n_buffers;
GLuint first = 0;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLintptr offset = 4; /* ATOMIC and XFB require alignment of 4 */
GLint max_buffers = 0;
size_t validated_index = n_buffers - 1;
/* Get max */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Select count so <first + count> does not exceed max.
* Validated index shall be in the specified range.
*/
if (n_buffers > max_buffers)
{
count = max_buffers;
validated_index = max_buffers - 1;
}
/* Storage */
Buffer buffer[n_buffers];
GLuint buffer_ids[n_buffers];
GLintptr offsets[n_buffers];
GLsizei strides[n_buffers];
/* Prepare buffers */
for (size_t j = 0; j < n_buffers; ++j)
{
buffer[j].InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
buffer_ids[j] = buffer[j].m_id;
offsets[j] = offset;
strides[j] = stride;
}
/* Prepare VAO */
GLuint vao = 0;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
try
{
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
/* - INVALID_OPERATION when <first> + <count> exceeds limits; */
{
GLsizei t_count = n_buffers;
GLuint t_first = 0;
/* Select first so <first + count> exceeds max, avoid negative first */
if (n_buffers <= max_buffers)
{
t_first = max_buffers - n_buffers + 1;
}
else
{
t_count = max_buffers + 1;
/* first = 0; */
}
/* Test */
gl.bindVertexBuffers(t_first, t_count, buffer_ids, offsets, strides);
CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid <first> + <count>");
}
/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
* existing buffer;
*/
{
GLuint t_buffer_ids[n_buffers];
memcpy(t_buffer_ids, buffer_ids, sizeof(buffer_ids));
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isBuffer(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Invalidate the entry */
t_buffer_ids[validated_index] = invalid_id;
/* Test */
gl.bindVertexBuffers(first, count, t_buffer_ids, offsets, strides);
CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid buffer id");
}
/* - INVALID_VALUE if any value in <offsets> or <strides> is less than zero. */
{
GLintptr t_offsets[n_buffers];
GLsizei t_strides[n_buffers];
memcpy(t_offsets, offsets, sizeof(offsets));
memcpy(t_strides, strides, sizeof(strides));
/* Invalidate the entry */
t_offsets[validated_index] = -1;
t_strides[validated_index] = -1;
/* Test */
gl.bindVertexBuffers(first, count, buffer_ids, t_offsets, strides);
CHECK_ERROR(GL_INVALID_VALUE, "BindVertexBuffers with negative offset");
gl.bindVertexBuffers(first, count, buffer_ids, offsets, t_strides);
CHECK_ERROR(GL_INVALID_VALUE, "BindVertexBuffers with negative stride");
}
}
catch (const std::exception&)
{
gl.deleteVertexArrays(1, &vao);
TCU_FAIL("Unexpected error generated");
}
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindBuffersBaseTest::FunctionalBindBuffersBaseTest(deqp::Context& context)
: TestCase(context, "functional_bind_buffers_base", "Verifies that BindBuffersBase works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindBuffersBaseTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
for (size_t i = 0; i < s_n_buffer_tragets; ++i)
{
const GLenum pname_binding = s_buffer_infos[i].m_pname_binding;
const GLenum pname_max = s_buffer_infos[i].m_pname_max;
const GLenum pname_max_size = s_buffer_infos[i].m_pname_max_size;
const GLenum target = s_buffer_infos[i].m_target;
const std::string& target_name = glu::getBufferTargetStr(target).toString();
GLint max_buffers = 0;
GLint max_size = 0;
/* Get max */
gl.getIntegerv(pname_max, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Get max size */
gl.getIntegerv(pname_max_size, &max_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
GLintptr buffer_size = max_size / max_buffers;
/* Storage */
std::vector<Buffer> buffer;
std::vector<GLuint> buffer_ids;
buffer.resize(max_buffers);
buffer_ids.resize(max_buffers);
/* Prepare buffers */
for (GLint j = 0; j < max_buffers; ++j)
{
buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
buffer_ids[j] = buffer[j].m_id;
}
/*
* - execute BindBufferBase to bind all buffers to tested target;
* - inspect if bindings were modified;
*/
gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/*
*
* - execute BindBufferBase for first half of bindings with NULL as <buffers>
* to unbind first half of bindings for tested target;
* - inspect if bindings were modified;
* - execute BindBufferBase for second half of bindings with NULL as <buffers>
* to unbind rest of bindings;
* - inspect if bindings were modified;
*/
GLint half_index = max_buffers / 2;
gl.bindBuffersBase(target, 0 /* first */, half_index /* count */, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
for (GLint j = 0; j < half_index; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, 0);
}
for (GLint j = half_index; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
gl.bindBuffersBase(target, half_index /* first */, max_buffers - half_index /* count */, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, 0);
}
/*
* - change <buffers> so first entry is invalid;
* - execute BindBufferBase to bind all buffers to tested target; It is
* expected that INVALID_OPERATION will be generated;
* - inspect if all bindings but first were modified;
*/
/* Find invalid id */
GLuint invalid_id = 1;
while (1)
{
if (GL_TRUE != gl.isBuffer(invalid_id))
{
break;
}
invalid_id += 1;
}
buffer_ids[0] = invalid_id;
gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindBufferBase with invalid buffer id");
/* Update buffer_ids */
buffer_ids[0] = 0; /* 0 means unbound */
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/*
* - bind any buffer to first binding;
* - execute BindBufferBase for 0 as <first>, 1 as <count> and <buffers> filled
* with zeros to unbind 1st binding for tested target;
* - inspect if bindings were modified;
*/
gl.bindBufferBase(target, 0, buffer[0].m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
checkBinding(m_context, pname_binding, 0, target_name, buffer[0].m_id);
std::vector<GLuint> t_buffer_ids;
t_buffer_ids.resize(max_buffers);
gl.bindBuffersBase(target, 0 /* first */, 1 /* count */, &t_buffer_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/* - unbind all buffers. */
gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, 0);
}
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindBuffersRangeTest::FunctionalBindBuffersRangeTest(deqp::Context& context)
: TestCase(context, "functional_bind_buffers_range", "Verifies that BindBuffersRange works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindBuffersRangeTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
for (size_t i = 0; i < s_n_buffer_tragets; ++i)
{
const GLenum pname_binding = s_buffer_infos[i].m_pname_binding;
const GLenum pname_max = s_buffer_infos[i].m_pname_max;
const GLenum pname_max_size = s_buffer_infos[i].m_pname_max_size;
const GLenum target = s_buffer_infos[i].m_target;
const std::string& target_name = glu::getBufferTargetStr(target).toString();
GLint max_buffers = 0;
GLint max_size = 0;
/* Get max */
gl.getIntegerv(pname_max, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Get max size */
gl.getIntegerv(pname_max_size, &max_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
GLintptr buffer_size = max_size / max_buffers;
/* Storage */
std::vector<Buffer> buffer;
std::vector<GLuint> buffer_ids;
std::vector<GLintptr> offsets;
std::vector<GLsizeiptr> sizes;
buffer.resize(max_buffers);
buffer_ids.resize(max_buffers);
offsets.resize(max_buffers);
sizes.resize(max_buffers);
/* Prepare buffers */
for (GLint j = 0; j < max_buffers; ++j)
{
buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
buffer_ids[j] = buffer[j].m_id;
offsets[j] = 0;
sizes[j] = buffer_size;
}
/*
* - execute BindBufferBase to bind all buffers to tested target;
* - inspect if bindings were modified;
*/
gl.bindBuffersRange(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0], &offsets[0], &sizes[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/*
*
* - execute BindBufferBase for first half of bindings with NULL as <buffers>
* to unbind first half of bindings for tested target;
* - inspect if bindings were modified;
* - execute BindBufferBase for second half of bindings with NULL as <buffers>
* to unbind rest of bindings;
* - inspect if bindings were modified;
*/
GLint half_index = max_buffers / 2;
gl.bindBuffersRange(target, 0 /* first */, half_index /* count */, 0, &offsets[0], &sizes[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
for (GLint j = 0; j < half_index; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, 0);
}
for (GLint j = half_index; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
gl.bindBuffersRange(target, half_index /* first */, max_buffers - half_index /* count */, 0, &offsets[0],
&sizes[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, 0);
}
/*
* - change <buffers> so first entry is invalid;
* - execute BindBufferBase to bind all buffers to tested target; It is
* expected that INVALID_OPERATION will be generated;
* - inspect if all bindings but first were modified;
*/
/* Find invalid id */
GLuint invalid_id = 1;
while (1)
{
if (GL_TRUE != gl.isBuffer(invalid_id))
{
break;
}
invalid_id += 1;
}
buffer_ids[0] = invalid_id;
gl.bindBuffersRange(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0], &offsets[0], &sizes[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersRange with invalid buffer id");
/* Update buffer_ids */
buffer_ids[0] = 0; /* 0 means unbound */
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/*
* - bind any buffer to first binding;
* - execute BindBufferBase for 0 as <first>, 1 as <count> and <buffers> filled
* with zeros to unbind 1st binding for tested target;
* - inspect if bindings were modified;
*/
gl.bindBufferBase(target, 0, buffer[0].m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
checkBinding(m_context, pname_binding, 0, target_name, buffer[0].m_id);
std::vector<GLuint> t_buffer_ids;
t_buffer_ids.resize(max_buffers);
gl.bindBuffersRange(target, 0 /* first */, 1 /* count */, &t_buffer_ids[0], &offsets[0], &sizes[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
for (GLint j = 0; j < max_buffers; ++j)
{
checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
}
/* - unbind all buffers. */
gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, 0);
}
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindTexturesTest::FunctionalBindTexturesTest(deqp::Context& context)
: TestCase(context, "functional_bind_textures", "Verifies that BindTextures works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindTexturesTest::iterate()
{
static const GLuint depth = 6;
static const GLuint height = 6;
static const GLuint width = 6;
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_textures = 0;
/* Get max */
gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
Buffer buffer;
std::vector<Texture> texture;
std::vector<GLuint> texture_ids;
std::vector<GLuint> t_texture_ids;
texture.resize(max_textures);
texture_ids.resize(max_textures);
t_texture_ids.resize(max_textures);
/* Prepare buffer */
buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, 16 /* size */, 0 /* data */);
/* Prepare textures */
for (size_t i = 0; i < s_n_texture_tragets; ++i)
{
const GLenum target = s_texture_infos[i].m_target;
if (GL_TEXTURE_BUFFER != target)
{
texture[i].InitStorage(m_context, target, 1, GL_RGBA8, width, height, depth);
}
else
{
texture[i].InitBuffer(m_context, GL_RGBA8, buffer.m_id);
}
/* Unbind */
Texture::Bind(gl, 0, target);
}
for (GLint i = s_n_texture_tragets; i < max_textures; ++i)
{
texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
}
/* Unbind */
Texture::Bind(gl, 0, GL_TEXTURE_2D);
for (GLint i = 0; i < max_textures; ++i)
{
texture_ids[i] = texture[i].m_id;
}
/*
* - execute BindTextures to bind all textures;
* - inspect bindings of all texture units to verify that proper bindings were
* set;
*/
gl.bindTextures(0, max_textures, &texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
for (GLint i = 0; i < max_textures; ++i)
{
checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
}
/*
* - execute BindTextures for the first half of units with <textures> filled
* with zeros, to unbind those units;
* - inspect bindings of all texture units to verify that proper bindings were
* unbound;
*/
GLint half_index = max_textures / 2;
for (GLint i = 0; i < max_textures; ++i)
{
t_texture_ids[i] = 0;
}
gl.bindTextures(0, half_index, &t_texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
for (GLint i = 0; i < half_index; ++i)
{
checkTextureBinding(m_context, getBinding(i), i, 0);
}
for (GLint i = half_index; i < max_textures; ++i)
{
checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
}
/*
* - execute BindTextures for the second half of units with NULL as<textures>,
* to unbind those units;
* - inspect bindings of all texture units to verify that proper bindings were
* unbound;
*/
gl.bindTextures(half_index, max_textures - half_index, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
for (GLint i = 0; i < max_textures; ++i)
{
checkTextureBinding(m_context, getBinding(i), i, 0);
}
/*
* - modify <textures> so first entry is invalid;
* - execute BindTextures to bind all textures; It is expected that
* INVALID_OPERATION will be generated;
* - inspect bindings of all texture units to verify that proper bindings were
* set;
*/
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isTexture(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Set invalid id */
texture_ids[0] = invalid_id;
gl.bindTextures(0, max_textures, &texture_ids[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid texture id");
checkTextureBinding(m_context, getBinding(0), 0, 0);
for (GLint i = 1; i < max_textures; ++i)
{
checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
}
/* - unbind all textures. */
gl.bindTextures(0, max_textures, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindSamplersTest::FunctionalBindSamplersTest(deqp::Context& context)
: TestCase(context, "functional_bind_samplers", "Verifies that BindSamplers works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindSamplersTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_samplers = 0;
/* Get max */
gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_samplers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
std::vector<GLuint> sampler_ids;
std::vector<GLuint> t_sampler_ids;
sampler_ids.resize(max_samplers);
t_sampler_ids.resize(max_samplers);
for (GLint i = 0; i < max_samplers; ++i)
{
t_sampler_ids[i] = 0;
}
/* Prepare samplers */
gl.genSamplers(max_samplers, &sampler_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
try
{
/* - execute BindSamplers to bind all samplers;
* - inspect bindings to verify that proper samplers were set;
*/
gl.bindSamplers(0 /* first */, max_samplers /* count */, &sampler_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
for (GLint i = 0; i < max_samplers; ++i)
{
checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", sampler_ids[i]);
}
/* - execute BindSamplers for first half of bindings with <samplers> filled
* with zeros, to unbind those samplers;
* - inspect bindings to verify that proper samplers were unbound;
*/
GLint half_index = max_samplers / 2;
gl.bindSamplers(0, half_index, &t_sampler_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
for (GLint i = 0; i < half_index; ++i)
{
checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", 0);
}
for (GLint i = half_index; i < max_samplers; ++i)
{
checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", sampler_ids[i]);
}
/* - execute BindSamplers for second half of bindings with NULL as <samplers>,
* to unbind those samplers;
* - inspect bindings to verify that proper samplers were unbound;
*/
gl.bindSamplers(half_index, max_samplers - half_index, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
for (GLint i = 0; i < max_samplers; ++i)
{
checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", 0);
}
/* - modify <samplers> so first entry is invalid;
* - execute BindSamplers to bind all samplers; It is expected that
* INVALID_OPERATION will be generated;
* - inspect bindings to verify that proper samplers were set;
*/
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isSampler(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Prepare ids */
t_sampler_ids[0] = invalid_id;
for (GLint i = 1; i < max_samplers; ++i)
{
t_sampler_ids[i] = sampler_ids[i];
}
/* Bind */
gl.bindSamplers(0, max_samplers, &t_sampler_ids[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid sampler id");
/* Set 0 for invalid entry */
t_sampler_ids[0] = 0;
for (GLint i = 0; i < max_samplers; ++i)
{
checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", t_sampler_ids[i]);
}
/* - unbind all samplers. */
gl.bindSamplers(0, max_samplers, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
}
catch (const std::exception&)
{
gl.deleteSamplers(max_samplers, &sampler_ids[0]);
TCU_FAIL("Invalid error generated");
}
/* Delete samplers */
gl.deleteSamplers(max_samplers, &sampler_ids[0]);
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindImageTexturesTest::FunctionalBindImageTexturesTest(deqp::Context& context)
: TestCase(context, "functional_bind_image_textures", "Verifies that BindImageTextures works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindImageTexturesTest::iterate()
{
static const GLuint depth = 6;
static const GLuint height = 6;
static const GLuint width = 6;
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_textures = 0;
/* Get max */
gl.getIntegerv(GL_MAX_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
Buffer buffer;
std::vector<Texture> texture;
std::vector<GLuint> texture_ids;
std::vector<GLuint> t_texture_ids;
texture.resize(max_textures);
texture_ids.resize(max_textures);
t_texture_ids.resize(max_textures);
/* Prepare buffer */
buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, 16 /* size */, 0 /* data */);
/* Prepare textures */
for (GLint i = 0; i < (GLint)s_n_texture_tragets; ++i)
{
const GLenum target = s_texture_infos[i].m_target;
if (i >= max_textures)
{
break;
}
if (GL_TEXTURE_BUFFER != target)
{
texture[i].InitStorage(m_context, target, 1, GL_RGBA8, width, height, depth);
}
else
{
texture[i].InitBuffer(m_context, GL_RGBA8, buffer.m_id);
}
/* Unbind */
Texture::Bind(gl, 0, target);
}
for (GLint i = (GLint)s_n_texture_tragets; i < max_textures; ++i)
{
texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
}
/* Unbind */
Texture::Bind(gl, 0, GL_TEXTURE_2D);
for (GLint i = 0; i < max_textures; ++i)
{
texture_ids[i] = texture[i].m_id;
}
/*
* - execute BindImageTextures to bind all images;
* - inspect bindings to verify that proper images were set;
*/
gl.bindImageTextures(0, max_textures, &texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
for (GLint i = 0; i < max_textures; ++i)
{
checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
}
/*
* - execute BindTextures for the first half of units with <textures> filled
* with zeros, to unbind those units;
* - inspect bindings of all texture units to verify that proper bindings were
* unbound;
*/
GLint half_index = max_textures / 2;
for (GLint i = 0; i < max_textures; ++i)
{
t_texture_ids[i] = 0;
}
gl.bindImageTextures(0, half_index, &t_texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
for (GLint i = 0; i < half_index; ++i)
{
checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", 0);
}
for (GLint i = half_index; i < max_textures; ++i)
{
checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
}
/*
* - execute BindTextures for the second half of units with NULL as<textures>,
* to unbind those units;
* - inspect bindings of all texture units to verify that proper bindings were
* unbound;
*/
gl.bindImageTextures(half_index, max_textures - half_index, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
for (GLint i = 0; i < max_textures; ++i)
{
checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", 0);
}
/*
* - modify <textures> so first entry is invalid;
* - execute BindTextures to bind all textures; It is expected that
* INVALID_OPERATION will be generated;
* - inspect bindings of all texture units to verify that proper bindings were
* set;
*/
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isTexture(invalid_id))
{
break;
}
invalid_id += 1;
}
/* Set invalid id */
texture_ids[0] = invalid_id;
gl.bindImageTextures(0, max_textures, &texture_ids[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid texture id");
checkBinding(m_context, GL_IMAGE_BINDING_NAME, 0, "Image unit", 0);
for (GLint i = 1; i < max_textures; ++i)
{
checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
}
/* - unbind all textures. */
gl.bindImageTextures(0, max_textures, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
FunctionalBindVertexBuffersTest::FunctionalBindVertexBuffersTest(deqp::Context& context)
: TestCase(context, "functional_bind_vertex_buffers", "Verifies that BindVertexBuffers works as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalBindVertexBuffersTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
static const GLintptr buffer_size = 16;
static const GLintptr offset = 4;
static const GLsizei stride = 4;
GLuint invalid_id = 1; /* Start with 1, as 0 is not valid name */
GLint max_buffers = 0;
/* Get max */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
std::vector<Buffer> buffer;
std::vector<GLuint> buffer_ids;
std::vector<GLintptr> offsets;
std::vector<GLsizei> strides;
std::vector<GLuint> t_buffer_ids;
buffer.resize(max_buffers);
buffer_ids.resize(max_buffers);
offsets.resize(max_buffers);
strides.resize(max_buffers);
t_buffer_ids.resize(max_buffers);
/* Prepare buffers */
for (GLint i = 0; i < max_buffers; ++i)
{
buffer[i].InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
buffer_ids[i] = buffer[i].m_id;
offsets[i] = offset;
strides[i] = stride;
t_buffer_ids[i] = 0;
}
GLuint vao = 0;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
try
{
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
/* - execute BindVertexBuffers to bind all buffer;
* - inspect bindings to verify that proper buffers were set;
*/
gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
for (GLint i = 0; i < max_buffers; ++i)
{
checkVertexAttribBinding(m_context, i, buffer_ids[i]);
}
/* - execute BindVertexBuffers for first half of bindings with <buffers> filled
* with zeros, to unbind those buffers;
* - inspect bindings to verify that proper buffers were unbound;
*/
GLint half_index = max_buffers / 2;
gl.bindVertexBuffers(0, half_index, &t_buffer_ids[0], &offsets[0], &strides[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
for (GLint i = 0; i < half_index; ++i)
{
checkVertexAttribBinding(m_context, i, 0);
}
for (GLint i = half_index; i < max_buffers; ++i)
{
checkVertexAttribBinding(m_context, i, buffer_ids[i]);
}
/* - execute BindVertexBuffers for second half of bindings with NULL as
* <buffers>, to unbind those buffers;
* - inspect bindings to verify that proper buffers were unbound;
*/
gl.bindVertexBuffers(half_index, max_buffers - half_index, 0, &offsets[0], &strides[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
for (GLint i = 0; i < max_buffers; ++i)
{
checkVertexAttribBinding(m_context, i, 0);
}
/* - modify <buffers> so first entry is invalid;
* - execute BindVertexBuffers to bind all buffers; It is expected that
* INVALID_OPERATION will be generated;
* - inspect bindings to verify that proper buffers were set;
*/
/* Find invalid id */
while (1)
{
if (GL_TRUE != gl.isBuffer(invalid_id))
{
break;
}
invalid_id += 1;
}
buffer_ids[0] = invalid_id;
gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid id");
checkVertexAttribBinding(m_context, 0, 0);
for (GLint i = 1; i < max_buffers; ++i)
{
checkVertexAttribBinding(m_context, i, buffer_ids[i]);
}
/* - unbind all buffers. */
gl.bindVertexBuffers(0, max_buffers, 0, &offsets[0], &strides[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
}
catch (const std::exception&)
{
gl.deleteVertexArrays(1, &vao);
TCU_FAIL("Unexpected error generated");
}
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
/* Set result */
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DispatchBindBuffersBaseTest::DispatchBindBuffersBaseTest(deqp::Context& context)
: TestCase(context, "dispatch_bind_buffers_base", "Tests BindBuffersBase with dispatch command")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DispatchBindBuffersBaseTest::iterate()
{
static const GLchar* cs = "#version 440 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"UBO_LIST\n"
"layout (std140, binding = 0) buffer SSB {\n"
" vec4 sum;\n"
"} ssb;\n"
"\n"
"void main()\n"
"{\n"
" ssb.sum = SUM_LIST;\n"
"}\n"
"\n";
static const GLchar* ubo = "layout (std140, binding = XXX) uniform BXXX { vec4 data; } bXXX;";
static const GLintptr buffer_size = 4 * sizeof(GLfloat);
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLint max_buffers = 0;
GLfloat sum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
/* Get max */
gl.getIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* UBO */
/* Storage */
std::vector<Buffer> uni_buffer;
std::vector<GLuint> uni_buffer_ids;
uni_buffer.resize(max_buffers);
uni_buffer_ids.resize(max_buffers);
/* Prepare buffers */
for (GLint i = 0; i < max_buffers; ++i)
{
const GLfloat data[4] = {
(GLfloat)(i * 4 + 0), (GLfloat)(i * 4 + 1), (GLfloat)(i * 4 + 2), (GLfloat)(i * 4 + 3),
};
sum[0] += data[0];
sum[1] += data[1];
sum[2] += data[2];
sum[3] += data[3];
uni_buffer[i].InitData(m_context, GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, buffer_size, data);
uni_buffer_ids[i] = uni_buffer[i].m_id;
}
gl.bindBuffersBase(GL_UNIFORM_BUFFER, 0 /* first */, max_buffers /* count */, &uni_buffer_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
/* SSBO */
Buffer ssb_buffer;
ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
ssb_buffer.BindBase(0);
/* Prepare program */
size_t ubo_position = 0;
size_t sum_position = 0;
std::string cs_source = cs;
for (GLint i = 0; i < max_buffers; ++i)
{
size_t ubo_start_position = ubo_position;
size_t sum_start_position = sum_position;
GLchar index[16];
sprintf(index, "%d", i);
/* Add entry to ubo list */
replaceToken("UBO_LIST", ubo_position, "UBO\nUBO_LIST", cs_source);
ubo_position = ubo_start_position;
replaceToken("UBO", ubo_position, ubo, cs_source);
ubo_position = ubo_start_position;
replaceToken("XXX", ubo_position, index, cs_source);
replaceToken("XXX", ubo_position, index, cs_source);
replaceToken("XXX", ubo_position, index, cs_source);
/* Add entry to sum list */
replaceToken("SUM_LIST", sum_position, "bXXX.data + SUM_LIST", cs_source);
sum_position = sum_start_position;
replaceToken("XXX", sum_position, index, cs_source);
}
/* Remove token for lists */
replaceToken(" + SUM_LIST", sum_position, "", cs_source);
replaceToken("UBO_LIST", ubo_position, "", cs_source);
Program program(m_context);
program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
gl.memoryBarrier(GL_ALL_BARRIER_BITS);
GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
GLfloat* result = (GLfloat*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
if (0 != memcmp(result, sum, 4 * sizeof(GLfloat)))
{
test_result = false;
}
gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
gl.getError(); /* Ignore error */
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DispatchBindBuffersRangeTest::DispatchBindBuffersRangeTest(deqp::Context& context)
: TestCase(context, "dispatch_bind_buffers_range", "Tests BindBuffersRange with dispatch command")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DispatchBindBuffersRangeTest::iterate()
{
static const GLchar* cs = "#version 440 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"layout (std140, binding = 0) uniform B0 { int data; } b0;"
"layout (std140, binding = 1) uniform B1 { int data; } b1;"
"layout (std140, binding = 2) uniform B2 { int data; } b2;"
"layout (std140, binding = 3) uniform B3 { int data; } b3;"
"\n"
"layout (std140, binding = 0) buffer SSB {\n"
" int sum;\n"
"} ssb;\n"
"\n"
"void main()\n"
"{\n"
" //ssb.sum = b1.data;// + b1.data + b2.data + b3.data;\n"
" ssb.sum = b0.data + b1.data + b2.data + b3.data;\n"
"}\n"
"\n";
static const GLint data[] = { 0x00010001, 0x01000100 };
static const size_t n_buffers = 4;
static const GLint sum = 0x02020202;
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
/* UBO */
GLint offset_alignment = 0;
gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offset_alignment);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
Buffer uni_buffer;
GLuint uni_buffer_ids[n_buffers];
std::vector<GLubyte> uni_data;
GLintptr uni_offsets[n_buffers];
GLintptr uni_sizes[n_buffers];
const size_t buffer_size = (n_buffers - 1) * offset_alignment + sizeof(GLint);
uni_data.resize(buffer_size);
for (size_t i = 0; i < buffer_size; ++i)
{
uni_data[i] = 0xaa;
}
for (size_t i = 0; i < n_buffers; ++i)
{
void* dst = &uni_data[i * offset_alignment];
const void* src = &data[(i % 2)];
memcpy(dst, src, sizeof(GLint));
}
uni_buffer.InitData(m_context, GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, buffer_size, &uni_data[0]);
for (size_t i = 0; i < n_buffers; ++i)
{
uni_buffer_ids[i] = uni_buffer.m_id;
uni_offsets[i] = i * offset_alignment;
uni_sizes[i] = sizeof(GLint);
}
gl.bindBuffersRange(GL_UNIFORM_BUFFER, 0 /* first */, n_buffers /* count */, &uni_buffer_ids[0], &uni_offsets[0],
&uni_sizes[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
/* SSBO */
Buffer ssb_buffer;
ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLint), 0 /* data */);
ssb_buffer.BindBase(0);
/* Prepare program */
Program program(m_context);
program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
gl.memoryBarrier(GL_ALL_BARRIER_BITS);
GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
GLint* result = (GLint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
if (0 != memcmp(result, &sum, sizeof(sum)))
{
test_result = false;
}
gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
gl.getError(); /* Ignore error */
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DispatchBindTexturesTest::DispatchBindTexturesTest(deqp::Context& context)
: TestCase(context, "dispatch_bind_textures", "Tests BindTextures with dispatch command")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DispatchBindTexturesTest::iterate()
{
static const GLchar* cs = "#version 440 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"SAMPLER_LIST\n"
"layout (std140, binding = 0) buffer SSB {\n"
" uint sum;\n"
"} ssb;\n"
"\n"
"void main()\n"
"{\n"
" uvec4 sum = SUM_LIST;\n"
" ssb.sum = sum.r\n;"
"}\n"
"\n";
static const GLchar* sampler = "layout (location = XXX) uniform SAMPLER sXXX;";
static const GLchar* sampling[] = {
"texture(sXXX, COORDS)", "texture(sXXX, COORDS)", "texture(sXXX, COORDS)", "texture(sXXX, COORDS)",
"texture(sXXX, COORDS)", "texelFetch(sXXX, COORDS)", "texture(sXXX, COORDS)", "texture(sXXX, COORDS)",
"texture(sXXX, COORDS)", "texelFetch(sXXX, COORDS, 0)", "texelFetch(sXXX, COORDS, 0)"
};
static const GLchar* samplers[] = { "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
"usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray",
"usampler2DRect", "usampler2DMS", "usampler2DMSArray" };
static const GLchar* coordinates[] = {
"0.5f",
"vec2(0.5f, 0.0f)",
"vec2(0.5f, 0.5f)",
"vec3(0.5f, 0.5f, 0.0f)",
"vec3(0.5f, 0.5f, 0.5f)",
"0",
"vec3(0.5f, 0.5f, 0.5f)",
"vec4(0.5f, 0.5f, 0.5f, 0.0f)",
"vec2(0.5f, 0.5f)",
"ivec2(0, 0)",
"ivec3(0, 0, 0)",
};
static const GLuint depth = 6;
static const GLuint height = 6;
static const GLuint width = 6;
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLint max_textures = 0;
GLint max_image_samples = 0;
GLuint sum = 0;
/* Get max */
gl.getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Check if load/store from multisampled images is supported */
gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Textures */
/* Storage */
std::vector<Texture> texture;
std::vector<GLuint> texture_ids;
Buffer texture_buffer;
texture.resize(max_textures);
texture_ids.resize(max_textures);
/* Prepare */
for (GLint i = 0; i < max_textures; ++i)
{
GLenum target = getTarget(i);
if (target >= GL_TEXTURE_2D_MULTISAMPLE && max_image_samples < 2)
target = GL_TEXTURE_2D;
GLuint data[width * height * depth];
for (GLuint j = 0; j < width * height * depth; ++j)
{
data[j] = i;
}
sum += i;
bool is_array = false;
switch (target)
{
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
is_array = true;
/* Intentional fallthrough */
case GL_TEXTURE_2D_MULTISAMPLE:
texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
fillMSTexture(m_context, texture[i].m_id, i, is_array);
break;
case GL_TEXTURE_BUFFER:
texture_buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, sizeof(data), data);
texture[i].InitBuffer(m_context, GL_R32UI, texture_buffer.m_id);
break;
default:
texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
Texture::Bind(gl, texture[i].m_id, target);
Texture::SubImage(gl, target, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
}
/* Clean */
Texture::Bind(gl, 0, target);
texture_ids[i] = texture[i].m_id;
}
gl.bindTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
/* SSBO */
Buffer ssb_buffer;
ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
ssb_buffer.BindBase(0);
/* Prepare program */
size_t sam_position = 0;
size_t sum_position = 0;
std::string cs_source = cs;
GLint max_target_index = (GLint)(max_image_samples >= 2 ? s_n_texture_tragets : s_n_texture_tragets - 2);
for (GLint i = 0; i < max_textures; ++i)
{
size_t sam_start_position = sam_position;
size_t sum_start_position = sum_position;
GLchar index[16];
sprintf(index, "%d", i);
const GLchar* coords = 0;
const GLchar* sampler_type = 0;
const GLchar* sampling_code = 0;
if (i < max_target_index)
{
coords = coordinates[i];
sampler_type = samplers[i];
sampling_code = sampling[i];
}
else
{
coords = coordinates[2]; /* vec2(0.5f, 0.5f) */
sampler_type = samplers[2]; /* usampler2D */
sampling_code = sampling[2]; /* texture(sXXX, COORDS) */
}
/* Add entry to ubo list */
replaceToken("SAMPLER_LIST", sam_position, "SAMPLER\nSAMPLER_LIST", cs_source);
sam_position = sam_start_position;
replaceToken("SAMPLER", sam_position, sampler, cs_source);
sam_position = sam_start_position;
replaceToken("XXX", sam_position, index, cs_source);
replaceToken("SAMPLER", sam_position, sampler_type, cs_source);
replaceToken("XXX", sam_position, index, cs_source);
/* Add entry to sum list */
replaceToken("SUM_LIST", sum_position, "SAMPLING + SUM_LIST", cs_source);
sum_position = sum_start_position;
replaceToken("SAMPLING", sum_position, sampling_code, cs_source);
sum_position = sum_start_position;
replaceToken("XXX", sum_position, index, cs_source);
replaceToken("COORDS", sum_position, coords, cs_source);
}
/* Remove token for lists */
replaceToken(" + SUM_LIST", sum_position, "", cs_source);
replaceToken("SAMPLER_LIST", sam_position, "", cs_source);
Program program(m_context);
program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
/* Set samplers */
for (GLint i = 0; i < max_textures; ++i)
{
gl.uniform1i(i, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
}
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
gl.memoryBarrier(GL_ALL_BARRIER_BITS);
GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
if (0 != memcmp(result, &sum, sizeof(sum)))
{
test_result = false;
}
gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
gl.getError(); /* Ignore error */
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DispatchBindImageTexturesTest::DispatchBindImageTexturesTest(deqp::Context& context)
: TestCase(context, "dispatch_bind_image_textures", "Tests BindImageTextures with dispatch command")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DispatchBindImageTexturesTest::iterate()
{
static const GLchar* cs = "#version 440 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"IMAGE_LIST\n"
"layout (std140, binding = 0) buffer SSB {\n"
" uint sum;\n"
"} ssb;\n"
"\n"
"void main()\n"
"{\n"
" uvec4 sum = SUM_LIST;\n"
" ssb.sum = sum.r\n;"
"}\n"
"\n";
static const GLchar* image = "layout (location = XXX, r32ui) readonly uniform IMAGE iXXX;";
static const GLchar* loading[] = {
"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)",
"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)",
"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS, 0)", "imageLoad(iXXX, COORDS, 0)"
};
static const GLchar* images[] = { "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray",
"uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray",
"uimage2DRect", "uimage2DMS", "uimage2DMSArray" };
static const GLchar* coordinates[] = {
"0",
"ivec2(0, 0)",
"ivec2(0, 0)",
"ivec3(0, 0, 0)",
"ivec3(0, 0, 0)",
"0",
"ivec3(0, 0, 0)",
"ivec3(0, 0, 0)",
"ivec2(0, 0)",
"ivec2(0, 0)",
"ivec3(0, 0, 0)",
};
static const GLuint depth = 6;
static const GLuint height = 6;
static const GLuint width = 6;
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLint max_textures = 0;
GLint max_image_samples = 0;
GLuint sum = 0;
/* Get max */
gl.getIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Check if load/store from multisampled images is supported */
gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Textures */
/* Storage */
std::vector<Texture> texture;
std::vector<GLuint> texture_ids;
Buffer texture_buffer;
texture.resize(max_textures);
texture_ids.resize(max_textures);
/* Prepare */
for (GLint i = 0; i < max_textures; ++i)
{
GLenum target = getTarget(i);
if (target >= GL_TEXTURE_2D_MULTISAMPLE && max_image_samples == 0)
target = GL_TEXTURE_2D;
GLuint data[width * height * depth];
for (GLuint j = 0; j < width * height * depth; ++j)
{
data[j] = i;
}
sum += i;
bool is_array = false;
switch (target)
{
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
is_array = true;
/* Intentional fallthrough */
case GL_TEXTURE_2D_MULTISAMPLE:
texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
fillMSTexture(m_context, texture[i].m_id, i, is_array);
break;
case GL_TEXTURE_BUFFER:
texture_buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, sizeof(data), data);
texture[i].InitBuffer(m_context, GL_R32UI, texture_buffer.m_id);
break;
default:
texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
Texture::Bind(gl, texture[i].m_id, target);
Texture::SubImage(gl, target, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
break;
}
/* Clean */
Texture::Bind(gl, 0, target);
texture_ids[i] = texture[i].m_id;
}
gl.bindImageTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
/* SSBO */
Buffer ssb_buffer;
ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
ssb_buffer.BindBase(0);
/* Prepare program */
size_t load_position = 0;
size_t sum_position = 0;
std::string cs_source = cs;
GLint max_target_index = (GLint)(max_image_samples > 0 ? s_n_texture_tragets : s_n_texture_tragets - 2);
for (GLint i = 0; i < max_textures; ++i)
{
size_t load_start_position = load_position;
size_t sum_start_position = sum_position;
GLchar index[16];
sprintf(index, "%d", i);
const GLchar* coords = 0;
const GLchar* image_type = 0;
const GLchar* loading_code = 0;
if (i < max_target_index)
{
coords = coordinates[i];
image_type = images[i];
loading_code = loading[i];
}
else
{
coords = coordinates[2]; /* vec2(0.5f, 0.5f) */
image_type = images[2]; /* usampler2D */
loading_code = loading[2]; /* texture(sXXX, COORDS) */
}
/* Add entry to ubo list */
replaceToken("IMAGE_LIST", load_position, "IMAGE\nIMAGE_LIST", cs_source);
load_position = load_start_position;
replaceToken("IMAGE", load_position, image, cs_source);
load_position = load_start_position;
replaceToken("XXX", load_position, index, cs_source);
replaceToken("IMAGE", load_position, image_type, cs_source);
replaceToken("XXX", load_position, index, cs_source);
/* Add entry to sum list */
replaceToken("SUM_LIST", sum_position, "LOADING + SUM_LIST", cs_source);
sum_position = sum_start_position;
replaceToken("LOADING", sum_position, loading_code, cs_source);
sum_position = sum_start_position;
replaceToken("XXX", sum_position, index, cs_source);
replaceToken("COORDS", sum_position, coords, cs_source);
}
/* Remove token for lists */
replaceToken(" + SUM_LIST", sum_position, "", cs_source);
replaceToken("IMAGE_LIST", load_position, "", cs_source);
Program program(m_context);
program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
/* Set images */
for (GLint i = 0; i < max_textures; ++i)
{
gl.uniform1i(i, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
}
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
gl.memoryBarrier(GL_ALL_BARRIER_BITS);
GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
if (0 != memcmp(result, &sum, sizeof(sum)))
{
test_result = false;
}
gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
gl.getError(); /* Ignore error */
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DispatchBindSamplersTest::DispatchBindSamplersTest(deqp::Context& context)
: TestCase(context, "dispatch_bind_samplers", "Tests BindSamplers with dispatch command")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DispatchBindSamplersTest::iterate()
{
static const GLchar* cs = "#version 440 core\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"SAMPLER_LIST\n"
"layout (std140, binding = 0) buffer SSB {\n"
" uint sum;\n"
"} ssb;\n"
"\n"
"void main()\n"
"{\n"
" uvec4 sum = SUM_LIST;\n"
" ssb.sum = sum.r\n;"
"}\n"
"\n";
static const GLchar* sampler = "layout (location = XXX) uniform usampler2D sXXX;";
static const GLchar* sampling = "texture(sXXX, vec2(1.5f, 0.5f))";
static const GLuint depth = 1;
static const GLuint height = 8;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
GLint max_textures = 0;
/* Get max */
gl.getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &max_textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Textures */
/* Storage */
std::vector<GLuint> sampler_ids;
std::vector<Texture> texture;
std::vector<GLuint> texture_ids;
sampler_ids.resize(max_textures);
texture.resize(max_textures);
texture_ids.resize(max_textures);
GLuint data[width * height * depth];
for (GLuint j = 0; j < width * height; ++j)
{
data[j] = 0;
}
{
const size_t last_line_offset = (height - 1) * width;
const size_t last_pixel_in_line_offset = width - 1;
for (GLuint j = 0; j < width; ++j)
{
data[j] = 1;
data[j + last_line_offset] = 1;
}
for (GLuint j = 0; j < height; ++j)
{
const size_t line_offset = j * width;
data[line_offset] = 1;
data[line_offset + last_pixel_in_line_offset] = 1;
}
}
/* Prepare */
for (GLint i = 0; i < max_textures; ++i)
{
texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_R32UI, width, height, depth);
Texture::Bind(gl, texture[i].m_id, GL_TEXTURE_2D);
Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
texture_ids[i] = texture[i].m_id;
}
/* Clean */
Texture::Bind(gl, 0, GL_TEXTURE_2D);
/* Execute the test */
gl.bindTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
/* SSBO */
Buffer ssb_buffer;
ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
ssb_buffer.BindBase(0);
/* Prepare program */
size_t sam_position = 0;
size_t sum_position = 0;
std::string cs_source = cs;
for (GLint i = 0; i < max_textures; ++i)
{
size_t sam_start_position = sam_position;
size_t sum_start_position = sum_position;
GLchar index[16];
sprintf(index, "%d", i);
/* Add entry to ubo list */
replaceToken("SAMPLER_LIST", sam_position, "SAMPLER\nSAMPLER_LIST", cs_source);
sam_position = sam_start_position;
replaceToken("SAMPLER", sam_position, sampler, cs_source);
sam_position = sam_start_position;
replaceToken("XXX", sam_position, index, cs_source);
replaceToken("XXX", sam_position, index, cs_source);
/* Add entry to sum list */
replaceToken("SUM_LIST", sum_position, "SAMPLING + SUM_LIST", cs_source);
sum_position = sum_start_position;
replaceToken("SAMPLING", sum_position, sampling, cs_source);
sum_position = sum_start_position;
replaceToken("XXX", sum_position, index, cs_source);
}
/* Remove token for lists */
replaceToken(" + SUM_LIST", sum_position, "", cs_source);
replaceToken("SAMPLER_LIST", sam_position, "", cs_source);
Program program(m_context);
program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
/* Set texture units */
for (GLint i = 0; i < max_textures; ++i)
{
gl.uniform1i(i, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
}
/* Prepare samplers */
gl.genSamplers(max_textures, &sampler_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
try
{
gl.bindSamplers(0 /* first */, max_textures /* count */, &sampler_ids[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
for (GLint i = 0; i < max_textures; ++i)
{
gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "SamplerParameteri");
}
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
gl.memoryBarrier(GL_ALL_BARRIER_BITS);
GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
}
catch (const std::exception&)
{
gl.deleteSamplers(max_textures, &sampler_ids[0]);
TCU_FAIL("Unexpected error generated");
}
/* Remove samplers */
gl.deleteSamplers(max_textures, &sampler_ids[0]);
/* Verify results */
GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
if (0 != memcmp(result, &max_textures, sizeof(max_textures)))
{
test_result = false;
}
gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
gl.getError(); /* Ignore error */
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param context Test context
**/
DrawBindVertexBuffersTest::DrawBindVertexBuffersTest(deqp::Context& context)
: TestCase(context, "draw_bind_vertex_buffers", "Tests BindVertexBuffers command with drawArrays")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult DrawBindVertexBuffersTest::iterate()
{
static const GLchar* vs = "#version 440 core\n"
"\n"
"ATTRIBUTE_LIST\n"
"\n"
"out vec4 vs_gs_sum;\n"
"\n"
"void main()\n"
"{\n"
" vs_gs_sum = SUM_LIST;\n"
"}\n"
"\n";
static const GLchar* gs = "#version 440 core\n"
"\n"
"layout(points) in;\n"
"layout(triangle_strip, max_vertices = 4) out;\n"
"\n"
"in vec4 vs_gs_sum[];\n"
"out vec4 gs_fs_sum;\n"
"\n"
"void main()\n"
"{\n"
" gs_fs_sum = vs_gs_sum[0];\n"
" gl_Position = vec4(-1, -1, 0, 1);\n"
" EmitVertex();\n"
" gs_fs_sum = vs_gs_sum[0];\n"
" gl_Position = vec4(-1, 1, 0, 1);\n"
" EmitVertex();\n"
" gs_fs_sum = vs_gs_sum[0];\n"
" gl_Position = vec4(1, -1, 0, 1);\n"
" EmitVertex();\n"
" gs_fs_sum = vs_gs_sum[0];\n"
" gl_Position = vec4(1, 1, 0, 1);\n"
" EmitVertex();\n"
"}\n"
"\n";
static const GLchar* fs = "#version 440 core\n"
"\n"
"in vec4 gs_fs_sum;\n"
"out vec4 fs_out;\n"
"\n"
"void main()\n"
"{\n"
" fs_out = gs_fs_sum;\n"
"}\n"
"\n";
static const GLchar* attribute = "layout (location = XXX) in vec4 aXXX;";
static const GLuint height = 8;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
#if DEBUG_ENBALE_MESSAGE_CALLBACK
gl.debugMessageCallback(debug_proc, &m_context);
GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
static const GLintptr attribute_size = 4 * sizeof(GLfloat);
GLint max_buffers = 0;
GLuint vao = 0;
/* Get max */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/* Storage */
Buffer buffer;
std::vector<GLuint> buffer_ids;
std::vector<GLfloat> data;
std::vector<GLintptr> offsets;
std::vector<GLsizei> strides;
buffer_ids.resize(max_buffers);
data.resize(max_buffers * 4);
offsets.resize(max_buffers);
strides.resize(max_buffers);
/* Prepare data */
const GLfloat value = 1.0f / (GLfloat)max_buffers;
for (GLint i = 0; i < max_buffers; ++i)
{
data[i * 4 + 0] = value;
data[i * 4 + 1] = value;
data[i * 4 + 2] = value;
data[i * 4 + 3] = value;
}
/* Prepare buffer */
buffer.InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, data.size() * sizeof(GLfloat), &data[0]);
for (GLint i = 0; i < max_buffers; ++i)
{
buffer_ids[i] = buffer.m_id;
offsets[i] = i * attribute_size;
strides[i] = attribute_size;
}
/* Prepare FBO */
Framebuffer framebuffer(m_context);
Texture texture;
texture.InitStorage(m_context, GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, width, height, 1 /* depth */);
/* */
Framebuffer::Generate(gl, framebuffer.m_id);
Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width,
height);
/* Prepare program */
size_t attr_position = 0;
size_t sum_position = 0;
std::string vs_source = vs;
for (GLint i = 0; i < max_buffers; ++i)
{
size_t attr_start_position = attr_position;
size_t sum_start_position = sum_position;
GLchar index[16];
sprintf(index, "%d", i);
/* Add entry to ubo list */
replaceToken("ATTRIBUTE_LIST", attr_position, "ATTRIBUTE\nATTRIBUTE_LIST", vs_source);
attr_position = attr_start_position;
replaceToken("ATTRIBUTE", attr_position, attribute, vs_source);
attr_position = attr_start_position;
replaceToken("XXX", attr_position, index, vs_source);
replaceToken("XXX", attr_position, index, vs_source);
/* Add entry to sum list */
replaceToken("SUM_LIST", sum_position, "aXXX + SUM_LIST", vs_source);
sum_position = sum_start_position;
replaceToken("XXX", sum_position, index, vs_source);
}
/* Remove token for lists */
replaceToken(" + SUM_LIST", sum_position, "", vs_source);
replaceToken("ATTRIBUTE_LIST", attr_position, "", vs_source);
Program program(m_context);
program.Init("" /* cs */, fs, gs, "" /* tcs */, "" /* tes */, vs_source.c_str());
program.Use();
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
try
{
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
for (GLint i = 0; i < max_buffers; ++i)
{
gl.enableVertexAttribArray(i);
GLU_EXPECT_NO_ERROR(gl.getError(), "EnableVertexAttribArray");
}
/* */
gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
/* */
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
for (GLint i = 0; i < max_buffers; ++i)
{
gl.disableVertexAttribArray(i);
GLU_EXPECT_NO_ERROR(gl.getError(), "DisableVertexAttribArray");
}
}
catch (const std::exception&)
{
gl.deleteVertexArrays(1, &vao);
TCU_FAIL("Unexpected error generated");
}
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
/* Verify results */
GLuint pixels[width * height];
for (GLuint i = 0; i < width * height; ++i)
{
pixels[i] = 0;
}
Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* Unbind */
Texture::Bind(gl, 0, GL_TEXTURE_2D);
/* Verify */
for (GLuint i = 0; i < width * height; ++i)
{
if (0xffffffff != pixels[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)pixels[i]
<< " at offset: " << i << tcu::TestLog::EndMessage;
test_result = false;
break;
}
}
/* Set result */
if (true == test_result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
} /* MultiBind */
/** Constructor.
*
* @param context Rendering context.
**/
MultiBindTests::MultiBindTests(deqp::Context& context)
: TestCaseGroup(context, "multi_bind", "Verifies \"multi bind\" functionality")
{
/* Left blank on purpose */
}
/** Initializes a multi_bind test group.
*
**/
void MultiBindTests::init(void)
{
addChild(new MultiBind::DispatchBindTexturesTest(m_context));
addChild(new MultiBind::ErrorsBindBuffersTest(m_context));
addChild(new MultiBind::ErrorsBindTexturesTest(m_context));
addChild(new MultiBind::ErrorsBindSamplersTest(m_context));
addChild(new MultiBind::ErrorsBindImageTexturesTest(m_context));
addChild(new MultiBind::ErrorsBindVertexBuffersTest(m_context));
addChild(new MultiBind::FunctionalBindBuffersBaseTest(m_context));
addChild(new MultiBind::FunctionalBindBuffersRangeTest(m_context));
addChild(new MultiBind::FunctionalBindTexturesTest(m_context));
addChild(new MultiBind::FunctionalBindSamplersTest(m_context));
addChild(new MultiBind::FunctionalBindImageTexturesTest(m_context));
addChild(new MultiBind::FunctionalBindVertexBuffersTest(m_context));
addChild(new MultiBind::DispatchBindBuffersBaseTest(m_context));
addChild(new MultiBind::DispatchBindBuffersRangeTest(m_context));
addChild(new MultiBind::DispatchBindImageTexturesTest(m_context));
addChild(new MultiBind::DispatchBindSamplersTest(m_context));
addChild(new MultiBind::DrawBindVertexBuffersTest(m_context));
}
} /* gl4cts namespace */