blob: f166cc60c6cca07f2a13a2ab531b20728af139c8 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2014-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 glcViewportArrayTests.cpp
* \brief Implements conformance tests for "Viewport Array" functionality.
*/ /*-------------------------------------------------------------------*/
#include "glcViewportArrayTests.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "gluStrUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuTestLog.hpp"
#include <algorithm>
#include <iomanip>
#include <string>
#include <vector>
using namespace glw;
namespace glcts
{
namespace ViewportArray
{
/** Constructor.
*
* @param context CTS context.
**/
Utils::buffer::buffer(deqp::Context& context) : m_id(0), m_context(context), m_target(0)
{
}
/** Destructor
*
**/
Utils::buffer::~buffer()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteBuffers(1, &m_id);
m_id = 0;
}
}
/** Execute BindBuffer
*
**/
void Utils::buffer::bind() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(m_target, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
}
/** Execute BindBufferRange
*
* @param index <index> parameter
* @param offset <offset> parameter
* @param size <size> parameter
**/
void Utils::buffer::bindRange(glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBufferRange(m_target, index, m_id, offset, size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
}
/** Execute GenBuffer
*
* @param target Target that will be used by this buffer
**/
void Utils::buffer::generate(glw::GLenum target)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
m_target = target;
gl.genBuffers(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
}
/** Maps buffer content
*
* @param access Access rights for mapped region
*
* @return Mapped memory
**/
void* Utils::buffer::map(GLenum access) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(m_target, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
void* result = gl.mapBuffer(m_target, access);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
return result;
}
/** Unmaps buffer
*
**/
void Utils::buffer::unmap() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(m_target, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
gl.unmapBuffer(m_target);
GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
}
/** Execute BufferData
*
* @param size <size> parameter
* @param data <data> parameter
* @param usage <usage> parameter
**/
void Utils::buffer::update(glw::GLsizeiptr size, glw::GLvoid* data, glw::GLenum usage)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(m_target, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
gl.bufferData(m_target, size, data, usage);
GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
}
/** Constructor
*
* @param context CTS context
**/
Utils::framebuffer::framebuffer(deqp::Context& context) : m_id(0), m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Utils::framebuffer::~framebuffer()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteFramebuffers(1, &m_id);
m_id = 0;
}
}
/** Attach texture to specified attachment
*
* @param attachment Attachment
* @param texture_id Texture id
* @param width Texture width
* @param height Texture height
**/
void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
glw::GLuint height)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bind();
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, attachment, texture_id, 0 /* 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
*
**/
void Utils::framebuffer::bind()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
}
/** Clear framebuffer
*
* @param mask <mask> parameter of glClear. Decides which shall be cleared
**/
void Utils::framebuffer::clear(glw::GLenum mask)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clear(mask);
GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
}
/** Specifies clear color
*
* @param red Red channel
* @param green Green channel
* @param blue Blue channel
* @param alpha Alpha channel
**/
void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clearColor(red, green, blue, alpha);
GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
}
/** Generate framebuffer
*
**/
void Utils::framebuffer::generate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genFramebuffers(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
}
Utils::shaderCompilationException::shaderCompilationException(const glw::GLchar* source, const glw::GLchar* message)
: m_shader_source(source), m_error_message(message)
{
/* Nothing to be done */
}
const char* Utils::shaderCompilationException::what() const throw()
{
return "Shader compilation failed";
}
Utils::programLinkageException::programLinkageException(const glw::GLchar* message) : m_error_message(message)
{
/* Nothing to be done */
}
const char* Utils::programLinkageException::what() const throw()
{
return "Program linking failed";
}
const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
/** Constructor.
*
* @param context CTS context.
**/
Utils::program::program(deqp::Context& context)
: m_compute_shader_id(0)
, m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_program_object_id(0)
, m_tesselation_control_shader_id(0)
, m_tesselation_evaluation_shader_id(0)
, m_vertex_shader_id(0)
, m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Utils::program::~program()
{
remove();
}
/** Build program
*
* @param compute_shader_code Compute shader source code
* @param fragment_shader_code Fragment shader source code
* @param geometry_shader_code Geometry shader source code
* @param tesselation_control_shader_code Tesselation control shader source code
* @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
* @param vertex_shader_code Vertex shader source code
* @param varying_names Array of strings containing names of varyings to be captured with transfrom feedback
* @param n_varying_names Number of varyings to be captured with transfrom feedback
* @param is_separable Selects if monolithis or separable program should be built. Defaults to false
**/
void Utils::program::build(const glw::GLchar* compute_shader_code, const glw::GLchar* fragment_shader_code,
const glw::GLchar* geometry_shader_code, const glw::GLchar* tesselation_control_shader_code,
const glw::GLchar* tesselation_evaluation_shader_code, const glw::GLchar* vertex_shader_code,
const glw::GLchar* const* varying_names, glw::GLuint n_varying_names, bool is_separable)
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create shader objects and compile */
if (0 != compute_shader_code)
{
m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_compute_shader_id, compute_shader_code);
}
if (0 != fragment_shader_code)
{
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_fragment_shader_id, fragment_shader_code);
}
if (0 != geometry_shader_code)
{
m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_geometry_shader_id, geometry_shader_code);
}
if (0 != tesselation_control_shader_code)
{
m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
}
if (0 != tesselation_evaluation_shader_code)
{
m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
}
if (0 != vertex_shader_code)
{
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_vertex_shader_id, vertex_shader_code);
}
/* Create program object */
m_program_object_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
/* Set up captyured varyings' names */
if (0 != n_varying_names)
{
gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
}
/* Set separable parameter */
if (true == is_separable)
{
gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
}
/* Link program */
link();
}
void Utils::program::compile(GLuint shader_id, const GLchar* source) const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Compilation status */
glw::GLint status = GL_FALSE;
/* Set source code */
gl.shaderSource(shader_id, 1 /* count */, &source, 0 /* lengths */);
GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
/* Compile */
gl.compileShader(shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
/* Get compilation status */
gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Log compilation error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Error log length */
gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Prepare storage */
message.resize(length);
/* Get error log */
gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
throw shaderCompilationException(source, &message[0]);
}
}
glw::GLint Utils::program::getAttribLocation(const glw::GLchar* name) const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint location = gl.getAttribLocation(m_program_object_id, name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetAttribLocation");
return location;
}
/** Get subroutine index
*
* @param subroutine_name Subroutine name
*
* @return Index of subroutine
**/
GLuint Utils::program::getSubroutineIndex(const glw::GLchar* subroutine_name, glw::GLenum shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLuint index = -1;
index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
if (GL_INVALID_INDEX == index)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Subroutine is not available");
}
return index;
}
/** Get subroutine uniform location
*
* @param uniform_name Subroutine uniform name
*
* @return Location of subroutine uniform
**/
GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar* uniform_name, glw::GLenum shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint location = -1;
location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
if (-1 == location)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Subroutine uniform is not available");
}
return location;
}
/** Get uniform location
*
* @param uniform_name Subroutine uniform name
*
* @return Location of uniform
**/
GLint Utils::program::getUniformLocation(const glw::GLchar* uniform_name) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint location = -1;
location = gl.getUniformLocation(m_program_object_id, uniform_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
if (-1 == location)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Uniform is not available");
}
return location;
}
/** Attach shaders and link program
*
**/
void Utils::program::link() const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Link status */
glw::GLint status = GL_FALSE;
/* Attach shaders */
if (0 != m_compute_shader_id)
{
gl.attachShader(m_program_object_id, m_compute_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_fragment_shader_id)
{
gl.attachShader(m_program_object_id, m_fragment_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_geometry_shader_id)
{
gl.attachShader(m_program_object_id, m_geometry_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_tesselation_control_shader_id)
{
gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_tesselation_evaluation_shader_id)
{
gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_vertex_shader_id)
{
gl.attachShader(m_program_object_id, m_vertex_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
/* Link */
gl.linkProgram(m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
/* Get link status */
gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
/* Log link error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Get error log length */
gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
message.resize(length);
/* Get error log */
gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
throw programLinkageException(&message[0]);
}
}
/** Delete program object and all attached shaders
*
**/
void Utils::program::remove()
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Make sure program object is no longer used by GL */
gl.useProgram(0);
/* Clean program object */
if (0 != m_program_object_id)
{
gl.deleteProgram(m_program_object_id);
m_program_object_id = 0;
}
/* Clean shaders */
if (0 != m_compute_shader_id)
{
gl.deleteShader(m_compute_shader_id);
m_compute_shader_id = 0;
}
if (0 != m_fragment_shader_id)
{
gl.deleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (0 != m_geometry_shader_id)
{
gl.deleteShader(m_geometry_shader_id);
m_geometry_shader_id = 0;
}
if (0 != m_tesselation_control_shader_id)
{
gl.deleteShader(m_tesselation_control_shader_id);
m_tesselation_control_shader_id = 0;
}
if (0 != m_tesselation_evaluation_shader_id)
{
gl.deleteShader(m_tesselation_evaluation_shader_id);
m_tesselation_evaluation_shader_id = 0;
}
if (0 != m_vertex_shader_id)
{
gl.deleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
}
/** Execute UseProgram
*
**/
void Utils::program::use() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
}
void Utils::program::printShaderSource(const GLchar* source, tcu::MessageBuilder& log)
{
GLuint line_number = 0;
log << "Shader source.";
log << "\nLine||Source\n";
while (0 != source)
{
std::string line;
const GLchar* next_line = strchr(source, '\n');
if (0 != next_line)
{
next_line += 1;
line.assign(source, next_line - source);
}
else
{
line = source;
}
if (0 != *source)
{
log << std::setw(4) << line_number << "||" << line;
}
source = next_line;
line_number += 1;
}
}
/** Constructor.
*
* @param context CTS context.
**/
Utils::texture::texture(deqp::Context& context)
: m_id(0), m_width(0), m_height(0), m_depth(0), m_context(context), m_is_array(false)
{
/* Nothing to done here */
}
/** Destructor
*
**/
Utils::texture::~texture()
{
release();
}
/** Bind texture to GL_TEXTURE_2D
*
**/
void Utils::texture::bind() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (false == m_is_array)
{
gl.bindTexture(GL_TEXTURE_2D, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
}
else
{
gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
}
}
/** Create 2d texture
*
* @param width Width of texture
* @param height Height of texture
* @param internal_format Internal format of texture
**/
void Utils::texture::create(GLuint width, GLuint height, GLenum internal_format)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
release();
m_width = width;
m_height = height;
m_depth = 1;
m_is_array = false;
gl.genTextures(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
bind();
gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
}
/** Create 2d texture array
*
* @param width Width of texture
* @param height Height of texture
* @param depth Depth of texture
* @param internal_format Internal format of texture
**/
void Utils::texture::create(GLuint width, GLuint height, GLuint depth, GLenum internal_format)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
release();
m_width = width;
m_height = height;
m_depth = depth;
m_is_array = true;
gl.genTextures(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
bind();
gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, internal_format, width, height, depth);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
}
/** Get contents of texture
*
* @param format Format of image
* @param type Type of image
* @param out_data Buffer for image
**/
void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glu::ContextType& context_type = m_context.getRenderContext().getType();
bind();
GLenum textarget = GL_TEXTURE_2D;
if (true == m_is_array)
{
textarget = GL_TEXTURE_2D_ARRAY;
}
if (glu::isContextTypeGLCore(context_type))
{
gl.getTexImage(textarget, 0 /* level */, format, type, out_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
GLuint temp_fbo = 0;
gl.genFramebuffers(1, &temp_fbo);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, temp_fbo);
/* OpenGL ES only guarantees support for RGBA formats of each type.
Since the tests are only expecting single-channel formats, we read them back
in RGBA to a temporary buffer and then copy only the first component
to the actual output buffer */
GLenum read_format = format;
switch (format)
{
case GL_RED:
read_format = GL_RGBA;
break;
case GL_RED_INTEGER:
read_format = GL_RGBA_INTEGER;
break;
default:
TCU_FAIL("unexpected format");
}
/* we can get away just handling one type of data, as long as the components are the same size */
if (type != GL_INT && type != GL_FLOAT)
{
TCU_FAIL("unexpected type");
}
std::vector<GLint> read_data;
const GLuint layer_size = m_width * m_height * 4;
read_data.resize(layer_size * m_depth);
if (m_is_array)
{
for (GLuint layer = 0; layer < m_depth; ++layer)
{
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_id, 0, layer);
gl.readPixels(0, 0, m_width, m_height, read_format, type, &read_data[layer * layer_size]);
}
}
else
{
gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, m_id, 0);
gl.readPixels(0, 0, m_width, m_height, read_format, type, &read_data[0]);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
gl.deleteFramebuffers(1, &temp_fbo);
/* copy the first channel from the readback buffer to the output buffer */
GLint* out_data_int = (GLint*)out_data;
for (GLuint elem = 0; elem < (m_width * m_height * m_depth); ++elem)
{
out_data_int[elem] = read_data[elem * 4];
}
}
}
/** Delete texture
*
**/
void Utils::texture::release()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteTextures(1, &m_id);
m_id = 0;
}
}
/** Update contents of texture
*
* @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
**/
void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format,
glw::GLenum type, glw::GLvoid* data)
{
static const GLuint level = 0;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bind();
if (false == m_is_array)
{
gl.texSubImage2D(GL_TEXTURE_2D, level, 0 /* x */, 0 /* y */, width, height, format, type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
}
else
{
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth, format,
type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
}
}
/** Constructor.
*
* @param context CTS context.
**/
Utils::vertexArray::vertexArray(deqp::Context& context) : m_id(0), m_context(context)
{
}
/** Destructor
*
**/
Utils::vertexArray::~vertexArray()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteVertexArrays(1, &m_id);
m_id = 0;
}
}
/** Execute BindVertexArray
*
**/
void Utils::vertexArray::bind()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindVertexArray(m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
}
/** Execute GenVertexArrays
*
**/
void Utils::vertexArray::generate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genVertexArrays(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
}
/** Constructor
*
* @param context Test context
**/
APIErrors::APIErrors(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "api_errors", "Test verifies error generated by API")
{
/* Nothing to be done here */
}
template <typename T>
void APIErrors::depthRangeArrayHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
{
std::vector<T> data;
data.resize(max_viewports * 2 /* near + far */);
for (GLint i = 0; i < max_viewports; ++i)
{
data[i * 2] = (T)0.0;
data[i * 2 + 1] = (T)1.0;
}
depthFunc.depthRangeArray(0, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "depthRangeArray, correct parameters", test_result);
depthFunc.depthRangeArray(max_viewports, 1, &data[0]);
checkGLError(GL_INVALID_VALUE, "depthRangeArray, <first> == GL_MAX_VIEWPORTS", test_result);
depthFunc.depthRangeArray(1, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "depthRangeArray, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
depthFunc.depthRangeArray(1, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "depthRangeArray, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
}
template <typename T>
void APIErrors::depthRangeIndexedHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
{
depthFunc.depthRangeIndexed(0 /* index */, (T)0.0, (T)1.0);
checkGLError(GL_NO_ERROR, "depthRangeIndexed, <index> == 0", test_result);
depthFunc.depthRangeIndexed(max_viewports - 1 /* index */, (T)0.0, (T)1.0);
checkGLError(GL_NO_ERROR, "depthRangeIndexed, <index> == GL_MAX_VIEWPORTS - 1", test_result);
depthFunc.depthRangeIndexed(max_viewports /* index */, (T)0.0, (T)1.0);
checkGLError(GL_INVALID_VALUE, "depthRangeIndexed, <index> == GL_MAX_VIEWPORTS", test_result);
depthFunc.depthRangeIndexed(max_viewports + 1 /* index */, (T)0.0, (T)1.0);
checkGLError(GL_INVALID_VALUE, "depthRangeIndexed, <index> > GL_MAX_VIEWPORTS", test_result);
}
template <typename T>
void APIErrors::getDepthHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
{
T data[4];
depthFunc.getDepthi_v(GL_DEPTH_RANGE, max_viewports - 1, data);
checkGLError(GL_NO_ERROR, "getDouble/Floati_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
depthFunc.getDepthi_v(GL_DEPTH_RANGE, max_viewports, data);
checkGLError(GL_INVALID_VALUE, "getDouble/Floati_v, <index> == GL_MAX_VIEWPORTS", test_result);
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult APIErrors::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glu::ContextType& context_type = m_context.getRenderContext().getType();
Utils::DepthFuncWrapper depthFunc(m_context);
/* Test result */
bool test_result = true;
GLint max_viewports = 0;
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
/*
* * DepthRangeArrayv generates INVALID_VALUE when <first> + <count> is greater
* than or equal to the value of MAX_VIEWPORTS;
*/
if (glu::isContextTypeGLCore(context_type))
{
depthRangeArrayHelper<GLdouble>(depthFunc, max_viewports, test_result);
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
depthRangeArrayHelper<GLfloat>(depthFunc, max_viewports, test_result);
}
/*
* * DepthRangeIndexed generates INVALID_VALUE when <index> is greater than or
* equal to the value of MAX_VIEWPORTS;
*/
if (glu::isContextTypeGLCore(context_type))
{
depthRangeIndexedHelper<GLdouble>(depthFunc, max_viewports, test_result);
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
depthRangeIndexedHelper<GLfloat>(depthFunc, max_viewports, test_result);
}
/*
* * ViewportArrayv generates INVALID_VALUE when <first> + <count> is greater
* than or equal to the value of MAX_VIEWPORTS;
*/
{
std::vector<GLfloat> data;
data.resize(max_viewports * 4 /* x + y + w + h */);
for (GLint i = 0; i < max_viewports; ++i)
{
data[i * 4 + 0] = 0.0f;
data[i * 4 + 1] = 0.0f;
data[i * 4 + 2] = 1.0f;
data[i * 4 + 3] = 1.0f;
}
gl.viewportArrayv(0, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "viewportArrayv, correct parameters", test_result);
gl.viewportArrayv(max_viewports, 1, &data[0]);
checkGLError(GL_INVALID_VALUE, "viewportArrayv, <first> == GL_MAX_VIEWPORTS", test_result);
gl.viewportArrayv(1, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "viewportArrayv, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
gl.viewportArrayv(1, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "viewportArrayv, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
}
/*
* * ViewportIndexedf and ViewportIndexedfv generate INVALID_VALUE when <index>
* is greater than or equal to the value of MAX_VIEWPORTS;
*/
{
GLfloat data[4 /* x + y + w + h */];
data[0] = 0.0f;
data[1] = 0.0f;
data[2] = 1.0f;
data[3] = 1.0f;
gl.viewportIndexedf(0 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
checkGLError(GL_NO_ERROR, "viewportIndexedf, <index> == 0", test_result);
gl.viewportIndexedf(max_viewports - 1 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
checkGLError(GL_NO_ERROR, "viewportIndexedf, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.viewportIndexedf(max_viewports /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
checkGLError(GL_INVALID_VALUE, "viewportIndexedf, <index> == GL_MAX_VIEWPORTS", test_result);
gl.viewportIndexedf(max_viewports + 1 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
checkGLError(GL_INVALID_VALUE, "viewportIndexedf, <index> > GL_MAX_VIEWPORTS", test_result);
gl.viewportIndexedfv(0 /* index */, data);
checkGLError(GL_NO_ERROR, "viewportIndexedfv, <index> == 0", test_result);
gl.viewportIndexedfv(max_viewports - 1 /* index */, data);
checkGLError(GL_NO_ERROR, "viewportIndexedfv, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.viewportIndexedfv(max_viewports /* index */, data);
checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, <index> == GL_MAX_VIEWPORTS", test_result);
gl.viewportIndexedfv(max_viewports + 1 /* index */, data);
checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, <index> > GL_MAX_VIEWPORTS", test_result);
}
/*
* * ViewportArrayv, Viewport, ViewportIndexedf and ViewportIndexedfv generate
* INVALID_VALUE when <w> or <h> values are negative;
*/
{
gl.viewport(0, 0, -1, 1);
checkGLError(GL_INVALID_VALUE, "viewport, negative width", test_result);
gl.viewport(0, 0, 1, -1);
checkGLError(GL_INVALID_VALUE, "viewport, negative height", test_result);
for (GLint i = 0; i < max_viewports; ++i)
{
std::vector<GLfloat> data;
data.resize(max_viewports * 4 /* x + y + w + h */);
for (GLint j = 0; j < max_viewports; ++j)
{
data[j * 4 + 0] = 0.0f;
data[j * 4 + 1] = 0.0f;
data[j * 4 + 2] = 1.0f;
data[j * 4 + 3] = 1.0f;
}
/* Set width to -1 */
data[i * 4 + 2] = -1.0f;
gl.viewportArrayv(0, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "viewportArrayv, negative width", test_result);
gl.viewportIndexedf(i /* index */, 0.0f, 0.0f, -1.0f, 1.0f);
checkGLError(GL_INVALID_VALUE, "viewportIndexedf, negative width", test_result);
gl.viewportIndexedfv(i /* index */, &data[i * 4]);
checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, negative width", test_result);
/* Set width to 1 and height to -1*/
data[i * 4 + 2] = 1.0f;
data[i * 4 + 3] = -1.0f;
gl.viewportArrayv(0, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "viewportArrayv, negative height", test_result);
gl.viewportIndexedf(i /* index */, 0.0f, 0.0f, 1.0f, -1.0f);
checkGLError(GL_INVALID_VALUE, "viewportIndexedf, negative height", test_result);
gl.viewportIndexedfv(i /* index */, &data[i * 4]);
checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, negative height", test_result);
}
}
/*
* * ScissorArrayv generates INVALID_VALUE when <first> + <count> is greater
* than or equal to the value of MAX_VIEWPORTS;
*/
{
std::vector<GLint> data;
data.resize(max_viewports * 4 /* x + y + w + h */);
for (GLint i = 0; i < max_viewports; ++i)
{
data[i * 4 + 0] = 0;
data[i * 4 + 1] = 0;
data[i * 4 + 2] = 1;
data[i * 4 + 3] = 1;
}
gl.scissorArrayv(0, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "scissorArrayv, correct parameters", test_result);
gl.scissorArrayv(max_viewports, 1, &data[0]);
checkGLError(GL_INVALID_VALUE, "scissorArrayv, <first> == GL_MAX_VIEWPORTS", test_result);
gl.scissorArrayv(1, max_viewports - 1, &data[0]);
checkGLError(GL_NO_ERROR, "scissorArrayv, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
gl.scissorArrayv(1, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "scissorArrayv, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
}
/*
* * ScissorIndexed and ScissorIndexedv generate INVALID_VALUE when <index> is
* greater than or equal to the value of MAX_VIEWPORTS;
*/
{
GLint data[4 /* x + y + w + h */];
data[0] = 0;
data[1] = 0;
data[2] = 1;
data[3] = 1;
gl.scissorIndexed(0 /* index */, 0, 0, 1, 1);
checkGLError(GL_NO_ERROR, "scissorIndexed, <index> == 0", test_result);
gl.scissorIndexed(max_viewports - 1 /* index */, 0, 0, 1, 1);
checkGLError(GL_NO_ERROR, "scissorIndexed, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.scissorIndexed(max_viewports /* index */, 0, 0, 1, 1);
checkGLError(GL_INVALID_VALUE, "scissorIndexed, <index> == GL_MAX_VIEWPORTS", test_result);
gl.scissorIndexed(max_viewports + 1 /* index */, 0, 0, 1, 1);
checkGLError(GL_INVALID_VALUE, "scissorIndexed, <index> > GL_MAX_VIEWPORTS", test_result);
gl.scissorIndexedv(0 /* index */, data);
checkGLError(GL_NO_ERROR, "scissorIndexedv, <index> == 0", test_result);
gl.scissorIndexedv(max_viewports - 1 /* index */, data);
checkGLError(GL_NO_ERROR, "scissorIndexedv, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.scissorIndexedv(max_viewports /* index */, data);
checkGLError(GL_INVALID_VALUE, "scissorIndexedv, <index> == GL_MAX_VIEWPORTS", test_result);
gl.scissorIndexedv(max_viewports + 1 /* index */, data);
checkGLError(GL_INVALID_VALUE, "scissorIndexedv, <index> > GL_MAX_VIEWPORTS", test_result);
}
/*
* * ScissorArrayv, ScissorIndexed, ScissorIndexedv and Scissor generate
* INVALID_VALUE when <width> or <height> values are negative;
*/
{
gl.scissor(0, 0, -1, 1);
checkGLError(GL_INVALID_VALUE, "scissor, negative width", test_result);
gl.scissor(0, 0, 1, -1);
checkGLError(GL_INVALID_VALUE, "scissor, negative height", test_result);
for (GLint i = 0; i < max_viewports; ++i)
{
std::vector<GLint> data;
data.resize(max_viewports * 4 /* x + y + w + h */);
for (GLint j = 0; j < max_viewports; ++j)
{
data[j * 4 + 0] = 0;
data[j * 4 + 1] = 0;
data[j * 4 + 2] = 1;
data[j * 4 + 3] = 1;
}
/* Set width to -1 */
data[i * 4 + 2] = -1;
gl.scissorArrayv(0, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "scissorArrayv, negative width", test_result);
gl.scissorIndexed(i /* index */, 0, 0, -1, 1);
checkGLError(GL_INVALID_VALUE, "scissorIndexed, negative width", test_result);
gl.scissorIndexedv(i /* index */, &data[i * 4]);
checkGLError(GL_INVALID_VALUE, "scissorIndexedv, negative width", test_result);
/* Set width to 1 and height to -1*/
data[i * 4 + 2] = 1;
data[i * 4 + 3] = -1;
gl.scissorArrayv(0, max_viewports, &data[0]);
checkGLError(GL_INVALID_VALUE, "scissorArrayv, negative height", test_result);
gl.scissorIndexed(i /* index */, 0, 0, 1, -1);
checkGLError(GL_INVALID_VALUE, "scissorIndexed, negative height", test_result);
gl.scissorIndexedv(i /* index */, &data[i * 4]);
checkGLError(GL_INVALID_VALUE, "scissorIndexedv, negative height", test_result);
}
}
/*
* * Disablei, Enablei and IsEnabledi generate INVALID_VALUE when <cap> is
* SCISSOR_TEST and <index> is greater than or equal to the
* value of MAX_VIEWPORTS;
*/
{
gl.disablei(GL_SCISSOR_TEST, max_viewports - 1);
checkGLError(GL_NO_ERROR, "disablei, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.disablei(GL_SCISSOR_TEST, max_viewports);
checkGLError(GL_INVALID_VALUE, "disablei, <index> == GL_MAX_VIEWPORTS", test_result);
gl.enablei(GL_SCISSOR_TEST, max_viewports - 1);
checkGLError(GL_NO_ERROR, "enablei, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.enablei(GL_SCISSOR_TEST, max_viewports);
checkGLError(GL_INVALID_VALUE, "enablei, <index> == GL_MAX_VIEWPORTS", test_result);
gl.isEnabledi(GL_SCISSOR_TEST, max_viewports - 1);
checkGLError(GL_NO_ERROR, "isEnabledi, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.isEnabledi(GL_SCISSOR_TEST, max_viewports);
checkGLError(GL_INVALID_VALUE, "isEnabledi, <index> == GL_MAX_VIEWPORTS", test_result);
}
/*
* * GetIntegeri_v generates INVALID_VALUE when <target> is SCISSOR_BOX and
* <index> is greater than or equal to the value of MAX_VIEWPORTS;
*/
{
GLint data[4];
gl.getIntegeri_v(GL_SCISSOR_BOX, max_viewports - 1, data);
checkGLError(GL_NO_ERROR, "getIntegeri_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.getIntegeri_v(GL_SCISSOR_BOX, max_viewports, data);
checkGLError(GL_INVALID_VALUE, "getIntegeri_v, <index> == GL_MAX_VIEWPORTS", test_result);
}
/*
* * GetFloati_v generates INVALID_VALUE when <target> is VIEWPORT and <index>
* is greater than or equal to the value of MAX_VIEWPORTS;
*/
{
GLfloat data[4];
gl.getFloati_v(GL_VIEWPORT, max_viewports - 1, data);
checkGLError(GL_NO_ERROR, "getFloati_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
gl.getFloati_v(GL_VIEWPORT, max_viewports, data);
checkGLError(GL_INVALID_VALUE, "getFloati_v, <index> == GL_MAX_VIEWPORTS", test_result);
}
/*
* * GetDoublei_v generates INVALID_VALUE when <target> is DEPTH_RANGE and
* <index> is greater than or equal to the value of MAX_VIEWPORTS;
*/
if (glu::isContextTypeGLCore(context_type))
{
getDepthHelper<GLdouble>(depthFunc, max_viewports, test_result);
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
getDepthHelper<GLfloat>(depthFunc, max_viewports, test_result);
}
/* 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;
}
/** Check if glGetError returns expected error
*
* @param expected_error Expected error code
* @param description Description of test case
* @param out_result Set to false if the current error is not equal to expected one
**/
void APIErrors::checkGLError(GLenum expected_error, const GLchar* description, bool& out_result)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLenum error = gl.getError();
if (expected_error != error)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case fail. Description: " << description
<< " Invalid error: " << glu::getErrorStr(error)
<< " expected: " << glu::getErrorStr(expected_error)
<< tcu::TestLog::EndMessage;
out_result = false;
}
}
/** Constructor
*
* @param context Test context
**/
Queries::Queries(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "queries", "Test verifies initial state of API")
{
/* Nothing to be done here */
}
template <typename T>
void Queries::depthRangeInitialValuesHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result,
T*)
{
std::vector<T> data;
data.resize(max_viewports * 2 /* near + far */);
for (GLint i = 0; i < max_viewports; ++i)
{
depthFunc.getDepthi_v(GL_DEPTH_RANGE, i, &data[i * 2]);
GLU_EXPECT_NO_ERROR(depthFunc.getFunctions().getError(), "getDouble/Floati_v");
}
for (GLint i = 0; i < max_viewports; ++i)
{
GLint near = (GLint)data[2 * i + 0];
GLint far = (GLint)data[2 * i + 1];
if ((0.0 != near) || (1.0 != far))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial depth range [" << i
<< "]: " << near << " : " << far << " expected: 0.0 : 1.0"
<< tcu::TestLog::EndMessage;
test_result = false;
break;
}
}
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult Queries::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glu::ContextType& context_type = m_context.getRenderContext().getType();
Utils::DepthFuncWrapper depthFunc(m_context);
/* Test result */
bool test_result = true;
GLint layer_provoking_vertex = 0;
GLint max_viewports = 0;
GLfloat max_renderbuffer_size = 0.0f;
GLfloat max_viewport_dims[2] = { 0.0f, 0.0f };
GLfloat viewport_bounds_range[2] = { 0.0, 0.0f };
GLint viewport_provoking_vertex = 0;
GLint viewport_subpixel_bits = -1;
gl.getIntegerv(GL_LAYER_PROVOKING_VERTEX, &layer_provoking_vertex);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
gl.getFloatv(GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
gl.getFloatv(GL_MAX_VIEWPORT_DIMS, max_viewport_dims);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloatv");
gl.getFloatv(GL_VIEWPORT_BOUNDS_RANGE, viewport_bounds_range);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloatv");
gl.getIntegerv(GL_VIEWPORT_INDEX_PROVOKING_VERTEX, &viewport_provoking_vertex);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
gl.getIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &viewport_subpixel_bits);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
const GLint window_width = m_context.getRenderContext().getRenderTarget().getWidth();
const GLint window_height = m_context.getRenderContext().getRenderTarget().getHeight();
/*
* * Initial dimensions of VIEWPORT returned by GetFloati_v match dimensions of
* the window into which GL is rendering;
*/
{
std::vector<GLfloat> data;
data.resize(max_viewports * 4 /* x + y + w+ h */);
for (GLint i = 0; i < max_viewports; ++i)
{
gl.getFloati_v(GL_VIEWPORT, i, &data[i * 4]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloati_v");
}
for (GLint i = 0; i < max_viewports; ++i)
{
GLint viewport_width = (GLint)data[4 * i + 2];
GLint viewport_height = (GLint)data[4 * i + 3];
if ((window_width != viewport_width) || (window_height != viewport_height))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial viewport [" << i
<< "] dimennsions: " << viewport_width << " x " << viewport_height
<< " expected: " << window_width << " x " << window_height
<< tcu::TestLog::EndMessage;
test_result = false;
break;
}
}
}
/*
* * Initial values of DEPTH_RANGE returned by GetDoublei_v are [0, 1];
*/
if (glu::isContextTypeGLCore(context_type))
{
depthRangeInitialValuesHelper<GLdouble>(depthFunc, max_viewports, test_result);
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
depthRangeInitialValuesHelper<GLfloat>(depthFunc, max_viewports, test_result);
}
/*
* * Initial state of SCISSOR_TEST returned by IsEnabledi is FALSE;
*/
{
for (GLint i = 0; i < max_viewports; ++i)
{
if (GL_FALSE != gl.isEnabledi(GL_SCISSOR_TEST, i))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Scissor test is enabled at " << i
<< ". Expected disabled." << tcu::TestLog::EndMessage;
test_result = false;
break;
}
}
}
/*
* * Initial dimensions of SCISSOR_BOX returned by GetIntegeri_v are either
* zeros or match dimensions of the window into which GL is rendering;
*/
{
std::vector<GLint> data;
data.resize(max_viewports * 4 /* x + y + w+ h */);
for (GLint i = 0; i < max_viewports; ++i)
{
gl.getIntegeri_v(GL_SCISSOR_BOX, i, &data[i * 4]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegeri_v");
}
for (GLint i = 0; i < max_viewports; ++i)
{
GLint scissor_width = data[4 * i + 2];
GLint scissor_height = data[4 * i + 3];
if ((window_width != scissor_width) || (window_height != scissor_height))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial scissor box [" << i
<< "] dimennsions: " << scissor_width << " x " << scissor_height
<< " expected: " << window_width << " x " << window_height
<< tcu::TestLog::EndMessage;
test_result = false;
break;
}
}
}
/*
* * Dimensions of MAX_VIEWPORT_DIMS returned by GetFloati_v are at least
* as big as supported dimensions of render buffers, see MAX_RENDERBUFFER_SIZE;
*/
{
if ((max_viewport_dims[0] < max_renderbuffer_size) || (max_viewport_dims[1] < max_renderbuffer_size))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Invalid MAX_VIEWPORT_DIMS: " << max_viewport_dims[0] << " x "
<< max_viewport_dims[1] << " expected: " << max_renderbuffer_size << " x " << max_renderbuffer_size
<< tcu::TestLog::EndMessage;
test_result = false;
}
}
/*
* * Value of MAX_VIEWPORTS returned by GetIntegeri_v is at least 16;
*/
{
if (16 > max_viewports)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid MAX_VIEWPORTS: " << max_viewports
<< " expected at least 16." << tcu::TestLog::EndMessage;
test_result = false;
}
}
/*
* * Value of VIEWPORT_SUBPIXEL_BITS returned by GetIntegeri_v is at least 0;
*/
{
if (0 > viewport_subpixel_bits)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Invalid VIEWPORT_SUBPIXEL_BITS: " << viewport_subpixel_bits
<< " expected at least 0." << tcu::TestLog::EndMessage;
test_result = false;
}
}
/*
* * Values of VIEWPORT_BOUNDS_RANGE returned by GetFloatv are
* at least [-32768, 32767];
*/
{
if ((-32768.0f < viewport_bounds_range[0]) || (32767.0f > viewport_bounds_range[1]))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Invalid VIEWPORT_BOUNDS_RANGE: " << viewport_bounds_range[0] << " : "
<< viewport_bounds_range[1] << " expected at least: -32768.0f : 32767.0f" << tcu::TestLog::EndMessage;
test_result = false;
}
}
/*
* * Values of LAYER_PROVOKING_VERTEX and VIEWPORT_INDEX_PROVOKING_VERTEX
* returned by GetIntegerv are located in the following set
* { FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, PROVOKING_VERTEX,
* UNDEFINED_VERTEX };
*/
{
switch (layer_provoking_vertex)
{
case GL_FIRST_VERTEX_CONVENTION:
case GL_LAST_VERTEX_CONVENTION:
case GL_PROVOKING_VERTEX:
case GL_UNDEFINED_VERTEX:
break;
default:
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Invalid LAYER_PROVOKING_VERTEX: " << layer_provoking_vertex
<< tcu::TestLog::EndMessage;
test_result = false;
}
switch (viewport_provoking_vertex)
{
case GL_FIRST_VERTEX_CONVENTION:
case GL_LAST_VERTEX_CONVENTION:
case GL_PROVOKING_VERTEX:
case GL_UNDEFINED_VERTEX:
break;
default:
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Invalid LAYER_PROVOKING_VERTEX: " << layer_provoking_vertex
<< tcu::TestLog::EndMessage;
test_result = false;
}
}
/* 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;
}
/* Constants used by ViewportAPI */
const GLuint ViewportAPI::m_n_elements = 4;
/** Constructor
*
* @param context Test context
**/
ViewportAPI::ViewportAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "viewport_api", "Test verifies that \viewport api\" works as expected")
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult ViewportAPI::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test result */
bool test_result = true;
GLint max_viewports = 0;
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
std::vector<GLfloat> scissor_box_data_a;
std::vector<GLfloat> scissor_box_data_b;
scissor_box_data_a.resize(max_viewports * m_n_elements);
scissor_box_data_b.resize(max_viewports * m_n_elements);
/*
* - get initial dimensions of VIEWPORT for all MAX_VIEWPORTS indices;
* - change location and dimensions of all indices at once with
* ViewportArrayv;
* - get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
*/
getViewports(max_viewports, scissor_box_data_a);
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] += 0.125f;
scissor_box_data_a[i * m_n_elements + 1] += 0.125f;
scissor_box_data_a[i * m_n_elements + 2] -= 0.125f;
scissor_box_data_a[i * m_n_elements + 3] -= 0.125f;
}
gl.viewportArrayv(0, max_viewports, &scissor_box_data_a[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewportArrayv");
getViewports(max_viewports, scissor_box_data_b);
compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportArrayv", test_result);
/*
* - for each index:
* * modify with ViewportIndexedf,
* * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_b[i * m_n_elements + 0] = 0.25f;
scissor_box_data_b[i * m_n_elements + 1] = 0.25f;
scissor_box_data_b[i * m_n_elements + 2] = 0.75f;
scissor_box_data_b[i * m_n_elements + 3] = 0.75f;
gl.viewportIndexedf(i, 0.25f, 0.25f, 0.75f, 0.75f);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewportIndexedf");
getViewports(max_viewports, scissor_box_data_a);
compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportIndexedf", test_result);
}
/*
* - for each index:
* * modify with ViewportIndexedfv,
* * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] = 0.375f;
scissor_box_data_a[i * m_n_elements + 1] = 0.375f;
scissor_box_data_a[i * m_n_elements + 2] = 0.625f;
scissor_box_data_a[i * m_n_elements + 3] = 0.625f;
gl.viewportIndexedfv(i, &scissor_box_data_a[i * m_n_elements]);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewportIndexedfv");
getViewports(max_viewports, scissor_box_data_b);
compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportIndexedfv", test_result);
}
/*
* - for each index:
* * modify all indices before and after current one with ViewportArrayv,
* * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
const GLfloat value = (0 == i % 2) ? 1.0f : 0.25f;
for (GLint j = 0; j < i; ++j)
{
scissor_box_data_b[j * m_n_elements + 0] = value;
scissor_box_data_b[j * m_n_elements + 1] = value;
scissor_box_data_b[j * m_n_elements + 2] = value;
scissor_box_data_b[j * m_n_elements + 3] = value;
}
for (GLint j = i + 1; j < max_viewports; ++j)
{
scissor_box_data_b[j * m_n_elements + 0] = value;
scissor_box_data_b[j * m_n_elements + 1] = value;
scissor_box_data_b[j * m_n_elements + 2] = value;
scissor_box_data_b[j * m_n_elements + 3] = value;
}
gl.viewportArrayv(0, max_viewports, &scissor_box_data_b[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewportArrayv");
getViewports(max_viewports, scissor_box_data_a);
compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportArrayv", test_result);
}
/*
* - change location and dimensions of all indices at once with Viewport;
* - get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] = 0.0f;
scissor_box_data_a[i * m_n_elements + 1] = 0.0f;
scissor_box_data_a[i * m_n_elements + 2] = 1.0f;
scissor_box_data_a[i * m_n_elements + 3] = 1.0f;
}
gl.viewport(0, 0, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
getViewports(max_viewports, scissor_box_data_b);
compareViewports(scissor_box_data_a, scissor_box_data_b, "viewport", test_result);
/* 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;
}
/** Compare two sets of viewport data (simple vector comparison)
*
* @param left Left set
* @param right Right set
* @param description Test case description
* @param out_result Set to false if sets are different, not modified otherwise
**/
void ViewportAPI::compareViewports(std::vector<GLfloat>& left, std::vector<GLfloat>& right, const GLchar* description,
bool& out_result)
{
for (size_t i = 0; i < left.size(); ++i)
{
if (left[i] != right[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
<< tcu::TestLog::EndMessage;
out_result = false;
}
}
}
/** Get position of all viewports
*
* @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
* @param data Memory buffer prepared for captured data
**/
void ViewportAPI::getViewports(GLint max_viewports, std::vector<GLfloat>& out_data)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
for (GLint i = 0; i < max_viewports; ++i)
{
gl.getFloati_v(GL_VIEWPORT, i, &out_data[i * 4]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getFloati_v");
}
}
/* Constants used by ScissorAPI */
const GLuint ScissorAPI::m_n_elements = 4;
/** Constructor
*
* @param context Test context
**/
ScissorAPI::ScissorAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "scissor_api", "Test verifies that \"scissor api\" works as expected")
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult ScissorAPI::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test result */
bool test_result = true;
GLint max_viewports = 0;
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
std::vector<GLint> scissor_box_data_a;
std::vector<GLint> scissor_box_data_b;
scissor_box_data_a.resize(max_viewports * m_n_elements);
scissor_box_data_b.resize(max_viewports * m_n_elements);
/*
* - get initial dimensions of SCISSOR_BOX for all MAX_VIEWPORTS indices;
* - change location and dimensions of all indices at once with
* ScissorArrayv;
* - get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
*/
getScissorBoxes(max_viewports, scissor_box_data_a);
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] += 1;
scissor_box_data_a[i * m_n_elements + 1] += 1;
scissor_box_data_a[i * m_n_elements + 2] -= 1;
scissor_box_data_a[i * m_n_elements + 3] -= 1;
}
gl.scissorArrayv(0, max_viewports, &scissor_box_data_a[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "scissorArrayv");
getScissorBoxes(max_viewports, scissor_box_data_b);
compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorArrayv", test_result);
/*
* - for each index:
* * modify with ScissorIndexed,
* * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_b[i * m_n_elements + 0] = 4;
scissor_box_data_b[i * m_n_elements + 1] = 4;
scissor_box_data_b[i * m_n_elements + 2] = 8;
scissor_box_data_b[i * m_n_elements + 3] = 8;
gl.scissorIndexed(i, 4, 4, 8, 8);
GLU_EXPECT_NO_ERROR(gl.getError(), "scissorIndexed");
getScissorBoxes(max_viewports, scissor_box_data_a);
compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorIndexed", test_result);
}
/*
* - for each index:
* * modify with ScissorIndexedv,
* * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] = 8;
scissor_box_data_a[i * m_n_elements + 1] = 8;
scissor_box_data_a[i * m_n_elements + 2] = 12;
scissor_box_data_a[i * m_n_elements + 3] = 12;
gl.scissorIndexedv(i, &scissor_box_data_a[i * m_n_elements]);
GLU_EXPECT_NO_ERROR(gl.getError(), "scissorIndexedv");
getScissorBoxes(max_viewports, scissor_box_data_b);
compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorIndexedv", test_result);
}
/*
* - for each index:
* * modify all indices before and after current one with ScissorArrayv,
* * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
const GLint value = (0 == i % 2) ? 1 : 4;
for (GLint j = 0; j < i; ++j)
{
scissor_box_data_b[j * m_n_elements + 0] = value;
scissor_box_data_b[j * m_n_elements + 1] = value;
scissor_box_data_b[j * m_n_elements + 2] = value;
scissor_box_data_b[j * m_n_elements + 3] = value;
}
for (GLint j = i + 1; j < max_viewports; ++j)
{
scissor_box_data_b[j * m_n_elements + 0] = value;
scissor_box_data_b[j * m_n_elements + 1] = value;
scissor_box_data_b[j * m_n_elements + 2] = value;
scissor_box_data_b[j * m_n_elements + 3] = value;
}
gl.scissorArrayv(0, max_viewports, &scissor_box_data_b[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "scissorArrayv");
getScissorBoxes(max_viewports, scissor_box_data_a);
compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorArrayv", test_result);
}
/*
* - change location and dimensions of all indices at once with Scissor;
* - get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_box_data_a[i * m_n_elements + 0] = 0;
scissor_box_data_a[i * m_n_elements + 1] = 0;
scissor_box_data_a[i * m_n_elements + 2] = 1;
scissor_box_data_a[i * m_n_elements + 3] = 1;
}
gl.scissor(0, 0, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "scissor");
getScissorBoxes(max_viewports, scissor_box_data_b);
compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissor", test_result);
/* 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;
}
/** Compare two sets of scissor box data (simple vector comparison)
*
* @param left Left set
* @param right Right set
* @param description Test case description
* @param out_result Set to false if sets are different, not modified otherwise
**/
void ScissorAPI::compareScissorBoxes(std::vector<GLint>& left, std::vector<GLint>& right, const GLchar* description,
bool& out_result)
{
for (size_t i = 0; i < left.size(); ++i)
{
if (left[i] != right[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
<< tcu::TestLog::EndMessage;
out_result = false;
}
}
}
/** Get position of all scissor boxes
*
* @param max_viewports Number of scissor boxes to capture, MAX_VIEWPORTS
* @param data Memory buffer prepared for captured data
**/
void ScissorAPI::getScissorBoxes(GLint max_viewports, std::vector<GLint>& out_data)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
for (GLint i = 0; i < max_viewports; ++i)
{
gl.getIntegeri_v(GL_SCISSOR_BOX, i, &out_data[i * 4]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegeri_v");
}
}
/* Constants used by DepthRangeAPI */
const GLuint DepthRangeAPI::m_n_elements = 2 /* near + far */;
/** Constructor
*
* @param context Test context
**/
DepthRangeAPI::DepthRangeAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "depth_range_api", "Test verifies that \"depth range api\" works as expected")
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult DepthRangeAPI::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
bool test_result;
const glu::ContextType& context_type = m_context.getRenderContext().getType();
if (glu::isContextTypeGLCore(context_type))
{
test_result = iterateHelper<GLdouble>();
}
else
{
DE_ASSERT(glu::isContextTypeES(context_type));
test_result = iterateHelper<GLfloat>();
}
/* 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;
}
template <typename T>
bool DepthRangeAPI::iterateHelper(T*)
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
Utils::DepthFuncWrapper depthFunc(m_context);
bool test_result = true;
GLint max_viewports = 0;
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
std::vector<T> depth_range_data_a;
std::vector<T> depth_range_data_b;
depth_range_data_a.resize(max_viewports * m_n_elements);
depth_range_data_b.resize(max_viewports * m_n_elements);
/*
* - get initial values of DEPTH_RANGE for all MAX_VIEWPORTS indices;
* - change values of all indices at once with DepthRangeArrayv;
* - get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
*/
getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
for (GLint i = 0; i < max_viewports; ++i)
{
depth_range_data_a[i * m_n_elements + 0] += 0.125;
depth_range_data_a[i * m_n_elements + 1] -= 0.125;
}
depthFunc.depthRangeArray(0, max_viewports, &depth_range_data_a[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeArray");
getDepthRanges(depthFunc, max_viewports, depth_range_data_b);
compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeArray", test_result);
/*
* - for each index:
* * modify with DepthRangeIndexed,
* * get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
depth_range_data_b[i * m_n_elements + 0] = 0.25;
depth_range_data_b[i * m_n_elements + 1] = 0.75;
depthFunc.depthRangeIndexed(i, (T)0.25, (T)0.75);
GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeIndexed");
getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeIndexed", test_result);
}
/*
* - for each index:
* * modify all indices before and after current one with DepthRangeArrayv,
* * get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
const T value = (0 == i % 2) ? T(1.0) : T(0.25);
for (GLint j = 0; j < i; ++j)
{
depth_range_data_b[j * m_n_elements + 0] = value;
depth_range_data_b[j * m_n_elements + 1] = value;
}
for (GLint j = i + 1; j < max_viewports; ++j)
{
depth_range_data_b[j * m_n_elements + 0] = value;
depth_range_data_b[j * m_n_elements + 1] = value;
}
depthFunc.depthRangeArray(0, max_viewports, &depth_range_data_b[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeArray");
getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeArray", test_result);
}
/*
* - change values of all indices at once with DepthRange;
* - get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
depth_range_data_a[i * m_n_elements + 0] = 0.0f;
depth_range_data_a[i * m_n_elements + 1] = 1.0f;
}
depthFunc.depthRange((T)0.0, (T)1.0);
GLU_EXPECT_NO_ERROR(gl.getError(), "depthRange");
getDepthRanges(depthFunc, max_viewports, depth_range_data_b);
compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRange", test_result);
return test_result;
}
/** Compare two sets of depth range data (simple vector comparison)
*
* @param left Left set
* @param right Right set
* @param description Test case description
* @param out_result Set to false if sets are different, not modified otherwise
**/
template <typename T>
void DepthRangeAPI::compareDepthRanges(std::vector<T>& left, std::vector<T>& right, const GLchar* description,
bool& out_result)
{
for (size_t i = 0; i < left.size(); ++i)
{
if (left[i] != right[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
<< tcu::TestLog::EndMessage;
out_result = false;
}
}
}
/** Get all depth ranges
*
* @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
* @param data Memory buffer prepared for captured data
**/
template <typename T>
void DepthRangeAPI::getDepthRanges(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, std::vector<T>& out_data)
{
for (GLint i = 0; i < max_viewports; ++i)
{
depthFunc.getDepthi_v(GL_DEPTH_RANGE, i, &out_data[i * m_n_elements]);
GLU_EXPECT_NO_ERROR(depthFunc.getFunctions().getError(), "getDouble/Floati_v");
}
}
/** Constructor
*
* @param context Test context
**/
ScissorTestStateAPI::ScissorTestStateAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
: TestCaseBase(context, extParams, "scissor_test_state_api",
"Test verifies that \"enable/disable api\" works as expected for scissor test")
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult ScissorTestStateAPI::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test result */
bool test_result = true;
GLint max_viewports = 0;
gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
std::vector<GLboolean> scissor_test_states_a;
std::vector<GLboolean> scissor_test_states_b;
scissor_test_states_a.resize(max_viewports);
scissor_test_states_b.resize(max_viewports);
/*
* - get initial state of SCISSOR_TEST for all MAX_VIEWPORTS indices;
* - for each index:
* * toggle SCISSOR_TEST,
* * get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
* - for each index:
* * toggle SCISSOR_TEST,
* * get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
*/
getScissorTestStates(max_viewports, scissor_test_states_a);
for (GLint i = 0; i < max_viewports; ++i)
{
if (GL_FALSE == scissor_test_states_a[i])
{
gl.enablei(GL_SCISSOR_TEST, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Enablei");
scissor_test_states_a[i] = GL_TRUE;
}
else
{
gl.disablei(GL_SCISSOR_TEST, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Disablei");
scissor_test_states_a[i] = GL_FALSE;
}
getScissorTestStates(max_viewports, scissor_test_states_b);
compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "1st toggle", test_result);
}
for (GLint i = 0; i < max_viewports; ++i)
{
if (GL_FALSE == scissor_test_states_a[i])
{
gl.enablei(GL_SCISSOR_TEST, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Enablei");
scissor_test_states_a[i] = GL_TRUE;
}
else
{
gl.disablei(GL_SCISSOR_TEST, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "Disablei");
scissor_test_states_a[i] = GL_FALSE;
}
getScissorTestStates(max_viewports, scissor_test_states_b);
compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "2nd toggle", test_result);
}
/*
* - enable SCISSOR_TEST for all indices at once with Enable;
* - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_test_states_a[i] = GL_TRUE;
}
gl.enable(GL_SCISSOR_TEST);
GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
getScissorTestStates(max_viewports, scissor_test_states_b);
compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "1st enable all", test_result);
/*
* - disable SCISSOR_TEST for all indices at once with Disable;
* - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_test_states_a[i] = GL_FALSE;
}
gl.disable(GL_SCISSOR_TEST);
GLU_EXPECT_NO_ERROR(gl.getError(), "Disable");
getScissorTestStates(max_viewports, scissor_test_states_b);
compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "Disable all", test_result);
/*
* - enable SCISSOR_TEST for all indices at once with Enable;
* - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
*/
for (GLint i = 0; i < max_viewports; ++i)
{
scissor_test_states_a[i] = GL_TRUE;
}
gl.enable(GL_SCISSOR_TEST);
GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
getScissorTestStates(max_viewports, scissor_test_states_b);
compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "2nd enable all", test_result);
/* 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;
}
/** Compare two sets of depth range data (simple vector comparison)
*
* @param left Left set
* @param right Right set
* @param description Test case description
* @param out_result Set to false if sets are different, not modified otherwise
**/
void ScissorTestStateAPI::compareScissorTestStates(std::vector<GLboolean>& left, std::vector<GLboolean>& right,
const GLchar* description, bool& out_result)
{
for (size_t i = 0; i < left.size(); ++i)
{
if (left[i] != right[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
<< tcu::TestLog::EndMessage;
out_result = false;
}
}
}
/** Get all depth ranges
*
* @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
* @param data Memory buffer prepared for captured data
**/
void ScissorTestStateAPI::getScissorTestStates(GLint max_viewports, std::vector<GLboolean>& out_data)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
for (GLint i = 0; i < max_viewports; ++i)
{
out_data[i] = gl.isEnabledi(GL_SCISSOR_TEST, i);
GLU_EXPECT_NO_ERROR(gl.getError(), "isEnabledi");
}
}
/* Constants used by DrawTestBase */
const GLuint DrawTestBase::m_depth = 16;
const GLuint DrawTestBase::m_height = 128;
const GLuint DrawTestBase::m_width = 128;
const GLuint DrawTestBase::m_r32f_height = 2;
const GLuint DrawTestBase::m_r32f_width = 16;
const GLuint DrawTestBase::m_r32ix4_depth = 4;
/** Constructor
*
* @param context Test context
* @param test_name Test name
* @param test_description Test description
**/
DrawTestBase::DrawTestBase(deqp::Context& context, const glcts::ExtParameters& extParams, const GLchar* test_name,
const GLchar* test_description)
: TestCaseBase(context, extParams, test_name, test_description)
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
**/
tcu::TestNode::IterateResult DrawTestBase::iterate()
{
if (!m_is_viewport_array_supported)
{
throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glu::ContextType& context_type = m_context.getRenderContext().getType();
/* Test result */
bool test_result = true;
/* Get type of test */
const TEST_TYPE test_type = getTestType();
GLuint n_draw_calls = getDrawCallsNumber();
GLuint n_iterations = 0;
switch (test_type)
{
case VIEWPORT:
case SCISSOR:
n_iterations = 3;
break;
case DEPTHRANGE:
case PROVOKING:
n_iterations = 2;
break;
default:
TCU_FAIL("Invalid enum");
}
/* Get shader sources and specialize them */
const std::string& frag = getFragmentShader();
const std::string& geom = getGeometryShader();
const std::string& vert = getVertexShader();
const GLchar* frag_template = frag.c_str();
const GLchar* geom_template = geom.c_str();
const GLchar* vert_template = vert.c_str();
std::string fragment = specializeShader(1, &frag_template);
std::string geometry = specializeShader(1, &geom_template);
std::string vertex = specializeShader(1, &vert_template);
/* Prepare program */
Utils::program program(m_context);
try
{
program.build(0 /* compute */, fragment.c_str(), geometry.c_str(), 0 /* tess ctrl */, 0 /* tess eval */,
vertex.c_str(), 0 /* varying names */, 0 /* n_varyings */);
}
catch (Utils::shaderCompilationException& exc)
{
/* Something wrong with compilation, test case failed */
tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
message << "Shader compilation failed. Error message: " << exc.m_error_message;
Utils::program::printShaderSource(exc.m_shader_source.c_str(), message);
message << tcu::TestLog::EndMessage;
TCU_FAIL("Shader compilation failed");
}
catch (Utils::programLinkageException& exc)
{
/* Something wrong with linking, test case failed */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Program linking failed. Error message: " << exc.m_error_message
<< tcu::TestLog::EndMessage;
TCU_FAIL("Program linking failed");
}
program.use();
/* Prepare VAO */
Utils::vertexArray vao(m_context);
vao.generate();
vao.bind();
/* For each iteration from test type */
for (GLuint i = 0; i < n_iterations; ++i)
{
/* Prepare textures */
Utils::texture texture_0(m_context);
Utils::texture texture_1(m_context);
prepareTextures(texture_0, texture_1);
/* Prepare framebuffer */
Utils::framebuffer framebuffer(m_context);
framebuffer.generate();
setupFramebuffer(framebuffer, texture_0, texture_1);
framebuffer.bind();
/* Set up viewports */
setupViewports(test_type, i);
if (false == isClearTest())
{
/* For each draw call */
for (GLuint draw_call = 0; draw_call < n_draw_calls; ++draw_call)
{
prepareUniforms(program, draw_call);
bool is_clear;
GLfloat depth_value;
getClearSettings(is_clear, draw_call, depth_value);
if (true == is_clear)
{
if (glu::isContextTypeGLCore(context_type))
{
gl.clearDepth((GLdouble)depth_value);
}
else
{
gl.clearDepthf(depth_value);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "ClearDepth");
gl.clear(GL_DEPTH_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
}
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
bool result = checkResults(texture_0, texture_1, draw_call);
if (false == result)
{
test_result = false;
goto end;
}
}
}
else
{
gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
bool result = checkResults(texture_0, texture_1, 0);
if (false == result)
{
test_result = false;
goto end;
}
}
}
end:
/* 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;
}
/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
*
* @param texture_0 Verified texture
* @param ignored
* @param ignored
*
* @return True if texture_0 is filled with expected pattern
**/
bool DrawTestBase::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */, GLuint /*draw_call_index */)
{
bool check_result = true;
GLint index = 0;
std::vector<GLint> texture_data;
texture_data.resize(m_width * m_height);
texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
for (GLuint y = 0; y < 4; ++y)
{
for (GLuint x = 0; x < 4; ++x)
{
bool result = checkRegionR32I(x, y, index, &texture_data[0]);
if (false == result)
{
check_result = false;
goto end;
}
index += 1;
}
}
end:
return check_result;
}
/** Get settings of clear operation
*
* @param clear_depth_before_draw Selects if clear depth should be executed before draw.
* @param ignored
* @param ignored
**/
void DrawTestBase::getClearSettings(bool& clear_depth_before_draw, GLuint /* iteration_index */,
GLfloat& /* depth_value */)
{
clear_depth_before_draw = false;
}
/** Get number of draw call to be executed during test
*
* @return 1
**/
GLuint DrawTestBase::getDrawCallsNumber()
{
return 1;
}
/** Get test type
*
* @return VIEWPORT
**/
DrawTestBase::TEST_TYPE DrawTestBase::getTestType()
{
return VIEWPORT;
}
/** Selects if test should do draw or clear operation
*
* @return false - draw operation
**/
bool DrawTestBase::isClearTest()
{
return false;
}
/** Prepare textures used as framebuffer's attachments for current draw call
*
* @param texture_0 R32I texture
* @param ignored
**/
void DrawTestBase::prepareTextures(Utils::texture& texture_0, Utils::texture& /* texture_1 */)
{
prepareTextureR32I(texture_0);
}
/** Prepare uniforms for given draw call
*
* @param ignored
* @param ignored
**/
void DrawTestBase::prepareUniforms(Utils::program& /* program */, GLuint /* draw_call_index */)
{
/* empty */
}
/** Attach textures to framebuffer
*
* @param framebuffer Framebuffer instance
* @param texture_0 Texture attached as color 0
* @param ignored
**/
void DrawTestBase::setupFramebuffer(Utils::framebuffer& framebuffer, Utils::texture& texture_0,
Utils::texture& /* texture_1 */)
{
framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, texture_0.m_id, m_width, m_height);
}
/** Check if region specified with <x and <y> is filled with expected value.
* Note: there is assumption that there are 4x4 regions
*
* @param x X coordinate of region
* @param y Y coordinate of region
* @param expected_value Expected value
* @param data Texture data (not region, but whole texture)
*
* @return True if region is filled with <expected_value>, false otherwise
**/
bool DrawTestBase::checkRegionR32I(GLuint x, GLuint y, GLint expected_value, GLint* data)
{
static GLuint width = m_width / 4;
static GLuint height = m_height / 4;
return checkRegionR32I(x, y, width, height, expected_value, data);
}
/** Check if region specified with <x and <y> is filled with expected value.
* Note: there is assumption that there are 4x4 regions
*
* @param x X coordinate of region
* @param y Y coordinate of region
* @param width Width of region
* @param height Height of region
* @param expected_value Expected value
* @param data Texture data (not region, but whole texture)
*
* @return True if region is filled with <expected_value>, false otherwise
**/
bool DrawTestBase::checkRegionR32I(GLuint x, GLuint y, GLuint width, GLuint height, GLint expected_value, GLint* data)
{
bool result = true;
const GLuint offset = (y * height * m_width) + (x * width);
for (GLuint line = 0; line < height; ++line)
{
const GLuint line_offset = offset + line * m_width;
for (GLuint texel = 0; texel < width; ++texel)
{
const GLuint texel_offset = line_offset + texel;
const GLint value = data[texel_offset];
if (expected_value != value)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid result. Region (" << x << "x"
<< y << "). Expected: " << expected_value << " got " << value
<< tcu::TestLog::EndMessage;
result = false;
goto end;
}
}
}
end:
return result;
}
/** Return boiler-plate vertex shader
*
* @return Source code of vertex shader
**/
std::string DrawTestBase::getVertexShader()
{
static const GLchar* source = "${VERSION}\n"
"\n"
"void main()\n"
"{\n"
" /* empty */;\n"
"}\n"
"\n";
std::string result = source;
return result;
}
/** Set up viewports
*
* @param type Type of test
* @param iteration_index Index of iteration for given test type
**/
void DrawTestBase::setupViewports(TEST_TYPE type, GLuint iteration_index)
{
switch (type)
{
case VIEWPORT:
{
VIEWPORT_METHOD method;
switch (iteration_index)
{
case 0:
case 1:
case 2:
method = (VIEWPORT_METHOD)iteration_index;
break;
default:
TCU_FAIL("Invalid value");
}
setup4x4Viewport(method);
}
break;
case SCISSOR:
{
SCISSOR_METHOD method;
switch (iteration_index)
{
case 0:
case 1:
case 2:
method = (SCISSOR_METHOD)iteration_index;
break;
default:
TCU_FAIL("Invalid value");
}
setup4x4Scissor(method, false /* set_zeros */);
}
break;
case DEPTHRANGE:
{
DEPTH_RANGE_METHOD method;
switch (iteration_index)
{
case 0:
case 1:
method = (DEPTH_RANGE_METHOD)iteration_index;
break;
default:
TCU_FAIL("Invalid value");
}
setup16x2Depths(method);
}
break;
case PROVOKING:
{
PROVOKING_VERTEX provoking;
switch (iteration_index)
{
case 0:
case 1:
provoking = (PROVOKING_VERTEX)iteration_index;
break;
default:
TCU_FAIL("Invalid value");
}
setup2x2Viewport(provoking);
}
break;
default:
TCU_FAIL("Invalid enum");
}
}
/** Prepare R32I texture filled with value -1
*
* @param texture Texture instance
**/
void DrawTestBase::prepareTextureR32I(Utils::texture& texture)
{
static const GLuint size = m_width * m_height;
GLint data[size];
for (GLuint i = 0; i < size; ++i)
{
data[i] = -1;
}
texture.create(m_width, m_height, GL_R32I);
texture.update(m_width, m_height, 0 /* depth */, GL_RED_INTEGER, GL_INT, data);
}
/** Prepare R32I array texture filled with value -1, 4 layers
*
* @param texture Texture instance
**/
void DrawTestBase::prepareTextureR32Ix4(Utils::texture& texture)
{
static const GLuint size = m_width * m_height * m_r32ix4_depth;
std::vector<GLint> data;
data.resize(size);
for (GLuint i = 0; i < size; ++i)
{
data[i] = -1;
}
texture.create(m_width, m_height, m_r32ix4_depth, GL_R32I);
texture.update(m_width, m_height, m_r32ix4_depth, GL_RED_INTEGER, GL_INT, &data[0]);
}
/** Prepare R32I array texture filled with value -1
*
* @param texture Texture instance
**/
void DrawTestBase::prepareTextureArrayR32I(Utils::texture& texture)
{
static const GLuint size = m_width * m_height * m_depth;
std::vector<GLint> data;
data.resize(size);
for (GLuint i = 0; i < size; ++i)
{
data[i] = -1;
}
texture.create(m_width, m_height, m_depth, GL_R32I);
texture.update(m_width, m_height, m_depth, GL_RED_INTEGER, GL_INT, &data[0]);
}
/** Prepare R32F texture filled with value -1
*
* @param texture Texture instance
**/
void DrawTestBase::prepareTextureR32F(Utils::texture& texture)
{
static const GLuint size = m_r32f_width * m_r32f_height;
GLfloat data[size];
for (GLuint i = 0; i < size; ++i)
{
data[i] = -1.0f;
}
texture.create(m_r32f_width, m_r32f_height, GL_R32F);
texture.update(m_r32f_width, m_r32f_height, 0 /* depth */, GL_RED, GL_FLOAT, data);
}