blob: 4a75d92559e48cc8ab94a82b7755a1d763bccc4b [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 esextcTextureCubeMapArrayStencilAttachments.cpp
* \brief Texture Cube Map Array Stencil Attachments (Test 3)
*/ /*-------------------------------------------------------------------*/
#include "esextcTextureCubeMapArrayStencilAttachments.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <string.h>
namespace glcts
{
/** Number of byte for one vec4 position */
const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_components = 4;
/** Number of configuration different cube map array textures*/
const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_cube_map_array_configurations = 4;
/** Number of vertices per triangle use in gemoetry shader*/
const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_vertices_gs = 3;
/** Constructor **/
CubeMapArrayDataStorage::CubeMapArrayDataStorage() : m_data_array(DE_NULL), m_depth(0), m_height(0), m_width(0)
{
}
/** Destructor **/
CubeMapArrayDataStorage::~CubeMapArrayDataStorage()
{
deinit();
}
/** Initializes data array
*
* @param width width of the texture;
* @param height height of the texture;
* @param depth number of layers in the texture (for cube map array must be multiple of 6);
* @param initial_value value which the allocated storage should be cleared with;
**/
void CubeMapArrayDataStorage::init(const glw::GLuint width, const glw::GLuint height, const glw::GLuint depth,
glw::GLubyte initial_value)
{
deinit();
m_width = width;
m_height = height;
m_depth = depth;
m_data_array = new glw::GLubyte[getArraySize()];
memset(m_data_array, initial_value, getArraySize() * sizeof(glw::GLubyte));
}
/** Deinitializes data array **/
void CubeMapArrayDataStorage::deinit(void)
{
if (m_data_array != DE_NULL)
{
delete[] m_data_array;
m_data_array = DE_NULL;
}
m_width = 0;
m_height = 0;
m_depth = 0;
}
/** Returns pointer to array.
*
* @return As per description.
**/
glw::GLubyte* CubeMapArrayDataStorage::getDataArray() const
{
return m_data_array;
}
/** Returns size of the array in bytes **/
glw::GLuint CubeMapArrayDataStorage::getArraySize() const
{
return m_width * m_height * m_depth * TextureCubeMapArrayStencilAttachments::m_n_components;
}
/* Fragment shader code */
const char* TextureCubeMapArrayStencilAttachments::m_fragment_shader_code = "${VERSION}\n"
"\n"
"${TEXTURE_CUBE_MAP_ARRAY_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(location = 0) out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(0, 1, 1, 0);\n"
"}\n";
/* Vertex shader code */
const char* TextureCubeMapArrayStencilAttachments::m_vertex_shader_code = "${VERSION}\n"
"\n"
"${TEXTURE_CUBE_MAP_ARRAY_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"in vec4 vertex_position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vertex_position;\n"
"}\n";
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's description
* @param immutable_storage if set to true, immutable textures will be used;
* @param fbo_layered if set to true, a layered draw framebuffer will be used;
**/
TextureCubeMapArrayStencilAttachments::TextureCubeMapArrayStencilAttachments(Context& context,
const ExtParameters& extParams,
const char* name, const char* description,
glw::GLboolean immutable_storage,
glw::GLboolean fbo_layered)
: TestCaseBase(context, extParams, name, description)
, m_fbo_layered(fbo_layered)
, m_immutable_storage(immutable_storage)
, m_fbo_draw_id(0)
, m_fbo_read_id(0)
, m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_program_id(0)
, m_texture_cube_array_stencil_id(0)
, m_texture_cube_array_color_id(0)
, m_vao_id(0)
, m_vbo_id(0)
, m_vertex_shader_id(0)
, m_cube_map_array_data(DE_NULL)
, m_result_data(DE_NULL)
{
/* Nothing to be done here */
}
/** Executes the test.
*
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
*
* Note the function throws exception should an error occur!
*
* @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
**/
tcu::TestNode::IterateResult TextureCubeMapArrayStencilAttachments::iterate(void)
{
initTest();
/* Retrieve ES entry-points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Set up stencil function */
gl.stencilFunc(GL_LESS, 0 /* ref */, 0xFF /* mask */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not setup stencil function");
/* Set up stencil operation */
gl.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not setup stencil operation");
/* Set up clear color */
gl.clearColor(1 /* red */, 0 /* green */, 0 /* blue */, 1 /* alpha */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set stencil color value!");
bool has_test_failed = false;
/* Iterate through all defined configurations */
for (glw::GLuint test_index = 0; test_index < m_n_cube_map_array_configurations; test_index++)
{
/* Build and activate a test-specific program object */
buildAndUseProgram(test_index);
/* Create textures, framebuffer... before for every test iteration */
initTestIteration(test_index);
/* Clear the color buffer with (1, 0, 0, 1) color */
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear color buffer");
/* Draw a full-screen quad */
gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
/* Read the rendered data */
glw::GLuint array_size =
m_cube_map_array_data[test_index].getArraySize() / m_cube_map_array_data[test_index].getDepth();
m_result_data = new glw::GLubyte[array_size];
memset(m_result_data, 0, sizeof(glw::GLubyte) * array_size);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind read framebuffer");
if (m_fbo_layered)
{
for (glw::GLuint n_layer = 0; n_layer < m_cube_map_array_data[test_index].getDepth(); ++n_layer)
{
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id,
0, /* level */
n_layer);
GLU_EXPECT_NO_ERROR(gl.getError(),
"Could not attach texture layer to color attachment of read framebuffer");
/* Is the data correct? */
has_test_failed = readPixelsAndCompareWithExpectedResult(test_index);
if (has_test_failed)
{
break;
}
} /* for (all layers) */
} /* if (m_fbo_layered) */
else
{
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id,
0 /* level */, 0);
GLU_EXPECT_NO_ERROR(gl.getError(),
"Could not attach texture layer to color attachment of read framebuffer");
/* Is the data correct? */
has_test_failed = readPixelsAndCompareWithExpectedResult(test_index);
}
/* Clean up */
cleanAfterTest();
if (has_test_failed)
{
break;
}
} /* for (all configurations) */
if (has_test_failed)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
else
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Deinitializes GLES objects created during the test.
*
*/
void TextureCubeMapArrayStencilAttachments::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Disable the stencil test */
gl.disable(GL_STENCIL_TEST);
/* If any of the iterations have broken, we should clean up here. */
cleanAfterTest();
gl.bindVertexArray(0);
/* Release test-wide objects */
if (m_vbo_id != 0)
{
gl.deleteBuffers(1, &m_vbo_id);
m_vbo_id = 0;
}
if (m_fbo_draw_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_draw_id);
m_fbo_draw_id = 0;
}
if (m_fbo_read_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_read_id);
m_fbo_read_id = 0;
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
m_vao_id = 0;
}
if (m_cube_map_array_data != DE_NULL)
{
delete[] m_cube_map_array_data;
m_cube_map_array_data = DE_NULL;
}
/* Deinitialize base class */
TestCaseBase::deinit();
}
/** Build and use a program object **/
void TextureCubeMapArrayStencilAttachments::buildAndUseProgram(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create a program object */
m_program_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a program object");
/* Create shader objects that will make up the program object */
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a fragment shader object");
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a vertex shader object");
if (m_fbo_layered)
{
std::string geometry_shader_code;
const char* geometry_shader_code_ptr = DE_NULL;
std::stringstream max_vertices_sstream;
std::stringstream n_iterations_sstream;
max_vertices_sstream << m_cube_map_array_data[test_index].getDepth() * m_n_vertices_gs;
n_iterations_sstream << m_cube_map_array_data[test_index].getDepth();
geometry_shader_code = getGeometryShaderCode(max_vertices_sstream.str(), n_iterations_sstream.str());
geometry_shader_code_ptr = geometry_shader_code.c_str();
m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a geometry shader object");
/* Build a program object */
if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_geometry_shader_id, 1,
&geometry_shader_code_ptr, m_vertex_shader_id, 1, &m_vertex_shader_code))
{
TCU_FAIL("Program could not have been created sucessfully from valid vertex/geometry/fragment shaders");
}
} /* if (m_fbo_layered) */
else
{
/* Build a program object */
if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_vertex_shader_id, 1,
&m_vertex_shader_code))
{
TCU_FAIL("Program could not have been created sucessfully from valid vertex/fragment shaders");
}
}
/* Use program */
glw::GLint posAttrib = -1;
gl.useProgram(m_program_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
posAttrib = gl.getAttribLocation(m_program_id, "vertex_position");
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!");
if (posAttrib == -1)
{
TCU_FAIL("vertex_position attribute is considered inactive");
}
gl.vertexAttribPointer(posAttrib, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure vertex_position vertex attribute array");
gl.enableVertexAttribArray(posAttrib);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!");
}
/** Check Framebuffer Status. Throws a TestError exception, should the framebuffer status
* be found incomplete.
*
* @param framebuffer_status FBO status, as returned by glCheckFramebufferStatus(), to check.
*
*/
void TextureCubeMapArrayStencilAttachments::checkFramebufferStatus(glw::GLenum framebuffer_status)
{
if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status)
{
switch (framebuffer_status)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
}
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
}
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
}
case GL_FRAMEBUFFER_UNSUPPORTED:
{
TCU_FAIL("Framebuffer incomplete, status: Error: GL_FRAMEBUFFER_UNSUPPORTED");
}
default:
{
TCU_FAIL("Framebuffer incomplete, status not recognized");
}
} /* switch (framebuffer_status) */
} /* if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) */
}
/** Clean after test **/
void TextureCubeMapArrayStencilAttachments::cleanAfterTest(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
gl.useProgram(0);
if (m_program_id != 0)
{
gl.deleteProgram(m_program_id);
m_program_id = 0;
}
if (m_fragment_shader_id != 0)
{
gl.deleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (m_geometry_shader_id != 0)
{
gl.deleteShader(m_geometry_shader_id);
m_geometry_shader_id = 0;
}
if (m_vertex_shader_id != 0)
{
gl.deleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
if (m_texture_cube_array_color_id != 0)
{
gl.deleteTextures(1, &m_texture_cube_array_color_id);
m_texture_cube_array_color_id = 0;
}
if (m_texture_cube_array_stencil_id != 0)
{
gl.deleteTextures(1, &m_texture_cube_array_stencil_id);
m_texture_cube_array_stencil_id = 0;
}
if (m_result_data != DE_NULL)
{
delete[] m_result_data;
m_result_data = DE_NULL;
}
}
/** Create an immutable texture storage for a color texture.
*
* @param test_index number of the test configuration to use texture properties from.
**/
void TextureCubeMapArrayStencilAttachments::createImmutableCubeArrayColor(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, /* target */
1, /* levels */
GL_RGBA8, /* internalformat */
m_cube_map_array_data[test_index].getWidth(), /* width */
m_cube_map_array_data[test_index].getHeight(), /* height */
m_cube_map_array_data[test_index].getDepth()); /* depth */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create an immutable color texture storage!");
}
/** Create an immutable texture storage for a stencil texture.
*
* @param test_index number of the test configuration to use texture properties from.
**/
void TextureCubeMapArrayStencilAttachments::createImmutableCubeArrayStencil(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
fillStencilData(test_index);
gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, /* target */
1, /* levels */
GL_DEPTH24_STENCIL8, /* internalformat */
m_cube_map_array_data[test_index].getWidth(), /* width */
m_cube_map_array_data[test_index].getHeight(), /* height */
m_cube_map_array_data[test_index].getDepth()); /* depth */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create an immutable stencil texture storage!");
gl.texSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, /* target */
0, /* level */
0, /* xoffset */
0, /* yoffset */
0, /* zoffset */
m_cube_map_array_data[test_index].getWidth(), /* width */
m_cube_map_array_data[test_index].getHeight(), /* height */
m_cube_map_array_data[test_index].getDepth(), /* depth */
GL_DEPTH_STENCIL, /* format */
GL_UNSIGNED_INT_24_8, /* type */
m_cube_map_array_data[test_index].getDataArray()); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not fill allocated texture storage with texture data!");
}
/** Create a mutable texture storage for a color texture.
*
* @param test_index number of the test configuration to use texture properties from.
*
**/
void TextureCubeMapArrayStencilAttachments::createMutableCubeArrayColor(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, /* target */
0, /* level */
GL_RGBA8, /* internal format */
m_cube_map_array_data[test_index].getWidth(), /* width */
m_cube_map_array_data[test_index].getHeight(), /* height */
m_cube_map_array_data[test_index].getDepth(), /* depth */
0, /* border */
GL_RGBA, /* format */
GL_UNSIGNED_BYTE, /* type */
m_cube_map_array_data[test_index].getDataArray()); /* pixel data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a mutable color texture storage!");
}
/** Create a mutable texture storage for a stencil texture.
*
* @param test_index number of the test configuration to use texture properties from.
**/
void TextureCubeMapArrayStencilAttachments::createMutableCubeArrayStencil(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
fillStencilData(test_index);
gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, /* target */
0, /* level */
GL_DEPTH24_STENCIL8, /* internal format */
m_cube_map_array_data[test_index].getWidth(), /* width */
m_cube_map_array_data[test_index].getHeight(), /* height */
m_cube_map_array_data[test_index].getDepth(), /* depth */
0, /* border */
GL_DEPTH_STENCIL, /* format */
GL_UNSIGNED_INT_24_8, /* type */
m_cube_map_array_data[test_index].getDataArray()); /* pixel data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a mutable stencil texture storage!");
}
/** Fill the texture used as stencil attachment with reference values
*
* @param test_index index of the test configuration this call is being made for.
*
**/
void TextureCubeMapArrayStencilAttachments::fillStencilData(glw::GLuint test_index)
{
glw::GLubyte* const data = m_cube_map_array_data[test_index].getDataArray();
memset(data, 0, m_cube_map_array_data[test_index].getArraySize() * sizeof(glw::GLubyte));
for (glw::GLuint depth_index = 0; depth_index < m_cube_map_array_data[test_index].getDepth(); depth_index++)
{
for (glw::GLuint x = 0; x < m_cube_map_array_data[test_index].getWidth(); x++)
{
for (glw::GLuint y = m_cube_map_array_data[test_index].getHeight() / 2;
y < m_cube_map_array_data[test_index].getHeight(); y++)
{
glw::GLuint depth_position_in_array = m_cube_map_array_data[test_index].getWidth() *
m_cube_map_array_data[test_index].getHeight() * m_n_components *
depth_index;
glw::GLuint y_position_in_array = m_cube_map_array_data[test_index].getHeight() * m_n_components * y;
glw::GLuint x_position_in_array = m_n_components * x;
glw::GLuint index_array = depth_position_in_array + y_position_in_array + x_position_in_array;
memset((data + index_array), 1, m_n_components);
} /* for (all rows) */
} /* for (all columns) */
} /* for (all layers) */
}
/** Returns a geometry shader code, adapted to user-specific values.
*
* @param max_vertices String storing maximum amount of vertices that geometry shader can output;
* @param n_layers String storing number of layer-faces in cube map array texture;
*/
std::string TextureCubeMapArrayStencilAttachments::getGeometryShaderCode(const std::string& max_vertices,
const std::string& n_layers)
{
/* Geometry shader template code */
std::string m_geometry_shader_template = "${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"layout(triangles) in;\n"
"layout(triangle_strip, max_vertices = <-MAX-VERTICES->) out;\n"
"\n"
"void main(void)\n"
"{\n"
" int layer;\n"
"\n"
" for (layer = 0; layer < <-N_LAYERS->; layer++)\n"
" {\n"
" gl_Layer = layer;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" gl_Layer = layer;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n"
"\n"
" gl_Layer = layer;\n"
" gl_Position = gl_in[2].gl_Position;\n"
" EmitVertex();\n"
"\n"
" EndPrimitive();\n"
" }\n"
"}\n";
/* Replace a "maximum number of emitted vertices" token with user-provided value */
std::string template_name = "<-MAX-VERTICES->";
std::size_t template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), max_vertices);
template_position = m_geometry_shader_template.find(template_name);
}
/* Do the same for the number of layers we want the geometry shader to modify. */
template_name = "<-N_LAYERS->";
template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), n_layers);
template_position = m_geometry_shader_template.find(template_name);
}
if (!m_is_geometry_shader_extension_supported && m_fbo_layered)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED);
}
return m_geometry_shader_template;
}
/** Initializes GLES objects created during the test. **/
void TextureCubeMapArrayStencilAttachments::initTest(void)
{
/* Check if EXT_texture_cube_map_array extension is supported */
if (!m_is_texture_cube_map_array_supported)
{
throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
if (!m_is_geometry_shader_extension_supported && m_fbo_layered)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED);
}
/* Retrieve ES entry-points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create 4 different configurations of cube map array texture */
m_cube_map_array_data = new CubeMapArrayDataStorage[m_n_cube_map_array_configurations];
m_cube_map_array_data[0].init(64, 64, 18);
m_cube_map_array_data[1].init(117, 117, 6);
m_cube_map_array_data[2].init(256, 256, 6);
m_cube_map_array_data[3].init(173, 173, 12);
/* full screen square */
glw::GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f };
/* Generate and bind VAO */
gl.genVertexArrays(1, &m_vao_id);
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
gl.genBuffers(1, &m_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate buffer object!");
gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set data for buffer object!");
/* Create and configure framebuffer object */
gl.genFramebuffers(1, &m_fbo_read_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate framebuffer object!");
gl.genFramebuffers(1, &m_fbo_draw_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate framebuffer object!");
gl.enable(GL_STENCIL_TEST);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable stencil test!");
}
/** Create and set OpenGL object need for one test iteration
*
* @param test_index number of the test configuration to use texture properties from.
**/
void TextureCubeMapArrayStencilAttachments::initTestIteration(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Set up texture storage for color data */
gl.genTextures(1, &m_texture_cube_array_color_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture object!");
gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_texture_cube_array_color_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to GL_TEXTURE_CUBE_MAP_ARRAY_EXT target");
if (m_immutable_storage)
{
createImmutableCubeArrayColor(test_index);
}
else
{
createMutableCubeArrayColor(test_index);
}
/* Set up texture storage for stencil data */
gl.genTextures(1, &m_texture_cube_array_stencil_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture object!");
gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_texture_cube_array_stencil_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind texture object to GL_TEXTURE_CUBE_MAP_ARRAY_EXT target");
if (m_immutable_storage)
{
createImmutableCubeArrayStencil(test_index);
}
else
{
createMutableCubeArrayStencil(test_index);
}
/* Set up the draw framebuffer */
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind draw framebuffer!");
gl.viewport(0, 0, m_cube_map_array_data[test_index].getWidth(), m_cube_map_array_data[test_index].getHeight());
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set viewport");
if (m_fbo_layered)
{
setupLayeredFramebuffer();
}
else
{
setupNonLayeredFramebuffer();
}
/* Is the draw FBO complete, now that we're done with configuring it? */
checkFramebufferStatus(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER));
}
/** Read pixels from color attachment of read framebuffer and compare them with expected result.
*
* @param test_index index of cube map array configuration
*
* @return true if failed, false otherwise.
*/
bool TextureCubeMapArrayStencilAttachments::readPixelsAndCompareWithExpectedResult(glw::GLuint test_index)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool has_test_failed = false;
gl.readPixels(0 /* x */, 0 /* y */, m_cube_map_array_data[test_index].getWidth(),
m_cube_map_array_data[test_index].getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_result_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read pixel data from color buffer");
glw::GLubyte expectedData[] = { 0, 0, 0, 0 };
/* Loop over all pixels and compare the rendered data with reference values */
for (glw::GLuint y = 0; y < m_cube_map_array_data[test_index].getHeight(); ++y)
{
/* Top half should be filled with different data than the bottom half */
if (y >= m_cube_map_array_data[test_index].getHeight() / 2)
{
expectedData[0] = 0;
expectedData[1] = 255;
expectedData[2] = 255;
expectedData[3] = 0;
}
else
{
expectedData[0] = 255;
expectedData[1] = 0;
expectedData[2] = 0;
expectedData[3] = 255;
}
const glw::GLubyte* data_row =
m_result_data + y * m_cube_map_array_data[test_index].getHeight() * m_n_cube_map_array_configurations;
for (glw::GLuint x = 0; x < m_cube_map_array_data[test_index].getWidth(); ++x)
{
const glw::GLubyte* data = data_row + x * m_n_components;
if (data[0] != expectedData[0] || data[1] != expectedData[1] || data[2] != expectedData[2] ||
data[3] != expectedData[3])
{
m_testCtx.getLog() << tcu::TestLog::Message << "Expected Data ( " << (unsigned int)expectedData[0]
<< "," << (unsigned int)expectedData[1] << "," << (unsigned int)expectedData[2]
<< "," << (unsigned int)expectedData[3] << ") "
<< "Result Data ( " << (unsigned int)data[0] << "," << (unsigned int)data[1] << ","
<< (unsigned int)data[2] << "," << (unsigned int)data[3] << ")"
<< tcu::TestLog::EndMessage;
has_test_failed = true;
}
} /* for (all pixels in a row) */
} /* for (all rows) */
return has_test_failed;
}
/** Attach color and stencil attachments to a layer framebuffer **/
void TextureCubeMapArrayStencilAttachments::setupLayeredFramebuffer()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to GL_COLOR_ATTACHMENT0!");
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_texture_cube_array_stencil_id,
0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to GL_DEPTH_STENCIL_ATTACHMENT! ");
}
/** Attach color and stencil attachments to a non-layered framebuffer. **/
void TextureCubeMapArrayStencilAttachments::setupNonLayeredFramebuffer()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id, 0 /* level */,
0 /* layer */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture layer 0 to GL_COLOR_ATTACHMENT0!");
gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_texture_cube_array_stencil_id,
0 /* level */, 0 /* layer */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture layer 0 to GL_DEPTH_STENCIL_ATTACHMENT! ");
}
} // namespace glcts