blob: 24f38ed30b131db5360751e0d665d245584edb10 [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");
break;
}
}
/** 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");
break;
}
}
/** 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");
break;
}
}
/** 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");
break;
}
}
/* 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) \
{ \
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"); \
} \
}
/* 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]