blob: 3e3adc1f1c7fe5d625cd1e1e72e470a85be81a06 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 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
*/ /*-------------------------------------------------------------------*/
#include "gl4cRobustnessTests.hpp"
#include "gluContextInfo.hpp"
#include "gluPlatform.hpp"
#include "gluRenderContext.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <cstring>
using namespace glw;
using namespace deqp::RobustBufferAccessBehavior;
namespace gl4cts
{
/** Extensions test method
* Checks if necessary extension is supported by context
**/
static bool checkExtension(deqp::Context& context, const char* extensionName)
{
/* If OpenGL 4.5 is available - feature shall be in Coree Profile. */
if (glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
{
return true;
}
/* OpenGL 4.5 is not available - check extensions. */
return context.getContextInfo().isExtensionSupported(extensionName);
}
namespace ResetNotificationStrategy
{
class RobustnessBase : public deqp::TestCase
{
private:
glu::RenderContext* m_robustContext;
public:
RobustnessBase(deqp::Context& context, const char* name, const char* description)
: deqp::TestCase(context, name, description), m_robustContext(NULL)
{
}
void createRobustContext(glu::ResetNotificationStrategy reset);
void releaseRobustContext(void);
glu::RenderContext* getRobustContext(void)
{
return m_robustContext;
}
};
void RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
{
glu::RenderConfig renderCfg(glu::ContextType(m_context.getRenderContext().getType().getAPI(), glu::CONTEXT_ROBUST));
glu::parseRenderConfig(&renderCfg, m_context.getTestContext().getCommandLine());
renderCfg.resetNotificationStrategy = reset;
renderCfg.surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
m_robustContext = glu::createRenderContext(m_testCtx.getPlatform(), m_testCtx.getCommandLine(), renderCfg);
}
void RobustnessBase::releaseRobustContext(void)
{
if (m_robustContext)
{
delete m_robustContext;
m_robustContext = NULL;
}
}
class NoResetNotificationCase : public RobustnessBase
{
typedef glw::GLenum(GLW_APIENTRY* PFNGLGETGRAPHICSRESETSTATUS)();
public:
NoResetNotificationCase(deqp::Context& context, const char* name, const char* description)
: RobustnessBase(context, name, description)
{
}
virtual IterateResult iterate(void)
{
if (!checkExtension(m_context, "GL_KHR_robustness"))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
createRobustContext(glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION);
getRobustContext()->makeCurrent();
PFNGLGETGRAPHICSRESETSTATUS pGetGraphicsResetStatus =
(PFNGLGETGRAPHICSRESETSTATUS)m_context.getRenderContext().getProcAddress("glGetGraphicsResetStatus");
if (DE_NULL == pGetGraphicsResetStatus)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_INTERNAL_ERROR,
"Pointer to function glGetGraphicsResetStatus is NULL.");
return STOP;
}
glw::GLint reset = 0;
const glw::Functions& gl = getRobustContext()->getFunctions();
gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
if (reset != GL_NO_RESET_NOTIFICATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
<< ", expected " << GL_NO_RESET_NOTIFICATION << "]." << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
glw::GLint status = pGetGraphicsResetStatus();
if (status != GL_NO_ERROR)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Test failed! glGetGraphicsResetStatus returned wrong value [" << status
<< ", expected " << GL_NO_ERROR << "]." << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
releaseRobustContext();
m_context.getRenderContext().makeCurrent();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
};
class LoseContextOnResetCase : public RobustnessBase
{
public:
LoseContextOnResetCase(deqp::Context& context, const char* name, const char* description)
: RobustnessBase(context, name, description)
{
}
virtual IterateResult iterate(void)
{
if (!checkExtension(m_context, "GL_KHR_robustness"))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
createRobustContext(glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET);
getRobustContext()->makeCurrent();
glw::GLint reset = 0;
const glw::Functions& gl = getRobustContext()->getFunctions();
gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
if (reset != GL_LOSE_CONTEXT_ON_RESET)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
<< ", expected " << GL_LOSE_CONTEXT_ON_RESET << "]." << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
releaseRobustContext();
m_context.getRenderContext().makeCurrent();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
};
} // ResetNotificationStrategy namespace
namespace RobustnessRobustBufferAccessBehavior
{
/* Buffer constants */
const GLuint Buffer::m_invalid_id = -1;
const GLenum Buffer::m_targets[Buffer::m_n_targets] = {
GL_ARRAY_BUFFER, /* 0 */
GL_ATOMIC_COUNTER_BUFFER, /* 1 */
GL_COPY_READ_BUFFER, /* 2 */
GL_COPY_WRITE_BUFFER, /* 3 */
GL_DISPATCH_INDIRECT_BUFFER, /* 4 */
GL_DRAW_INDIRECT_BUFFER, /* 5 */
GL_ELEMENT_ARRAY_BUFFER, /* 6 */
GL_PIXEL_PACK_BUFFER, /* 7 */
GL_PIXEL_UNPACK_BUFFER, /* 8 */
GL_QUERY_BUFFER, /* 9 */
GL_SHADER_STORAGE_BUFFER, /* 10 */
GL_TRANSFORM_FEEDBACK_BUFFER, /* 11 */
GL_UNIFORM_BUFFER, /* 12 */
};
/** Constructor.
*
* @param context CTS context.
**/
Buffer::Buffer(deqp::Context& context) : m_id(m_invalid_id), m_context(context), m_target(GL_ARRAY_BUFFER)
{
}
/** Destructor
*
**/
Buffer::~Buffer()
{
Release();
}
/** Initialize buffer instance
*
* @param target Buffer target
* @param usage Buffer usage enum
* @param size <size> parameter
* @param data <data> parameter
**/
void Buffer::InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data)
{
/* Delete previous buffer instance */
Release();
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
{
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
{
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.
*
* @param context CTS context.
**/
Texture::Texture(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
{
/* Nothing to done here */
}
/** Destructor
*
**/
Texture::~Texture()
{
Release();
}
/** Release texture instance
*
**/
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");
}
/** Get texture data
*
* @param gl GL functions
* @param id Texture id
* @param level Mipmap level
* @param width Texture width
* @param height Texture height
* @param format Format of data
* @param type Type of data
* @param out_data Buffer for data
**/
void Texture::GetData(const glw::Functions& gl, glw::GLuint id, glw::GLint level, glw::GLuint width, glw::GLuint height,
glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
{
GLuint fbo;
gl.genFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, level);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
gl.readPixels(0, 0, width, height, format, type, out_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
}
/** 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)
{
switch (target)
{
case GL_TEXTURE_1D:
gl.texStorage1D(target, levels, internal_format, width);
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);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
break;
case GL_TEXTURE_2D_MULTISAMPLE:
gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
gl.texStorage3D(target, levels, internal_format, width, height, depth);
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:
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;
}
}
/* VertexArray constants */
const GLuint VertexArray::m_invalid_id = -1;
/** Constructor.
*
* @param context CTS context.
**/
VertexArray::VertexArray(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
{
}
/** Destructor
*
**/
VertexArray::~VertexArray()
{
Release();
}
/** Release vertex array object instance
*
**/
void VertexArray::Release()
{
if (m_invalid_id != m_id)
{
const Functions& gl = m_context.getRenderContext().getFunctions();
Bind(gl, 0);
gl.deleteVertexArrays(1, &m_id);
m_id = m_invalid_id;
}
}
/** Binds Vertex array object
*
* @param gl GL functions
* @param id ID of vertex array object
**/
void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id)
{
gl.bindVertexArray(id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
}
/** Generates Vertex array object
*
* @param gl GL functions
* @param out_id ID of vertex array object
**/
void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id)
{
GLuint id = m_invalid_id;
gl.genVertexArrays(1, &id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
if (m_invalid_id == id)
{
TCU_FAIL("Invalid id");
}
out_id = id;
}
/** Constructor
*
* @param context Test context
**/
GetnUniformTest::GetnUniformTest(deqp::Context& context)
: deqp::TestCase(context, "getnuniform", "Verifies if read uniform variables to the buffer with bufSize less than "
"expected result with GL_INVALID_OPERATION")
, m_pGetnUniformfv(DE_NULL)
, m_pGetnUniformiv(DE_NULL)
, m_pGetnUniformuiv(DE_NULL)
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult GetnUniformTest::iterate()
{
if (!checkExtension(m_context, "GL_KHR_robustness") ||
!checkExtension(m_context, "GL_KHR_robust_buffer_access_behavior"))
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
m_pGetnUniformfv = (PFNGLGETNUNIFORMFV)m_context.getRenderContext().getProcAddress("glGetnUniformfv");
m_pGetnUniformiv = (PFNGLGETNUNIFORMIV)m_context.getRenderContext().getProcAddress("glGetnUniformiv");
m_pGetnUniformuiv = (PFNGLGETNUNIFORMUIV)m_context.getRenderContext().getProcAddress("glGetnUniformuiv");
if ((DE_NULL == m_pGetnUniformfv) || (DE_NULL == m_pGetnUniformiv) || (DE_NULL == m_pGetnUniformuiv))
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_INTERNAL_ERROR,
"Pointer to function glGetnUniform* is NULL.");
return STOP;
}
const Functions& gl = m_context.getRenderContext().getFunctions();
const GLfloat input4f[] = { 1.0f, 5.4f, 3.14159f, 1.28f };
const GLint input3i[] = { 10, -20, -30 };
const GLuint input4ui[] = { 10, 20, 30, 40 };
/* Test result indicator */
bool test_result = true;
/* Iterate over all cases */
Program program(m_context);
/* Compute Shader */
const std::string& cs = getComputeShader();
/* Shaders initialization */
program.Init(cs /* cs */, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
program.Use();
/* passing uniform values */
gl.programUniform4fv(program.m_id, 11, 1, input4f);
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4fv");
gl.programUniform3iv(program.m_id, 12, 1, input3i);
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform3iv");
gl.programUniform4uiv(program.m_id, 13, 1, input4ui);
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4uiv");
gl.dispatchCompute(1, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
/* veryfing gfetnUniform error messages */
GLfloat result4f[4];
GLint result3i[3];
GLuint result4ui[4];
m_pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 4, result4f);
test_result = test_result &&
verifyResult((void*)input4f, (void*)result4f, sizeof(GLfloat) * 4, "getnUniformfv [false negative]");
test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformfv [false negative]");
m_pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 3, result4f);
test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformfv [false positive]");
m_pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 3, result3i);
test_result = test_result &&
verifyResult((void*)input3i, (void*)result3i, sizeof(GLint) * 3, "getnUniformiv [false negative]");
test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformiv [false negative]");
m_pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 2, result3i);
test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformiv [false positive]");
m_pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 4, result4ui);
test_result = test_result && verifyResult((void*)input4ui, (void*)result4ui, sizeof(GLuint) * 4,
"getnUniformuiv [false negative]");
test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformuiv [false negative]");
m_pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 3, result4ui);
test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformuiv [false positive]");
/* 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;
}
std::string GetnUniformTest::getComputeShader()
{
static const GLchar* cs = "#version 320 es\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"layout (location = 11) uniform vec4 inputf;\n"
"layout (location = 12) uniform ivec3 inputi;\n"
"layout (location = 13) uniform uvec4 inputu;\n"
"\n"
"shared float valuef;\n"
"shared int valuei;\n"
"shared uint valueu;\n"
"\n"
"void main()\n"
"{\n"
" valuef = inputf.r + inputf.g + inputf.b + inputf.a;\n"
" valuei = inputi.r + inputi.g + inputi.b;\n"
" valueu = inputu.r + inputu.g + inputu.b + inputu.a;\n"
"}\n"
"\n";
std::string source = cs;
return source;
}
bool GetnUniformTest::verifyResult(const void* inputData, const void* resultData, int size, const char* method)
{
int diff = memcmp(inputData, resultData, size);
if (diff != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " result is not as expected."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool GetnUniformTest::verifyError(GLint error, GLint expectedError, const char* method)
{
if (error != expectedError)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
<< error << "]." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** Constructor
*
* @param context Test context
**/
ReadnPixelsTest::ReadnPixelsTest(deqp::Context& context)
: TestCase(context, "readnpixels", "Verifies if read pixels to the buffer with bufSize less than expected result "
"with GL_INVALID_OPERATION error")
, m_pReadnPixels(DE_NULL)
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ReadnPixelsTest::iterate()
{
if (!checkExtension(m_context, "GL_KHR_robustness") ||
!checkExtension(m_context, "GL_KHR_robust_buffer_access_behavior"))
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
m_pReadnPixels = (PFNGLREADNPIXELS)m_context.getRenderContext().getProcAddress("glReadnPixels");
if (DE_NULL == m_pReadnPixels)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_INTERNAL_ERROR,
"Pointer to function glReadnPixels is NULL.");
return STOP;
}
static const GLuint elements[] = {
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
};
static const GLfloat vertices[] = {
0.0f, 0.0f, 0.0f, 1.0f, /* 0 */
-1.0f, 0.0f, 0.0f, 1.0f, /* 1 */
-1.0f, 1.0f, 0.0f, 1.0f, /* 2 */
0.0f, 1.0f, 0.0f, 1.0f, /* 3 */
1.0f, 1.0f, 0.0f, 1.0f, /* 4 */
1.0f, 0.0f, 0.0f, 1.0f, /* 5 */
1.0f, -1.0f, 0.0f, 1.0f, /* 6 */
0.0f, -1.0f, 0.0f, 1.0f, /* 7 */
-1.0f, -1.0f, 0.0f, 1.0f, /* 8 */
};
static const GLchar* fs = "#version 320 es\n"
"\n"
"layout (location = 0) out lowp vec4 out_fs_color;\n"
"\n"
"void main()\n"
"{\n"
" out_fs_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n"
"\n";
static const GLchar* vs = "#version 320 es\n"
"\n"
"layout (location = 0) in vec4 in_vs_position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = in_vs_position;\n"
"}\n"
"\n";
static const GLuint height = 8;
static const GLuint width = 8;
static const GLuint n_vertices = 24;
/* GL entry points */
const Functions& gl = m_context.getRenderContext().getFunctions();
/* Test case objects */
Program program(m_context);
Texture texture(m_context);
Buffer elements_buffer(m_context);
Buffer vertices_buffer(m_context);
VertexArray vao(m_context);
/* Vertex array initialization */
VertexArray::Generate(gl, vao.m_id);
VertexArray::Bind(gl, vao.m_id);
/* Texture initialization */
Texture::Generate(gl, texture.m_id);
Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
Texture::Bind(gl, 0, GL_TEXTURE_2D);
/* Framebuffer initialization */
GLuint fbo;
gl.genFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_id, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
/* Buffers initialization */
elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(elements), elements);
vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
/* Shaders initialization */
program.Init("" /* cs */, fs, "" /* gs */, "" /* tcs */, "" /* tes */, vs);
Program::Use(gl, program.m_id);
/* Vertex buffer initialization */
vertices_buffer.Bind();
gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 16 /* stride */);
gl.enableVertexAttribArray(0 /* location */);
/* Binding elements/indices buffer */
elements_buffer.Bind();
cleanTexture(texture.m_id);
gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
/* Set result */
if (verifyResults())
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Fill texture with value 128
*
* @param texture_id Id of texture
**/
void ReadnPixelsTest::cleanTexture(glw::GLuint texture_id)
{
static const GLuint height = 8;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
GLubyte pixels[width * height];
for (GLuint i = 0; i < width * height; ++i)
{
pixels[i] = 64;
}
Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
/* Unbind */
Texture::Bind(gl, 0, GL_TEXTURE_2D);
}
/** Verifies glReadnPixels results
*
* @return true when glReadnPixels , false otherwise
**/
bool ReadnPixelsTest::verifyResults()
{
static const GLuint height = 8;
static const GLuint width = 8;
const Functions& gl = m_context.getRenderContext().getFunctions();
//Valid buffer size test
const GLint bufSizeValid = width * height;
GLubyte pixelsValid[bufSizeValid];
m_pReadnPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bufSizeValid, pixelsValid);
GLU_EXPECT_NO_ERROR(gl.getError(), "ReadnPixels");
//Verify glReadnPixels result
for (GLuint i = 0; i < width * height; ++i)
{
if (pixelsValid[i] != 255)
return false;
}
//Invalid buffer size test
const GLint bufSizeInvalid = width * height - 1;
GLubyte pixelsInvalid[bufSizeInvalid];
m_pReadnPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bufSizeInvalid, pixelsInvalid);
if (!verifyError(gl.getError(), GL_INVALID_OPERATION, "ReadnPixels [false positive]"))
return false;
return true;
}
/** Verify operation errors
*
* @param error OpenGL ES error code
* @param expectedError Expected error code
* @param method Method name marker
*
* @return true when error is as expected, false otherwise
**/
bool ReadnPixelsTest::verifyError(GLint error, GLint expectedError, const char* method)
{
if (error != expectedError)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
<< error << "]." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
} // RobustBufferAccessBehavior namespace
RobustnessTests::RobustnessTests(deqp::Context& context)
: TestCaseGroup(context, "robustness", "Verifies API coverage and functionality of GL_KHR_robustness extension.")
{
}
void RobustnessTests::init()
{
deqp::TestCaseGroup::init();
try
{
addChild(new ResetNotificationStrategy::NoResetNotificationCase(
m_context, "noResetNotification", "Verifies if NO_RESET_NOTIFICATION strategy works as expected."));
addChild(new ResetNotificationStrategy::LoseContextOnResetCase(
m_context, "loseContextOnReset", "Verifies if LOSE_CONTEXT_ON_RESET strategy works as expected."));
addChild(new RobustnessRobustBufferAccessBehavior::GetnUniformTest(m_context));
addChild(new RobustnessRobustBufferAccessBehavior::ReadnPixelsTest(m_context));
}
catch (...)
{
// Destroy context.
deqp::TestCaseGroup::deinit();
throw;
}
}
} // es32cts namespace