| /*------------------------------------------------------------------------- |
| * 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 |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "esextcGeometryShaderLayeredFramebuffer.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| #include <cstring> |
| |
| namespace glcts |
| { |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's desricption |
| **/ |
| GeometryShaderLayeredFramebufferBlending::GeometryShaderLayeredFramebufferBlending(Context& context, |
| const ExtParameters& extParams, |
| const char* name, |
| const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_fbo_id(0) |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_po_id(0) |
| , m_read_fbo_id(0) |
| , m_to_id(0) |
| , m_vao_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void GeometryShaderLayeredFramebufferBlending::deinit(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean up */ |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| } |
| |
| if (m_gs_id != 0) |
| { |
| gl.deleteShader(m_gs_id); |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| } |
| |
| if (m_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_read_fbo_id); |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| } |
| |
| /* Release base class */ |
| TestCaseBase::deinit(); |
| } |
| |
| /** Executes the test. |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. |
| * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. |
| * Note the function throws exception should an error occur! |
| **/ |
| tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferBlending::iterate(void) |
| { |
| /* Test-wide constants */ |
| #define N_TEXTURE_COMPONENTS (4) |
| #define TEXTURE_DEPTH (4) |
| #define TEXTURE_HEIGHT (4) |
| #define TEXTURE_WIDTH (4) |
| |
| /* Fragment shader code */ |
| const char* fs_code = "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = vec4(0.2);\n" |
| "}\n"; |
| |
| /* Geometry shader code */ |
| const char* gs_code = "${VERSION}\n" |
| "${GEOMETRY_SHADER_REQUIRE}\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices=64) out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " for (int n = 0; n < 4; ++n)\n" |
| " {\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " EndPrimitive();\n" |
| " }\n" |
| "}\n"; |
| |
| /* General variables */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| unsigned int n = 0; |
| unsigned int n_component = 0; |
| unsigned int n_layer = 0; |
| unsigned int n_slice = 0; |
| unsigned int x = 0; |
| unsigned int y = 0; |
| |
| unsigned char buffer[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char buffer_slice1[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char buffer_slice2[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char buffer_slice3[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char buffer_slice4[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char ref_buffer_slice1[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char ref_buffer_slice2[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char ref_buffer_slice3[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char ref_buffer_slice4[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| |
| if (!m_is_geometry_shader_extension_supported) |
| { |
| throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| /* Set up shader objects */ |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate shader objects"); |
| |
| /* Set up program objects */ |
| m_po_id = gl.createProgram(); |
| |
| if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id, 1 /* part */, |
| &m_boilerplate_vs_code)) |
| { |
| TCU_FAIL("Could not build program object"); |
| } |
| |
| /* Prepare texture data we will use for each slice */ |
| for (n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++n) |
| { |
| unsigned char* slice_pixels_ptr[] = { buffer_slice1 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice2 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice3 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice4 + n * N_TEXTURE_COMPONENTS }; |
| |
| for (n_slice = 0; n_slice < sizeof(slice_pixels_ptr) / sizeof(slice_pixels_ptr[0]); ++n_slice) |
| { |
| slice_pixels_ptr[n_slice][0] = 0; |
| slice_pixels_ptr[n_slice][1] = (unsigned char)(n_slice * 255 / 4); |
| slice_pixels_ptr[n_slice][2] = (unsigned char)(n_slice * 255 / 8); |
| slice_pixels_ptr[n_slice][3] = (unsigned char)(n_slice * 255 / 12); |
| } /* for (all slices) */ |
| } /* for (all pixels) */ |
| |
| /* Calculate reference texture data we will later use when verifying the rendered data */ |
| for (n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++n) |
| { |
| unsigned char* ref_slice_pixels_ptr[] = { ref_buffer_slice1 + n * N_TEXTURE_COMPONENTS, |
| ref_buffer_slice2 + n * N_TEXTURE_COMPONENTS, |
| ref_buffer_slice3 + n * N_TEXTURE_COMPONENTS, |
| ref_buffer_slice4 + n * N_TEXTURE_COMPONENTS }; |
| |
| unsigned char* slice_pixels_ptr[] = { buffer_slice1 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice2 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice3 + n * N_TEXTURE_COMPONENTS, |
| buffer_slice4 + n * N_TEXTURE_COMPONENTS }; |
| |
| for (n_slice = 0; n_slice < sizeof(slice_pixels_ptr) / sizeof(slice_pixels_ptr[0]); ++n_slice) |
| { |
| unsigned char* ref_slice_ptr = ref_slice_pixels_ptr[n_slice]; |
| unsigned char* slice_ptr = slice_pixels_ptr[n_slice]; |
| float slice_rgba[] = { |
| float(slice_ptr[0]) / 255.0f, /* convert to FP representation */ |
| float(slice_ptr[1]) / 255.0f, /* convert to FP representation */ |
| float(slice_ptr[2]) / 255.0f, /* convert to FP representation */ |
| float(slice_ptr[3]) / 255.0f /* convert to FP representation */ |
| }; |
| |
| for (n_component = 0; n_component < N_TEXTURE_COMPONENTS; ++n_component) |
| { |
| float temp_component = slice_rgba[n_component] /* dst_color */ * slice_rgba[n_component] /* dst_color */ |
| + 0.8f /* 1-src_color */ * 0.2f /* src_color */; |
| |
| /* Clamp if necessary */ |
| if (temp_component < 0) |
| { |
| temp_component = 0.0f; |
| } |
| else if (temp_component > 1) |
| { |
| temp_component = 1.0f; |
| } |
| |
| /* Convert back to GL_RGBA8 */ |
| ref_slice_ptr[n_component] = (unsigned char)(temp_component * 255.0f); |
| } /* for (all components) */ |
| } /* for (all slices) */ |
| } /* for (all pixels) */ |
| |
| /* Set up texture object used for the test */ |
| gl.genTextures(1, &m_to_id); |
| gl.bindTexture(GL_TEXTURE_3D, m_to_id); |
| gl.texStorage3D(GL_TEXTURE_3D, 1 /* levels */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice1); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice2); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice3); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice4); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object"); |
| |
| /* Set up framebuffer object used for the test */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id); |
| |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer"); |
| |
| /* Generate and bind a vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| gl.bindVertexArray(m_vao_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up vertex array object"); |
| |
| /* Set up blending */ |
| gl.blendFunc(GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR); |
| gl.enable(GL_BLEND); |
| |
| /* Render */ |
| gl.useProgram(m_po_id); |
| gl.viewport(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT); |
| |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed"); |
| |
| /* Verify rendered data in the layers */ |
| gl.genFramebuffers(1, &m_read_fbo_id); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id); |
| |
| for (n_layer = 0; n_layer < TEXTURE_DEPTH; ++n_layer) |
| { |
| bool has_layer_failed = false; |
| |
| const unsigned char* ref_buffer = |
| (n_layer == 0) ? |
| ref_buffer_slice1 : |
| (n_layer == 1) ? ref_buffer_slice2 : (n_layer == 2) ? ref_buffer_slice3 : ref_buffer_slice4; |
| |
| gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0 /* level */, n_layer); |
| gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixel data!"); |
| |
| for (y = 0; y < TEXTURE_HEIGHT; ++y) |
| { |
| const unsigned int pixel_size = N_TEXTURE_COMPONENTS; |
| const unsigned char* ref_row = ref_buffer + y * pixel_size; |
| const unsigned char* row = buffer + y * pixel_size; |
| |
| for (x = 0; x < TEXTURE_WIDTH; ++x) |
| { |
| #define EPSILON (1) |
| |
| const unsigned char* data = row + x * pixel_size; |
| const unsigned char* ref_data = ref_row + x * pixel_size; |
| |
| if (de::abs((int)data[0] - (int)ref_data[0]) > EPSILON || |
| de::abs((int)data[1] - (int)ref_data[1]) > EPSILON || |
| de::abs((int)data[2] - (int)ref_data[2]) > EPSILON || |
| de::abs((int)data[3] - (int)ref_data[3]) > EPSILON) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "(layer=" << n_layer << " x=" << x << " y=" << y |
| << ") " |
| << "Reference value is different than the rendered data (epsilon > " << EPSILON |
| << "): " |
| << "(" << (unsigned int)ref_data[0] << ", " << (unsigned int)ref_data[1] << ", " |
| << (unsigned int)ref_data[2] << ", " << (unsigned int)ref_data[3] << ") vs " |
| << "(" << (unsigned int)data[0] << ", " << (unsigned int)data[1] << ", " |
| << (unsigned int)data[2] << ", " << (unsigned int)data[3] << ")." |
| << tcu::TestLog::EndMessage; |
| |
| has_layer_failed = true; |
| } /* if (regions are different) */ |
| |
| #undef EPSILON |
| } /* for (all pixels in a row) */ |
| } /* for (all rows) */ |
| |
| if (has_layer_failed) |
| { |
| TCU_FAIL("Pixel data comparison failed"); |
| } |
| } /* for (all layers) */ |
| |
| /* Done */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| |
| #undef N_TEXTURE_COMPONENTS |
| #undef TEXTURE_DEPTH |
| #undef TEXTURE_HEIGHT |
| #undef TEXTURE_WIDTH |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| GeometryShaderLayeredFramebufferClear::GeometryShaderLayeredFramebufferClear(Context& context, |
| const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_fbo_char_id(0) |
| , m_fbo_int_id(0) |
| , m_fbo_uint_id(0) |
| , m_read_fbo_id(0) |
| , m_to_rgba32i_id(0) |
| , m_to_rgba32ui_id(0) |
| , m_to_rgba8_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Executes the test. |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. |
| * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. |
| * Note the function throws exception should an error occur! |
| **/ |
| tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferClear::iterate(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Test-wide definitions */ |
| #define N_TEXTURE_COMPONENTS (4) |
| #define TEXTURE_DEPTH (4) |
| #define TEXTURE_HEIGHT (4) |
| #define TEXTURE_WIDTH (4) |
| |
| /* Type definitions */ |
| typedef enum { |
| /* Always first */ |
| CLEAR_FIRST = 0, |
| |
| /* glClear() */ |
| CLEAR_PLAIN = CLEAR_FIRST, |
| /* glClearBufferfv() */ |
| CLEAR_BUFFERFV, |
| /* glClearBufferiv() */ |
| CLEAR_BUFFERIV, |
| /* glClearBufferuiv() */ |
| CLEAR_BUFFERUIV, |
| |
| /* Always last */ |
| CLEAR_COUNT |
| } _clear_type; |
| |
| /* General variables */ |
| const glw::GLenum fbo_draw_buffer = GL_COLOR_ATTACHMENT0; |
| |
| int n = 0; |
| int n_layer = 0; |
| int x = 0; |
| int y = 0; |
| |
| unsigned char buffer_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| int buffer_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned int buffer_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char slice_1_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| int slice_1_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned int slice_1_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char slice_2_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| int slice_2_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned int slice_2_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char slice_3_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| int slice_3_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned int slice_3_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char slice_4_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| int slice_4_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned int slice_4_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| |
| /* Only carry on if geometry shaders are supported */ |
| if (!m_is_geometry_shader_extension_supported) |
| { |
| throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| /* Set up slice data */ |
| memset(slice_1_data_char, 0, sizeof(slice_1_data_char)); |
| memset(slice_1_data_int, 0, sizeof(slice_1_data_int)); |
| memset(slice_1_data_uint, 0, sizeof(slice_1_data_uint)); |
| memset(slice_2_data_char, 0, sizeof(slice_2_data_char)); |
| memset(slice_2_data_int, 0, sizeof(slice_2_data_int)); |
| memset(slice_2_data_uint, 0, sizeof(slice_2_data_uint)); |
| memset(slice_3_data_char, 0, sizeof(slice_3_data_char)); |
| memset(slice_3_data_int, 0, sizeof(slice_3_data_int)); |
| memset(slice_3_data_uint, 0, sizeof(slice_3_data_uint)); |
| memset(slice_4_data_char, 0, sizeof(slice_4_data_char)); |
| memset(slice_4_data_int, 0, sizeof(slice_4_data_int)); |
| memset(slice_4_data_uint, 0, sizeof(slice_4_data_uint)); |
| |
| for (n = 0; n < 4 /* width */ * 4 /* height */; ++n) |
| { |
| slice_1_data_char[4 * n + 0] = 255; |
| slice_1_data_int[4 * n + 0] = 255; |
| slice_1_data_uint[4 * n + 0] = 255; |
| |
| slice_2_data_char[4 * n + 1] = 255; |
| slice_2_data_int[4 * n + 1] = 255; |
| slice_2_data_uint[4 * n + 1] = 255; |
| |
| slice_3_data_char[4 * n + 2] = 255; |
| slice_3_data_int[4 * n + 2] = 255; |
| slice_3_data_uint[4 * n + 2] = 255; |
| |
| slice_4_data_char[4 * n + 0] = 255; |
| slice_4_data_char[4 * n + 1] = 255; |
| slice_4_data_int[4 * n + 0] = 255; |
| slice_4_data_int[4 * n + 1] = 255; |
| slice_4_data_uint[4 * n + 0] = 255; |
| slice_4_data_uint[4 * n + 1] = 255; |
| } /* for (all pixels) */ |
| |
| /* Set up texture objects */ |
| gl.genTextures(1, &m_to_rgba8_id); |
| gl.genTextures(1, &m_to_rgba32i_id); |
| gl.genTextures(1, &m_to_rgba32ui_id); |
| |
| for (n = 0; n < 3 /* textures */; ++n) |
| { |
| void* to_data_1 = |
| (n == 0) ? (void*)slice_1_data_char : (n == 1) ? (void*)slice_1_data_int : (void*)slice_1_data_uint; |
| |
| void* to_data_2 = |
| (n == 0) ? (void*)slice_2_data_char : (n == 1) ? (void*)slice_2_data_int : (void*)slice_2_data_uint; |
| |
| void* to_data_3 = |
| (n == 0) ? (void*)slice_3_data_char : (n == 1) ? (void*)slice_3_data_int : (void*)slice_3_data_uint; |
| |
| void* to_data_4 = |
| (n == 0) ? (void*)slice_4_data_char : (n == 1) ? (void*)slice_4_data_int : (void*)slice_4_data_uint; |
| |
| glw::GLenum to_format = (n == 0) ? GL_RGBA : (n == 1) ? GL_RGBA_INTEGER : GL_RGBA_INTEGER; |
| |
| glw::GLenum to_internalformat = (n == 0) ? GL_RGBA8 : (n == 1) ? GL_RGBA32I : GL_RGBA32UI; |
| |
| glw::GLuint to_id = (n == 0) ? m_to_rgba8_id : (n == 1) ? m_to_rgba32i_id : m_to_rgba32ui_id; |
| |
| glw::GLenum to_type = (n == 0) ? GL_UNSIGNED_BYTE : (n == 1) ? GL_INT : GL_UNSIGNED_INT; |
| |
| gl.bindTexture(GL_TEXTURE_3D, to_id); |
| |
| gl.texStorage3D(GL_TEXTURE_3D, 1 /* levels */, to_internalformat, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH); |
| |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_1); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_2); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_3); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_4); |
| |
| gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); |
| gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize texture object"); |
| } /* for (all texture objects) */ |
| |
| /* Set up framebuffer object */ |
| gl.genFramebuffers(1, &m_fbo_char_id); |
| gl.genFramebuffers(1, &m_fbo_int_id); |
| gl.genFramebuffers(1, &m_fbo_uint_id); |
| gl.genFramebuffers(1, &m_read_fbo_id); |
| |
| for (n = 0; n < 3 /* framebuffers */; ++n) |
| { |
| glw::GLuint fbo_id = (n == 0) ? m_fbo_char_id : (n == 1) ? m_fbo_int_id : m_fbo_uint_id; |
| |
| glw::GLuint to_id = (n == 0) ? m_to_rgba8_id : (n == 1) ? m_to_rgba32i_id : m_to_rgba32ui_id; |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id); |
| gl.drawBuffers(1, &fbo_draw_buffer); |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_id, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize framebuffer object"); |
| } /* for (all framebuffers) */ |
| |
| /* Try reading from the layered framebuffer. */ |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_char_id); |
| gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer_char); |
| |
| /* Is the returned data an exact copy of what we've uploaded for layer zero? */ |
| if (memcmp(buffer_char, slice_1_data_char, sizeof(slice_1_data_char)) != 0) |
| { |
| TCU_FAIL("Retrieved data is different from data uploaded for layer 0 of a layered framebuffer."); |
| } |
| |
| /* Iterate through all clear calls supported */ |
| |
| for (int current_test = static_cast<int>(CLEAR_FIRST); current_test < static_cast<int>(CLEAR_COUNT); current_test++) |
| { |
| void* buffer = NULL; |
| const float clear_color_float[] = { 0.25f, 0.5f, 1.0f, 32.0f / 255.0f }; |
| const int clear_color_int[] = { 64, 128, 255, 32 }; |
| glw::GLuint fbo_id = 0; |
| int pixel_size = 0; |
| void* slice_1_data = NULL; |
| void* slice_2_data = NULL; |
| void* slice_3_data = NULL; |
| void* slice_4_data = NULL; |
| glw::GLenum to_format = GL_NONE; |
| glw::GLuint to_id = 0; |
| glw::GLenum to_type = GL_NONE; |
| |
| switch (static_cast<_clear_type>(current_test)) |
| { |
| case CLEAR_BUFFERFV: |
| case CLEAR_PLAIN: |
| { |
| buffer = buffer_char; |
| fbo_id = m_fbo_char_id; |
| pixel_size = N_TEXTURE_COMPONENTS; |
| slice_1_data = slice_1_data_char; |
| slice_2_data = slice_2_data_char; |
| slice_3_data = slice_3_data_char; |
| slice_4_data = slice_4_data_char; |
| to_format = GL_RGBA; |
| to_id = m_to_rgba8_id; |
| to_type = GL_UNSIGNED_BYTE; |
| |
| break; |
| } |
| |
| case CLEAR_BUFFERIV: |
| { |
| buffer = (void*)buffer_int; |
| fbo_id = m_fbo_int_id; |
| pixel_size = N_TEXTURE_COMPONENTS * sizeof(int); |
| slice_1_data = slice_1_data_int; |
| slice_2_data = slice_2_data_int; |
| slice_3_data = slice_3_data_int; |
| slice_4_data = slice_4_data_int; |
| to_format = GL_RGBA_INTEGER; |
| to_id = m_to_rgba32i_id; |
| to_type = GL_INT; |
| |
| break; |
| } |
| |
| case CLEAR_BUFFERUIV: |
| { |
| buffer = (void*)buffer_uint; |
| fbo_id = m_fbo_uint_id; |
| pixel_size = N_TEXTURE_COMPONENTS * sizeof(unsigned int); |
| slice_1_data = slice_1_data_uint; |
| slice_2_data = slice_2_data_uint; |
| slice_3_data = slice_3_data_uint; |
| slice_4_data = slice_4_data_uint; |
| to_format = GL_RGBA_INTEGER; |
| to_id = m_to_rgba32ui_id; |
| to_type = GL_UNSIGNED_INT; |
| |
| break; |
| } |
| |
| default: |
| { |
| /* This location should never be reached */ |
| TCU_FAIL("Execution flow failure"); |
| } |
| } /* switch (current_test)*/ |
| |
| /* Restore layer data just in case */ |
| gl.bindTexture(GL_TEXTURE_3D, to_id); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_1_data); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_2_data); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_3_data); |
| gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH, |
| TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_4_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage3D() call failed."); |
| |
| /* Issue requested clear call */ |
| gl.bindFramebuffer(GL_FRAMEBUFFER, fbo_id); |
| |
| switch (current_test) |
| { |
| case CLEAR_PLAIN: |
| { |
| gl.clearColor(clear_color_float[0], clear_color_float[1], clear_color_float[2], clear_color_float[3]); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| |
| break; |
| } |
| |
| case CLEAR_BUFFERIV: |
| { |
| gl.clearBufferiv(GL_COLOR, 0 /* draw buffer index */, clear_color_int); |
| |
| break; |
| } |
| |
| case CLEAR_BUFFERUIV: |
| { |
| gl.clearBufferuiv(GL_COLOR, 0 /* draw buffer index */, (const glw::GLuint*)clear_color_int); |
| |
| break; |
| } |
| |
| case CLEAR_BUFFERFV: |
| { |
| gl.clearBufferfv(GL_COLOR, 0 /* draw buffer index */, clear_color_float); |
| |
| break; |
| } |
| |
| default: |
| { |
| /* This location should never be reached */ |
| TCU_FAIL("Execution flow failure"); |
| } |
| } /* switch (current_test) */ |
| |
| /* Make sure no error was generated */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Clear call failed."); |
| |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create read framebuffer object!"); |
| |
| /* Check the layer data after a clear call */ |
| for (n_layer = 0; n_layer < TEXTURE_DEPTH; ++n_layer) |
| { |
| gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_id, 0 /* level */, n_layer); |
| gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, to_format, to_type, buffer); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); |
| |
| /* If we requested an integer clear, the pixels we obtained should be reset to specific values. |
| * If we asked for a FP-based clear, consider an epsilon. */ |
| for (y = 0; y < TEXTURE_HEIGHT; ++y) |
| { |
| const int row_size = TEXTURE_WIDTH * pixel_size; |
| unsigned char* row = (unsigned char*)buffer + y * row_size; |
| |
| for (x = 0; x < TEXTURE_WIDTH; ++x) |
| { |
| if (current_test == CLEAR_BUFFERIV || current_test == CLEAR_BUFFERUIV) |
| { |
| unsigned int* pixel = (unsigned int*)(row + x * pixel_size); |
| if (memcmp(pixel, clear_color_int, sizeof(clear_color_int)) != 0) |
| { |
| /* Test fails at this point */ |
| m_testCtx.getLog() |
| << tcu::TestLog::Message << "(x=" << x << " y=" << y << ") Reference pixel [" |
| << clear_color_int[0] << ", " << clear_color_int[1] << ", " << clear_color_int[2] |
| << ", " << clear_color_int[3] << "] is different from the one retrieved [" |
| << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << ", " |
| << (int)pixel[3] << "]" << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failure"); |
| } /* if (memcmp(pixel, clear_color_int, sizeof(clear_color_int) ) != 0) */ |
| } /* if (current_test == CLEAR_BUFFERIV || current_test == CLEAR_BUFFERUIV) */ |
| else |
| { |
| #define EPSILON (1) |
| |
| unsigned char* pixel = (unsigned char*)(row + x * pixel_size); |
| |
| if (de::abs((int)pixel[0] - clear_color_int[0]) > EPSILON || |
| de::abs((int)pixel[1] - clear_color_int[1]) > EPSILON || |
| de::abs((int)pixel[2] - clear_color_int[2]) > EPSILON || |
| de::abs((int)pixel[3] - clear_color_int[3]) > EPSILON) |
| { |
| /* Test fails at this point */ |
| m_testCtx.getLog() |
| << tcu::TestLog::Message << "(x=" << x << " y=" << y << ") Reference pixel [" |
| << clear_color_int[0] << ", " << clear_color_int[1] << ", " << clear_color_int[2] |
| << ", " << clear_color_int[3] << "] is different from the one retrieved [" |
| << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << ", " |
| << (int)pixel[3] << "]" << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failure"); |
| } /* if (pixel component has exceeded an allowed epsilon) */ |
| |
| #undef EPSILON |
| } |
| } /* for (all pixels) */ |
| } /* for (all rows) */ |
| } /* for (all layers) */ |
| } /* for (all clear call types) */ |
| |
| /* Done */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| |
| #undef TEXTURE_DEPTH |
| #undef TEXTURE_HEIGHT |
| #undef TEXTURE_WIDTH |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void GeometryShaderLayeredFramebufferClear::deinit(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_fbo_char_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_char_id); |
| } |
| |
| if (m_fbo_int_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_int_id); |
| } |
| |
| if (m_fbo_uint_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_uint_id); |
| } |
| |
| if (m_to_rgba32i_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_rgba32i_id); |
| } |
| |
| if (m_to_rgba32ui_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_rgba32ui_id); |
| } |
| |
| if (m_to_rgba8_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_rgba8_id); |
| } |
| |
| if (m_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_read_fbo_id); |
| } |
| |
| /* Release base class */ |
| TestCaseBase::deinit(); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's desricption |
| **/ |
| GeometryShaderLayeredFramebufferDepth::GeometryShaderLayeredFramebufferDepth(Context& context, |
| const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_fbo_id(0) |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_po_id(0) |
| , m_read_fbo_id(0) |
| , m_to_a_id(0) |
| , m_to_b_id(0) |
| , m_vao_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void GeometryShaderLayeredFramebufferDepth::deinit(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean up */ |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| } |
| |
| if (m_gs_id != 0) |
| { |
| gl.deleteShader(m_gs_id); |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| } |
| |
| if (m_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_read_fbo_id); |
| } |
| |
| if (m_to_a_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_a_id); |
| } |
| |
| if (m_to_b_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_b_id); |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| } |
| |
| /* Release base class */ |
| TestCaseBase::deinit(); |
| } |
| |
| /** Executes the test. |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. |
| * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. |
| * Note the function throws exception should an error occur! |
| **/ |
| tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferDepth::iterate(void) |
| { |
| /* General variables */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| unsigned int n = 0; |
| unsigned int x = 0; |
| unsigned int y = 0; |
| |
| /* Test-wide definitions */ |
| #define N_TEXTURE_COMPONENTS (4) |
| #define TEXTURE_DEPTH (4) |
| #define TEXTURE_HEIGHT (4) |
| #define TEXTURE_WIDTH (4) |
| |
| /* Fragment shader code */ |
| const char* fs_code = "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = vec4(1.0);\n" |
| "}\n"; |
| |
| const char* gs_code = "${VERSION}\n" |
| "${GEOMETRY_SHADER_REQUIRE}\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices=64) out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " for (int n = 0; n < 4; ++n)\n" |
| " {\n" |
| " float depth = -1.0 + float(n) * 0.5;\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(1, 1, depth, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(1, -1, depth, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(-1, 1, depth, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Layer = n;\n" |
| " gl_Position = vec4(-1, -1, depth, 1);\n" |
| " EmitVertex();\n" |
| "\n" |
| " EndPrimitive();\n" |
| " }\n" |
| "}\n"; |
| |
| /* This test should only run if EXT_geometry_shader is supported */ |
| if (!m_is_geometry_shader_extension_supported) |
| { |
| throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| /* Set up texture objects we will be using for the test */ |
| gl.genTextures(1, &m_to_a_id); |
| gl.genTextures(1, &m_to_b_id); |
| |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_a_id); |
| gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH); |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_b_id); |
| gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_DEPTH_COMPONENT32F, TEXTURE_WIDTH, TEXTURE_HEIGHT, |
| TEXTURE_DEPTH); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize texture objects"); |
| |
| /* Set up framebuffer object we will use for the test */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| gl.genFramebuffers(1, &m_read_fbo_id); |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id); |
| |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */); |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_to_b_id, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize framebuffer object"); |
| |
| if (gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Draw framebuffer is incomplete: " << gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Draw framebuffer is incomplete."); |
| } |
| |
| /* Set up shader objects */ |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize shader objects"); |
| |
| /* Set up program object */ |
| m_po_id = gl.createProgram(); |
| |
| if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id, 1 /* part */, |
| &m_boilerplate_vs_code)) |
| { |
| TCU_FAIL("Could not build program object"); |
| } |
| |
| /* Set up vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| gl.bindVertexArray(m_vao_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind vertex array object"); |
| |
| /* Clear the depth attachment before we continue */ |
| gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */); |
| gl.clearDepthf(0.5f); |
| gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Depth buffer clear operation failed"); |
| |
| /* Render */ |
| gl.useProgram(m_po_id); |
| gl.viewport(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT); |
| |
| gl.enable(GL_DEPTH_TEST); |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed"); |
| |
| /* Verify the output */ |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id); |
| |
| for (n = 0; n < TEXTURE_DEPTH; ++n) |
| { |
| unsigned char buffer[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS]; |
| unsigned char ref_color[4]; |
| |
| /* Determine reference color */ |
| if (n < 2) |
| { |
| memset(ref_color, 0xFF, sizeof(ref_color)); |
| } |
| else |
| { |
| memset(ref_color, 0, sizeof(ref_color)); |
| } |
| |
| /* Read the rendered layer data */ |
| gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */, n); |
| gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed"); |
| |
| /* Compare all pixels against the reference value */ |
| for (y = 0; y < TEXTURE_HEIGHT; ++y) |
| { |
| const unsigned int pixel_size = N_TEXTURE_COMPONENTS; |
| const unsigned int row_width = TEXTURE_WIDTH * pixel_size; |
| const unsigned char* row_data = buffer + y * row_width; |
| |
| for (x = 0; x < TEXTURE_WIDTH; ++x) |
| { |
| const unsigned char* result = row_data + x * pixel_size; |
| |
| if (memcmp(result, ref_color, sizeof(ref_color)) != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "(x=" << x << " y=" << y << ") " |
| << "Reference value is different than the rendered data: " |
| << "(" << (unsigned int)ref_color[0] << ", " << (unsigned int)ref_color[1] |
| << ", " << (unsigned int)ref_color[2] << ", " << (unsigned int)ref_color[3] |
| << ") vs " |
| << "(" << (unsigned int)result[0] << ", " << (unsigned int)result[1] << ", " |
| << (unsigned int)result[2] << ", " << (unsigned int)result[3] << ")." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Rendered data mismatch"); |
| } /* if (memcmp(row_data + x * pixel_size, ref_color, sizeof(ref_color) ) != 0)*/ |
| } /* for (all pixels in a row) */ |
| } /* for (all rows) */ |
| } /* for (all layers) */ |
| |
| /* Done */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| |
| #undef N_TEXTURE_COMPONENTS |
| #undef TEXTURE_DEPTH |
| #undef TEXTURE_HEIGHT |
| #undef TEXTURE_WIDTH |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's desricption |
| **/ |
| GeometryShaderLayeredFramebufferStencil::GeometryShaderLayeredFramebufferStencil(Context& context, |
| const ExtParameters& extParams, |
| const char* name, |
| const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_fbo_id(0) |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_po_id(0) |
| , m_to_a_id(0) |
| , m_to_b_id(0) |
| , m_vao_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void GeometryShaderLayeredFramebufferStencil::deinit(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clean up */ |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| } |
| |
| if (m_gs_id != 0) |
| { |
| gl.deleteShader(m_gs_id); |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| } |
| |
| if (m_to_a_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_a_id); |
| } |
| |
| if (m_to_b_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_b_id); |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| } |
| |
| /* Release base class */ |
| TestCaseBase::deinit(); |
| } |
| |
| /** Executes the test. |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. |
| * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. |
| * Note the function throws exception should an error occur! |
| **/ |
| tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferStencil::iterate(void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Test-wide definitions */ |
| #define N_TEXTURE_COMPONENTS (4) |
| #define TEXTURE_DEPTH (4) |
| #define TEXTURE_HEIGHT (4) |
| #define TEXTURE_WIDTH (8) |
| |
| /* Fragment shader code */ |
| const char* fs_code = "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = vec4(1, 1, 1, 1);\n" |
| "}\n"; |
| |
| /* Geometry shader code */ |
| const char* gs_code = "${VERSION}\n" |
| "${GEOMETRY_SHADER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "layout (points) in;\n" |
| "layout (triangle_strip, max_vertices = 16) out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " for (int n = 0; n < 4; ++n)\n" |
| " {\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " gl_Layer = n;\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " gl_Layer = n;\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " gl_Layer = n;\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " gl_Layer = n;\n" |
| " EmitVertex();\n" |
| "\n" |
| " EndPrimitive();\n" |
| " }\n" |
| "\n" |
| "}\n"; |
| |
| /* General variables */ |
| int n = 0; |
| |
| unsigned char slice_null_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 1 /* byte per texel */] = { 0 }; |
| unsigned char slice_1_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 }; |
| unsigned char slice_2_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 }; |
| unsigned char slice_3_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 }; |
| unsigned char slice_4_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 }; |
| |
| /* This test should only run if EXT_geometry_shader is supported */ |
| if (!m_is_geometry_shader_extension_supported) |
| { |
| throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| /* Create shader & program objects */ |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); |
| m_po_id = gl.createProgram(); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create shader or program objects"); |
| |
| /* Build test program object */ |
| if (!buildProgram(m_po_id, m_fs_id, 1 /* parts */, &fs_code, m_gs_id, 1 /* parts */, &gs_code, m_vs_id, |
| 1 /* parts */, &m_boilerplate_vs_code)) |
| { |
| TCU_FAIL("Could not build test program object"); |
| } |
| |
| /* Generate and bind a vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| gl.bindVertexArray(m_vao_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create & bind a vertex array object."); |
| |
| /* Configure slice data */ |
| for (n = 0; n < TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */; ++n) |
| { |
| /* We are okay with depth data being filled with glitch, but need the stencil data to be |
| * as per test spec. To keep code simple, we do not differentiate between floating-point and |
| * stencil part. |
| */ |
| slice_1_data[n] = 2; |
| slice_2_data[n] = 1; |
| |
| /* Slices 3 and 4 should be filled with 0s */ |
| slice_3_data[n] = 0; |
| slice_4_data[n] = 0; |
| } /* for (all pixels making up slices) */ |
| |
| /* Set up texture objects */ |
| gl.genTextures(1, &m_to_a_id); |
| gl.genTextures(1, &m_to_b_id); |
| |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_a_id); |
| gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH, |
| 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, NULL); |
| |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object A."); |
| |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_b_id); |
| gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, GL_DEPTH32F_STENCIL8, TEXTURE_WIDTH, TEXTURE_HEIGHT, |
| TEXTURE_DEPTH, 0 /* border */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); |
| |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, |
| slice_1_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, |
| slice_2_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, |
| slice_3_data); |
| gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, |
| TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, |
| slice_4_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object B."); |
| |
| /* Set up depth tests */ |
| gl.disable(GL_DEPTH_TEST); |
| |
| /* Set up stencil tests */ |
| gl.enable(GL_STENCIL_TEST); |
| gl.stencilFunc(GL_LESS, 0, /* reference value */ 0xFFFFFFFF /* mask */); |
| |
| /* Set up framebuffer objects */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id); |
| |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */); |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_to_b_id, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer."); |
| |
| /* Issue the draw call. */ |
| gl.useProgram(m_po_id); |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed."); |
| |
| /* Check the results */ |
| for (n = 0; n < 4 /* layers */; ++n) |
| { |
| glw::GLenum fbo_completeness = GL_NONE; |
| int m = 0; |
| unsigned char ref_data[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS] = { 0 }; |
| unsigned char result_data[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS] = { 0 }; |
| int x = 0; |
| int y = 0; |
| |
| /* Configure the read framebuffer */ |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id); |
| |
| gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */, n); |
| gl.framebufferTexture(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0 /* texture */, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up read framebuffer."); |
| |
| /* Verify read framebuffer is considered complete */ |
| fbo_completeness = gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER); |
| |
| if (fbo_completeness != GL_FRAMEBUFFER_COMPLETE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Read FBO is incomplete: " |
| << "[" << fbo_completeness << "]" << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Read FBO is incomplete."); |
| } |
| |
| /* Build reference data */ |
| for (m = 0; m < TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS; ++m) |
| { |
| if (n < 2) |
| { |
| ref_data[m] = 255; |
| } |
| else |
| { |
| ref_data[m] = 0; |
| } |
| } /* for (all reference pixels) */ |
| |
| /* Read the rendered data */ |
| gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, result_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed"); |
| |
| for (y = 0; y < TEXTURE_HEIGHT; ++y) |
| { |
| int pixel_size = N_TEXTURE_COMPONENTS; |
| int row_size = pixel_size * TEXTURE_WIDTH; |
| unsigned char* ref_row = ref_data + y * row_size; |
| unsigned char* result_row = result_data + y * row_size; |
| |
| for (x = 0; x < TEXTURE_WIDTH; ++x) |
| { |
| if (memcmp(ref_row, result_row, pixel_size) != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "(x=" << x << " y=" << y << "): Rendered data " |
| << "(" << result_row[0] << ", " << result_row[1] << ", " << result_row[2] << ", " |
| << result_row[3] << ")" |
| << " is different from reference data " |
| << "(" << ref_row[0] << ", " << ref_row[1] << ", " << ref_row[2] << ", " |
| << ref_row[3] << ")" << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failed"); |
| } /* if (memcmp(ref_row, result_row, pixel_size) != 0) */ |
| |
| ref_row += pixel_size; |
| result_row += pixel_size; |
| } /* for (all pixels in a row) */ |
| } /* for (all pixels) */ |
| } /* for (all layers) */ |
| |
| /* Done */ |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| |
| #undef N_TEXTURE_COMPONENTS |
| #undef TEXTURE_DEPTH |
| #undef TEXTURE_HEIGHT |
| #undef TEXTURE_WIDTH |
| } |
| |
| } // namespace glcts |