| /*------------------------------------------------------------------------- |
| * 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 |