| /*------------------------------------------------------------------------- |
| * 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 "esextcGeometryShaderRendering.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| #include <cmath> |
| #include <cstdlib> |
| #include <cstring> |
| |
| namespace glcts |
| { |
| |
| /** Constructor of the geometry shader test base class. |
| * |
| * @param context Rendering context |
| * @param name Name of the test |
| * @param description Description of the test |
| **/ |
| GeometryShaderRendering::GeometryShaderRendering(Context& context, const ExtParameters& extParams, const char* name, |
| const char* description) |
| : TestCaseGroupBase(context, extParams, name, description) |
| { |
| /* Left blank intentionally */ |
| } |
| |
| /** Retrieves test name for specific <input layout qualifier, |
| * output layout qualifier, draw call mode> combination. |
| * |
| * @param input Input layout qualifier. |
| * @param output_type Output layout qualifier. |
| * @param drawcall_mode Draw call mode. |
| * |
| * NOTE: This function throws TestError exception if the requested combination |
| * is considered invalid. |
| * |
| * @return Requested string. |
| **/ |
| const char* GeometryShaderRendering::getTestName(_shader_input input, _shader_output_type output_type, |
| glw::GLenum drawcall_mode) |
| { |
| const char* result = NULL; |
| |
| switch (input) |
| { |
| case SHADER_INPUT_POINTS: |
| { |
| switch (output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| result = "points_input_line_strip_output"; |
| break; |
| case SHADER_OUTPUT_TYPE_POINTS: |
| result = "points_input_points_output"; |
| break; |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| result = "points_input_triangles_output"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader output type requested"); |
| } |
| } /* switch (output_type) */ |
| |
| break; |
| } |
| |
| case SHADER_INPUT_LINES: |
| { |
| switch (output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_LINES: |
| result = "lines_input_line_strip_output_lines_drawcall"; |
| break; |
| case GL_LINE_STRIP: |
| result = "lines_input_line_strip_output_line_strip_drawcall"; |
| break; |
| case GL_LINE_LOOP: |
| result = "lines_input_line_strip_output_line_loop_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("UNrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_LINE_STRIP: */ |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_LINES: |
| result = "lines_input_points_output_lines_drawcall"; |
| break; |
| case GL_LINE_STRIP: |
| result = "lines_input_points_output_line_strip_drawcall"; |
| break; |
| case GL_LINE_LOOP: |
| result = "lines_input_points_output_line_loop_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("UNrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_POINTS: */ |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_LINES: |
| result = "lines_input_triangle_strip_output_lines_drawcall"; |
| break; |
| case GL_LINE_STRIP: |
| result = "lines_input_triangle_strip_output_line_strip_drawcall"; |
| break; |
| case GL_LINE_LOOP: |
| result = "lines_input_triangle_strip_output_line_loop_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("UNrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: */ |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader output type requested"); |
| } |
| } /* switch (output_type) */ |
| |
| break; |
| } /* case SHADER_INPUT_LINES:*/ |
| |
| case SHADER_INPUT_LINES_WITH_ADJACENCY: |
| { |
| switch (output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| if ((drawcall_mode == GL_LINES_ADJACENCY_EXT) || (drawcall_mode == GL_LINES_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_line_strip_output_lines_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) || (drawcall_mode == GL_LINE_STRIP_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_line_strip_output_line_strip_drawcall"; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_LINE_STRIP: */ |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| if ((drawcall_mode == GL_LINES_ADJACENCY_EXT) || (drawcall_mode == GL_LINES_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_points_output_lines_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) || (drawcall_mode == GL_LINE_STRIP_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_points_output_line_strip_drawcall"; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_POINTS: */ |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| if ((drawcall_mode == GL_LINES_ADJACENCY_EXT) || (drawcall_mode == GL_LINES_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_triangle_strip_output_lines_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) || (drawcall_mode == GL_LINE_STRIP_ADJACENCY)) |
| { |
| result = "lines_with_adjacency_input_triangle_strip_output_line_strip_drawcall"; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: */ |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader output type requested"); |
| } |
| } /* switch (output_type) */ |
| |
| break; |
| } /* case SHADER_INPUT_LINES_WITH_ADJACENCY: */ |
| |
| case SHADER_INPUT_TRIANGLES: |
| { |
| switch (output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_TRIANGLES: |
| result = "triangles_input_line_strip_output_triangles_drawcall"; |
| break; |
| case GL_TRIANGLE_FAN: |
| result = "triangles_input_line_strip_output_triangle_fan_drawcall"; |
| break; |
| case GL_TRIANGLE_STRIP: |
| result = "triangles_input_line_strip_output_triangle_strip_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_LINE_STRIP: */ |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_TRIANGLES: |
| result = "triangles_input_points_output_triangles_drawcall"; |
| break; |
| case GL_TRIANGLE_FAN: |
| result = "triangles_input_points_output_triangle_fan_drawcall"; |
| break; |
| case GL_TRIANGLE_STRIP: |
| result = "triangles_input_points_output_triangle_strip_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_POINTS: */ |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| switch (drawcall_mode) |
| { |
| case GL_TRIANGLES: |
| result = "triangles_input_triangle_strip_output_triangles_drawcall"; |
| break; |
| case GL_TRIANGLE_FAN: |
| result = "triangles_input_triangle_strip_output_triangle_fan_drawcall"; |
| break; |
| case GL_TRIANGLE_STRIP: |
| result = "triangles_input_triangle_strip_output_triangle_strip_drawcall"; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (drawcall_mode) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: */ |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader output type requested"); |
| } |
| } /* switch (output_type) */ |
| |
| break; |
| } /* case SHADER_INPUT_TRIANGLES: */ |
| |
| case SHADER_INPUT_TRIANGLES_WITH_ADJACENCY: |
| { |
| switch (output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| if ((drawcall_mode == GL_TRIANGLES_ADJACENCY_EXT) || (drawcall_mode == GL_TRIANGLES_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_line_strip_output_triangles_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY_EXT) || |
| (drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_line_strip_output_triangle_strip_adjacency_drawcall"; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_LINE_STRIP: */ |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| if ((drawcall_mode == GL_TRIANGLES_ADJACENCY_EXT) || (drawcall_mode == GL_TRIANGLES_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_points_output_triangles_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY_EXT) || |
| (drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_points_output_triangle_strip_adjacency_drawcall"; |
| break; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_POINTS:*/ |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| if ((drawcall_mode == GL_TRIANGLES_ADJACENCY_EXT) || (drawcall_mode == GL_TRIANGLES_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_triangle_strip_output_triangles_adjacency_drawcall"; |
| } |
| else if ((drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY_EXT) || |
| (drawcall_mode == GL_TRIANGLE_STRIP_ADJACENCY)) |
| { |
| result = "triangles_with_adjacency_input_triangle_strip_output_triangle_strip_adjacency_drawcall"; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: */ |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader output type requested"); |
| } |
| } /* switch (output_type) */ |
| |
| break; |
| } /* case SHADER_INPUT_TRIANGLES_WITH_ADJACENCY: */ |
| |
| default: |
| { |
| /* Unrecognized geometry shader input layout qualifier */ |
| TCU_FAIL("Unrecognized layout qualifier"); |
| } |
| } /* switch (input) */ |
| |
| return result; |
| } |
| |
| /* Initializes child instances of the group that will execute actual tests. */ |
| void GeometryShaderRendering::init(void) |
| { |
| /* Initialize base class */ |
| TestCaseGroupBase::init(); |
| |
| /* General variables */ |
| glw::GLenum drawcall_mode = GL_NONE; |
| _shader_input input = SHADER_INPUT_UNKNOWN; |
| |
| const glw::GLenum iterations[] = { /* geometry shader input layout qualifier */ /* draw call mode. */ |
| SHADER_INPUT_POINTS, GL_POINTS, SHADER_INPUT_LINES, GL_LINES, SHADER_INPUT_LINES, |
| GL_LINE_STRIP, SHADER_INPUT_LINES, GL_LINE_LOOP, |
| SHADER_INPUT_LINES_WITH_ADJACENCY, GL_LINES_ADJACENCY_EXT, |
| SHADER_INPUT_LINES_WITH_ADJACENCY, GL_LINE_STRIP_ADJACENCY_EXT, |
| SHADER_INPUT_TRIANGLES, GL_TRIANGLES, SHADER_INPUT_TRIANGLES, GL_TRIANGLE_FAN, |
| SHADER_INPUT_TRIANGLES, GL_TRIANGLE_STRIP, SHADER_INPUT_TRIANGLES_WITH_ADJACENCY, |
| GL_TRIANGLES_ADJACENCY_EXT, SHADER_INPUT_TRIANGLES_WITH_ADJACENCY, |
| GL_TRIANGLE_STRIP_ADJACENCY_EXT }; |
| const unsigned int n_iterations = sizeof(iterations) / sizeof(iterations[0]) / 2; |
| unsigned int n_output = 0; |
| |
| for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration) |
| { |
| /* Retrieve iteration-specific input layout qualifier and draw call mode data */ |
| input = (_shader_input)iterations[n_iteration * 2 + 0]; |
| drawcall_mode = iterations[n_iteration * 2 + 1]; |
| |
| /* Instantiate a worker. Each worker needs to be initialized & executed separately for each |
| * of the three supported input layout qualifiers.*/ |
| for (n_output = 0; n_output < SHADER_OUTPUT_TYPE_COUNT; ++n_output) |
| { |
| _shader_output_type output_type = (_shader_output_type)n_output; |
| const char* name = getTestName(input, output_type, drawcall_mode); |
| |
| switch (input) |
| { |
| case SHADER_INPUT_POINTS: |
| { |
| addChild( |
| new GeometryShaderRenderingPointsCase(m_context, m_extParams, name, drawcall_mode, output_type)); |
| |
| break; |
| } |
| |
| case SHADER_INPUT_LINES: |
| { |
| addChild(new GeometryShaderRenderingLinesCase(m_context, m_extParams, name, false, drawcall_mode, |
| output_type)); |
| |
| break; |
| } /* case SHADER_INPUT_LINES:*/ |
| |
| case SHADER_INPUT_LINES_WITH_ADJACENCY: |
| { |
| addChild(new GeometryShaderRenderingLinesCase(m_context, m_extParams, name, true, drawcall_mode, |
| output_type)); |
| |
| break; |
| } /* case SHADER_INPUT_LINES_WITH_ADJACENCY: */ |
| |
| case SHADER_INPUT_TRIANGLES: |
| { |
| addChild(new GeometryShaderRenderingTrianglesCase(m_context, m_extParams, name, false, drawcall_mode, |
| output_type)); |
| |
| break; |
| } |
| |
| case SHADER_INPUT_TRIANGLES_WITH_ADJACENCY: |
| { |
| addChild(new GeometryShaderRenderingTrianglesCase(m_context, m_extParams, name, true, drawcall_mode, |
| output_type)); |
| |
| break; |
| } |
| |
| default: |
| { |
| /* Unrecognized geometry shader input layout qualifier */ |
| TCU_FAIL("Unrecognized layout qualifier"); |
| } |
| } /* switch (input) */ |
| } /* for (all output layout qualifiers) */ |
| } /* for (all iterations) */ |
| } |
| |
| /** Base worker implementation */ |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| * @param testContext Test context. |
| * @param name Name of the test. |
| * @param description Description of what the test does. |
| **/ |
| GeometryShaderRenderingCase::GeometryShaderRenderingCase(Context& context, const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_context(context) |
| , m_instanced_raw_arrays_bo_id(0) |
| , m_instanced_unordered_arrays_bo_id(0) |
| , m_instanced_unordered_elements_bo_id(0) |
| , m_noninstanced_raw_arrays_bo_id(0) |
| , m_noninstanced_unordered_arrays_bo_id(0) |
| , m_noninstanced_unordered_elements_bo_id(0) |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_po_id(0) |
| , m_renderingTargetSize_uniform_location(0) |
| , m_singleRenderingTargetSize_uniform_location(0) |
| , m_vao_id(0) |
| , m_vs_id(0) |
| , m_fbo_id(0) |
| , m_read_fbo_id(0) |
| , m_to_id(0) |
| , m_instanced_fbo_id(0) |
| , m_instanced_read_fbo_id(0) |
| , m_instanced_to_id(0) |
| { |
| /* Left blank intentionally */ |
| } |
| |
| /** Releases all GLES objects initialized by the base class for geometry shader rendering case implementations. */ |
| void GeometryShaderRenderingCase::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| |
| m_fbo_id = 0; |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| |
| m_fs_id = 0; |
| } |
| |
| if (m_gs_id != 0) |
| { |
| gl.deleteShader(m_gs_id); |
| |
| m_gs_id = 0; |
| } |
| |
| if (m_instanced_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_instanced_fbo_id); |
| |
| m_instanced_fbo_id = 0; |
| } |
| |
| if (m_instanced_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_instanced_read_fbo_id); |
| |
| m_instanced_read_fbo_id = 0; |
| } |
| |
| if (m_instanced_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_instanced_to_id); |
| |
| m_instanced_to_id = 0; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_instanced_raw_arrays_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_instanced_raw_arrays_bo_id); |
| |
| m_instanced_raw_arrays_bo_id = 0; |
| } |
| |
| if (m_instanced_unordered_arrays_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_instanced_unordered_arrays_bo_id); |
| |
| m_instanced_unordered_arrays_bo_id = 0; |
| } |
| |
| if (m_instanced_unordered_elements_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_instanced_unordered_elements_bo_id); |
| |
| m_instanced_unordered_elements_bo_id = 0; |
| } |
| |
| if (m_noninstanced_raw_arrays_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_noninstanced_raw_arrays_bo_id); |
| |
| m_noninstanced_raw_arrays_bo_id = 0; |
| } |
| |
| if (m_noninstanced_unordered_arrays_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_noninstanced_unordered_arrays_bo_id); |
| |
| m_noninstanced_unordered_arrays_bo_id = 0; |
| } |
| |
| if (m_noninstanced_unordered_elements_bo_id != 0) |
| { |
| gl.deleteBuffers(1, &m_noninstanced_unordered_elements_bo_id); |
| |
| m_noninstanced_unordered_elements_bo_id = 0; |
| } |
| |
| if (m_read_fbo_id != 0) |
| { |
| gl.deleteFramebuffers(1, &m_read_fbo_id); |
| |
| m_read_fbo_id = 0; |
| } |
| |
| if (m_to_id != 0) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| |
| m_to_id = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /** Executes actual geometry shader-based rendering test, using an user-specified draw call. |
| * |
| * @param type Type of the draw call to use for the test. |
| **/ |
| void GeometryShaderRenderingCase::executeTest(GeometryShaderRenderingCase::_draw_call_type type) |
| { |
| glw::GLuint draw_fbo_id = 0; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const glw::GLenum index_type = getUnorderedElementsDataType(); |
| const glw::GLubyte max_elements_index = getUnorderedElementsMaxIndex(); |
| const glw::GLubyte min_elements_index = getUnorderedElementsMinIndex(); |
| const glw::GLenum mode = getDrawCallMode(); |
| unsigned int n_elements = getAmountOfElementsPerInstance(); |
| unsigned int n_instance = 0; |
| unsigned int n_instances = getAmountOfDrawInstances(); |
| const unsigned int n_vertices = getAmountOfVerticesPerInstance(); |
| const glw::GLint position_attribute_location = gl.getAttribLocation(m_po_id, "position"); |
| glw::GLuint read_fbo_id = 0; |
| unsigned int rt_height = 0; |
| unsigned int rt_width = 0; |
| unsigned int single_rt_height = 0; |
| unsigned int single_rt_width = 0; |
| |
| /* Reduce n_instances to 1 for non-instanced draw call modes */ |
| if (type == DRAW_CALL_TYPE_GL_DRAW_ARRAYS || type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS || |
| type == DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS) |
| { |
| draw_fbo_id = m_fbo_id; |
| n_instances = 1; |
| read_fbo_id = m_read_fbo_id; |
| } |
| else |
| { |
| draw_fbo_id = m_instanced_fbo_id; |
| read_fbo_id = m_instanced_read_fbo_id; |
| } |
| |
| /* Retrieve render-target size */ |
| getRenderTargetSize(n_instances, &rt_width, &rt_height); |
| getRenderTargetSize(1, &single_rt_width, &single_rt_height); |
| |
| /* Configure GL_ARRAY_BUFFER binding */ |
| switch (type) |
| { |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS: |
| { |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_noninstanced_raw_arrays_bo_id); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED: |
| { |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_instanced_raw_arrays_bo_id); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED: |
| { |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_instanced_unordered_arrays_bo_id); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS: |
| case DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS: |
| { |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_noninstanced_unordered_arrays_bo_id); |
| |
| break; |
| } |
| |
| default: |
| { |
| /* Unrecognized draw call mode */ |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (type) */ |
| |
| gl.vertexAttribPointer(position_attribute_location, 4, GL_FLOAT, GL_FALSE, 0 /* stride */, NULL); |
| gl.enableVertexAttribArray(position_attribute_location); |
| |
| /* Configure GL_ELEMENT_ARRAY_BUFFER binding */ |
| switch (type) |
| { |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS: |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED: |
| { |
| gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED: |
| { |
| gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_instanced_unordered_elements_bo_id); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS: |
| case DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS: |
| { |
| gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_noninstanced_unordered_elements_bo_id); |
| |
| break; |
| } |
| |
| default: |
| { |
| /* Unrecognized draw call mode */ |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (type) */ |
| |
| /* Configure draw framebuffer */ |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fbo_id); |
| gl.viewport(0 /* x */, 0 /* y */, rt_width, rt_height); |
| |
| /* Clear the color buffer. */ |
| gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Test set-up failed."); |
| |
| /* Render the test geometry */ |
| gl.useProgram(m_po_id); |
| gl.uniform2i(m_renderingTargetSize_uniform_location, rt_width, rt_height); |
| gl.uniform2i(m_singleRenderingTargetSize_uniform_location, single_rt_width, single_rt_height); |
| |
| setUniformsBeforeDrawCall(type); |
| |
| switch (type) |
| { |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS: |
| { |
| gl.drawArrays(mode, 0 /* first */, n_vertices); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED: |
| { |
| gl.drawArraysInstanced(mode, 0 /* first */, n_vertices, n_instances); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS: |
| { |
| gl.drawElements(mode, n_elements, index_type, NULL); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED: |
| { |
| gl.drawElementsInstanced(mode, n_elements, index_type, NULL, n_instances); |
| |
| break; |
| } |
| |
| case DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS: |
| { |
| gl.drawRangeElements(mode, min_elements_index, max_elements_index, n_elements, index_type, NULL); |
| |
| break; |
| } |
| |
| default: |
| { |
| /* Unrecognized draw call mode */ |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (type) */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed."); |
| |
| /* Retrieve rendered data */ |
| unsigned char* rendered_data = new unsigned char[rt_height * rt_width * 4 /* components */]; |
| |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo_id); |
| gl.readPixels(0 /* x */, 0 /* y */, rt_width, rt_height, GL_RGBA, GL_UNSIGNED_BYTE, rendered_data); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed"); |
| |
| /* Verify if the test succeeded */ |
| for (n_instance = 0; n_instance < n_instances; ++n_instance) |
| { |
| verify(type, n_instance, rendered_data); |
| } /* for (all instances) */ |
| |
| /* Release the data buffer */ |
| delete[] rendered_data; |
| } |
| |
| /** Initializes ES objects required to execute a set of tests for particular input layout qualifier. */ |
| void GeometryShaderRenderingCase::initTest() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Retrieve derivative class' properties */ |
| std::string fs_code = getFragmentShaderCode(); |
| std::string gs_code = getGeometryShaderCode(); |
| unsigned int n = 0; |
| unsigned int n_instances = getAmountOfDrawInstances(); |
| std::string vs_code = getVertexShaderCode(); |
| |
| /* Set pixel storage properties before we continue */ |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| |
| /* Create buffer objects the derivative implementation will fill with data */ |
| gl.genBuffers(1, &m_instanced_raw_arrays_bo_id); |
| gl.genBuffers(1, &m_instanced_unordered_arrays_bo_id); |
| gl.genBuffers(1, &m_instanced_unordered_elements_bo_id); |
| gl.genBuffers(1, &m_noninstanced_raw_arrays_bo_id); |
| gl.genBuffers(1, &m_noninstanced_unordered_arrays_bo_id); |
| gl.genBuffers(1, &m_noninstanced_unordered_elements_bo_id); |
| |
| /* Set up a separate set of objects, that will be used for testing instanced and non-instanced draw calls */ |
| for (n = 0; n < 2 /* non-/instanced draw calls */; ++n) |
| { |
| bool is_instanced = (n == 1); |
| |
| glw::GLuint* draw_fbo_id_ptr = !is_instanced ? &m_fbo_id : &m_instanced_fbo_id; |
| glw::GLuint* read_fbo_id_ptr = (!is_instanced) ? &m_read_fbo_id : &m_instanced_read_fbo_id; |
| unsigned int to_height = 0; |
| unsigned int to_width = 0; |
| glw::GLuint* to_id_ptr = (!is_instanced) ? &m_to_id : &m_instanced_to_id; |
| |
| /* n == 0: non-instanced draw calls, instanced otherwise */ |
| getRenderTargetSize((n == 0) ? 1 : n_instances, &to_width, &to_height); |
| |
| /* Create a texture object we will be rendering to */ |
| gl.genTextures(1, to_id_ptr); |
| gl.bindTexture(GL_TEXTURE_2D, *to_id_ptr); |
| gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, to_width, to_height); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure a 2D texture object"); |
| |
| /* Create and configure a framebuffer object that will be used for rendering */ |
| gl.genFramebuffers(1, draw_fbo_id_ptr); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *draw_fbo_id_ptr); |
| |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *to_id_ptr, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure draw framebuffer object"); |
| |
| if (gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
| { |
| TCU_FAIL("Draw framebuffer is reported to be incomplete"); |
| } /* if (gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) */ |
| |
| /* Create and bind a FBO we will use for reading rendered data */ |
| gl.genFramebuffers(1, read_fbo_id_ptr); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *read_fbo_id_ptr); |
| |
| gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *to_id_ptr, 0 /* level */); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure read framebuffer object"); |
| |
| if (gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
| { |
| TCU_FAIL("Read framebuffer is reported to be incomplete"); |
| } /* if (gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) */ |
| |
| /* Fill the iteration-specific buffer objects with data */ |
| glw::GLuint raw_arrays_bo_id = (is_instanced) ? m_instanced_raw_arrays_bo_id : m_noninstanced_raw_arrays_bo_id; |
| unsigned int raw_arrays_bo_size = getRawArraysDataBufferSize(is_instanced); |
| const void* raw_arrays_data = getRawArraysDataBuffer(is_instanced); |
| glw::GLuint unordered_arrays_bo_id = |
| (is_instanced) ? m_instanced_unordered_arrays_bo_id : m_noninstanced_unordered_arrays_bo_id; |
| unsigned int unordered_arrays_bo_size = getUnorderedArraysDataBufferSize(is_instanced); |
| const void* unordered_arrays_data = getUnorderedArraysDataBuffer(is_instanced); |
| glw::GLuint unordered_elements_bo_id = |
| (is_instanced) ? m_instanced_unordered_elements_bo_id : m_noninstanced_unordered_elements_bo_id; |
| unsigned int unordered_elements_bo_size = getUnorderedElementsDataBufferSize(is_instanced); |
| const void* unordered_elements_data = getUnorderedElementsDataBuffer(is_instanced); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, raw_arrays_bo_id); |
| gl.bufferData(GL_ARRAY_BUFFER, raw_arrays_bo_size, raw_arrays_data, GL_STATIC_COPY); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, unordered_arrays_bo_id); |
| gl.bufferData(GL_ARRAY_BUFFER, unordered_arrays_bo_size, unordered_arrays_data, GL_STATIC_COPY); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, unordered_elements_bo_id); |
| gl.bufferData(GL_ARRAY_BUFFER, unordered_elements_bo_size, unordered_elements_data, GL_STATIC_COPY); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure test buffer objects"); |
| |
| /* Create and bind a VAO */ |
| gl.genVertexArrays(1, &m_vao_id); |
| gl.bindVertexArray(m_vao_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate & bind a vertex array object"); |
| |
| /* Create and configure program & shader objects that will be used for the test case */ |
| const char* fs_code_ptr = fs_code.c_str(); |
| const char* gs_code_ptr = gs_code.c_str(); |
| const char* vs_code_ptr = vs_code.c_str(); |
| |
| 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/program objects"); |
| |
| if (!buildProgram(m_po_id, m_fs_id, 1, &fs_code_ptr, m_gs_id, 1, &gs_code_ptr, m_vs_id, 1, &vs_code_ptr)) |
| { |
| TCU_FAIL("Could not build shader program"); |
| } |
| |
| /* Retrieve uniform locations */ |
| m_renderingTargetSize_uniform_location = gl.getUniformLocation(m_po_id, "renderingTargetSize"); |
| m_singleRenderingTargetSize_uniform_location = gl.getUniformLocation(m_po_id, "singleRenderingTargetSize"); |
| } |
| |
| /* Checks all draw call types for a specific Geometry Shader input layout qualifier. |
| * |
| * @return Always STOP. |
| */ |
| tcu::TestNode::IterateResult GeometryShaderRenderingCase::iterate() |
| { |
| if (!m_is_geometry_shader_extension_supported) |
| { |
| throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| initTest(); |
| |
| executeTest(GeometryShaderRenderingCase::DRAW_CALL_TYPE_GL_DRAW_ARRAYS); |
| executeTest(GeometryShaderRenderingCase::DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED); |
| executeTest(GeometryShaderRenderingCase::DRAW_CALL_TYPE_GL_DRAW_ELEMENTS); |
| executeTest(GeometryShaderRenderingCase::DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED); |
| executeTest(GeometryShaderRenderingCase::DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS); |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param drawcall_mode Draw call mode that should be tested with this test case instance. |
| * @param output_type Geometry shader output type to be used. |
| * @param context Rendering context; |
| * @param testContext Test context; |
| * @param name Test name. |
| **/ |
| GeometryShaderRenderingPointsCase::GeometryShaderRenderingPointsCase(Context& context, const ExtParameters& extParams, |
| const char* name, glw::GLenum drawcall_mode, |
| _shader_output_type output_type) |
| : GeometryShaderRenderingCase( |
| context, extParams, name, |
| "Verifies all draw calls work correctly for specific input+output+draw call mode combination") |
| , m_output_type(output_type) |
| { |
| /* Sanity checks */ |
| if (drawcall_mode != GL_POINTS) |
| { |
| TCU_FAIL("Only GL_POINTS draw call mode is supported for 'points' geometry shader input layout qualifier test " |
| "implementation"); |
| } |
| |
| if (output_type != SHADER_OUTPUT_TYPE_POINTS && output_type != SHADER_OUTPUT_TYPE_LINE_STRIP && |
| output_type != SHADER_OUTPUT_TYPE_TRIANGLE_STRIP) |
| { |
| TCU_FAIL("Unsupported output layout qualifier type requested for 'points' geometry shader input layout " |
| "qualifier test implementation"); |
| } |
| |
| /* Retrieve rendertarget resolution for a single-instance case. |
| * |
| * Y coordinates will be dynamically updated in a vertex shader for |
| * multiple-instance tests. That's fine, since in multi-instanced tests |
| * we only expand the rendertarget's height; its width is unaffected. |
| */ |
| unsigned int rendertarget_height = 0; |
| unsigned int rendertarget_width = 0; |
| |
| getRenderTargetSize(1, &rendertarget_width, &rendertarget_height); |
| |
| /* Generate raw vertex array data. Note we do not differentiate between instanced and |
| * non-instanced cases for geometry shaders that emit points */ |
| const unsigned int raw_array_data_size = getRawArraysDataBufferSize(false); |
| |
| m_raw_array_data = new float[raw_array_data_size / sizeof(float)]; |
| |
| for (unsigned int n_point = 0; n_point < 8 /* points, as per test spec */; ++n_point) |
| { |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| m_raw_array_data[n_point * 4 + 0] = |
| -1 + ((float(3 + 7 * n_point) + 0.5f) / float(rendertarget_width)) * 2.0f; |
| m_raw_array_data[n_point * 4 + 1] = -1 + ((float(3.0f + 0.5f)) / float(rendertarget_height)) * 2.0f; |
| m_raw_array_data[n_point * 4 + 2] = 0.0f; |
| m_raw_array_data[n_point * 4 + 3] = 1.0f; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| m_raw_array_data[n_point * 4 + 0] = |
| -1 + ((float(1 + 5 * n_point) + 0.5f) / float(rendertarget_width)) * 2.0f; |
| m_raw_array_data[n_point * 4 + 1] = -1 + (float(1.5f + 0.5f) / float(rendertarget_height)) * 2.0f; |
| m_raw_array_data[n_point * 4 + 2] = 0.0f; |
| m_raw_array_data[n_point * 4 + 3] = 1.0f; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| m_raw_array_data[n_point * 4 + 0] = -1 + ((float(6 * n_point) + 0.5f) / float(rendertarget_width)) * 2.0f; |
| m_raw_array_data[n_point * 4 + 1] = -1.0f; |
| m_raw_array_data[n_point * 4 + 2] = 0.0f; |
| m_raw_array_data[n_point * 4 + 3] = 1.0f; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unsupported shader output layout qualifier requested"); |
| } |
| } /* switch (m_output_type) */ |
| } /* for (all points) */ |
| |
| /* Generate unordered data - we do not differentiate between instanced & non-instanced cases |
| * for "points" tests |
| */ |
| const unsigned int unordered_array_data_size = getUnorderedArraysDataBufferSize(false); |
| const unsigned int unordered_elements_data_size = getUnorderedElementsDataBufferSize(false); |
| |
| m_unordered_array_data = new float[unordered_array_data_size / sizeof(float)]; |
| m_unordered_elements_data = new unsigned char[unordered_elements_data_size]; |
| |
| for (unsigned int n_point = 0; n_point < 8 /* points, as per test spec */; ++n_point) |
| { |
| memcpy(m_unordered_array_data + n_point * 4, m_raw_array_data + (8 - n_point - 1) * 4, |
| sizeof(float) * 4 /* components */); |
| } /* for (all points) */ |
| |
| for (unsigned int n_point = 0; n_point < 8 /* points, as per test spec */; ++n_point) |
| { |
| m_unordered_elements_data[n_point] = (unsigned char)((n_point * 2) % 8 + n_point / 4); |
| } /* for (all points) */ |
| } |
| |
| /** Destructor. */ |
| GeometryShaderRenderingPointsCase::~GeometryShaderRenderingPointsCase() |
| { |
| if (m_raw_array_data != NULL) |
| { |
| delete[] m_raw_array_data; |
| |
| m_raw_array_data = NULL; |
| } |
| |
| if (m_unordered_array_data != NULL) |
| { |
| delete[] m_unordered_array_data; |
| |
| m_unordered_array_data = NULL; |
| } |
| |
| if (m_unordered_elements_data != NULL) |
| { |
| delete[] m_unordered_elements_data; |
| |
| m_unordered_elements_data = NULL; |
| } |
| } |
| |
| /** Retrieves amount of instances that should be drawn with glDraw*Elements() calls. |
| * |
| * @return As per description. |
| **/ |
| unsigned int GeometryShaderRenderingPointsCase::getAmountOfDrawInstances() |
| { |
| return 4 /* instances */; |
| } |
| |
| /** Retrieves amount of indices that should be used for rendering a single instance |
| * (glDraw*Elements() calls only) |
| * |
| * @return As per description. |
| */ |
| unsigned int GeometryShaderRenderingPointsCase::getAmountOfElementsPerInstance() |
| { |
| return 8 /* elements */; |
| } |
| |
| /** Retrieves amount of vertices that should be used for rendering a single instance |
| * (glDrawArrays*() calls only) |
| * |
| * @return As per description. |
| **/ |
| unsigned int GeometryShaderRenderingPointsCase::getAmountOfVerticesPerInstance() |
| { |
| return 8 /* points */; |
| } |
| |
| /** Draw call mode that should be used glDraw*() calls. |
| * |
| * @return As per description. |
| **/ |
| glw::GLenum GeometryShaderRenderingPointsCase::getDrawCallMode() |
| { |
| return GL_POINTS; |
| } |
| |
| /** Source code for a fragment shader that should be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingPointsCase::getFragmentShaderCode() |
| { |
| static std::string fs_code = "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in vec4 gs_fs_color;\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = gs_fs_color;\n" |
| "}\n"; |
| |
| return fs_code; |
| } |
| |
| /** Source code for a geometry shader that should be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingPointsCase::getGeometryShaderCode() |
| { |
| static const char* lines_gs_code = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(line_strip, max_vertices=15) out;\n" |
| "\n" |
| "in vec4 vs_gs_color[1];\n" |
| "out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " float bias = 0.0035;" |
| " for (int delta = 1; delta <= 3; ++delta)\n" |
| " {\n" |
| " float dx = float(delta * 2) / float(renderingTargetSize.x) + bias;\n" |
| " float dy = float(delta * 2) / float(renderingTargetSize.y) + bias;\n" |
| "\n" |
| /* TL->TR */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(dx, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* TR->BR */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(dx, dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* BR->BL */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* BL->TL */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| " }\n" |
| "}\n"; |
| |
| static const char* points_gs_code = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices=9) out;\n" |
| "\n" |
| "in vec4 vs_gs_color[1];\n" |
| "out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " float dx = 2.0 / float(renderingTargetSize.x);\n" |
| " float dy = 2.0 / float(renderingTargetSize.y);\n" |
| "\n" |
| /* TL */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* TM */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(0, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* TR */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(dx, -dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* L */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, 0, 0, 0); \n" |
| " EmitVertex();\n" |
| /* M */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| " EmitVertex();\n" |
| /* R */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(dx, 0, 0, 0);\n" |
| " EmitVertex();\n" |
| /* BL */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(-dx, dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* BM */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(0, dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* BR */ |
| " gs_fs_color = vs_gs_color[0];\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(dx, dy, 0, 0);\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| static const char* triangles_gs_code = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices=6) out;\n" |
| "\n" |
| "in vec4 vs_gs_color[1];\n" |
| "out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| /* Assume that point position corresponds to TL corner. */ |
| " float dx = float(2.0) / float(renderingTargetSize.x);\n" |
| " float dy = float(2.0) / float(renderingTargetSize.y);\n" |
| "\n" |
| /* BL 1 */ |
| " gs_fs_color = vec4(vs_gs_color[0].x, 0, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(0, 6.0 * dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* TL 1 */ |
| " gs_fs_color = vec4(vs_gs_color[0].x, 0, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| " EmitVertex();\n" |
| /* BR 1 */ |
| " gs_fs_color = vec4(vs_gs_color[0].x, 0, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(6.0 * dx, 6.0 * dy, 0, 0);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| /* BR 2 */ |
| " gs_fs_color = vec4(0, vs_gs_color[0].y, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(6.0 * dx, 6.0 * dy, 0, 0);\n" |
| " EmitVertex();\n" |
| /* TL 2 */ |
| " gs_fs_color = vec4(0, vs_gs_color[0].y, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| " EmitVertex();\n" |
| /* TR 2 */ |
| " gs_fs_color = vec4(0, vs_gs_color[0].y, 0, 0);\n" |
| " gl_Position = gl_in[0].gl_Position + vec4(6.0 * dx, 0, 0, 0);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| "}\n"; |
| const char* result = NULL; |
| |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| result = lines_gs_code; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| result = points_gs_code; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| result = triangles_gs_code; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Requested shader output layout qualifier is unsupported"); |
| } |
| } /* switch (m_output_type) */ |
| |
| return result; |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * vertex data to be used for glDrawArrays*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| **/ |
| glw::GLuint GeometryShaderRenderingPointsCase::getRawArraysDataBufferSize(bool /*instanced*/) |
| { |
| |
| return sizeof(float) * (1 /* point */ * 4 /* coordinates */) * 8 /* points in total, as per test spec */; |
| } |
| |
| /** Returns vertex data for the test. Only to be used for glDrawArrays*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| **/ |
| const void* GeometryShaderRenderingPointsCase::getRawArraysDataBuffer(bool /*instanced*/) |
| { |
| return m_raw_array_data; |
| } |
| |
| /** Retrieves resolution of off-screen rendering buffer that should be used for the test. |
| * |
| * @param n_instances Amount of draw call instances this render target will be used for. |
| * @param out_width Deref will be used to store rendertarget's width. Must not be NULL. |
| * @param out_height Deref will be used to store rendertarget's height. Must not be NULL. |
| **/ |
| void GeometryShaderRenderingPointsCase::getRenderTargetSize(unsigned int n_instances, unsigned int* out_width, |
| unsigned int* out_height) |
| { |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| *out_width = 56; /* as per test spec */ |
| *out_height = 7 * n_instances; /* as per test spec */ |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| *out_width = 38; /* as per test spec */ |
| *out_height = 3 * n_instances + 2 * (n_instances - 1); /* as per test spec */ |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| *out_width = 48; /* as per test spec */ |
| *out_height = 6 * n_instances; /* as per test spec */ |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unsupported shader output type"); |
| } |
| } /* switch (m_output_type) */ |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * vertex data to be used for glDrawElements*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| **/ |
| glw::GLuint GeometryShaderRenderingPointsCase::getUnorderedArraysDataBufferSize(bool /*instanced*/) |
| { |
| |
| /* Note: No difference between non-instanced and instanced cases for this class */ |
| return sizeof(float) * (1 /* point */ * 4 /* coordinates */) * 8 /* points in total, as per test spec */; |
| } |
| |
| /** Returns vertex data for the test. Only to be used for glDrawElements*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| **/ |
| const void* GeometryShaderRenderingPointsCase::getUnorderedArraysDataBuffer(bool /*instanced*/) |
| { |
| |
| /* Note: No difference between non-instanced and instanced cases for this class */ |
| return m_unordered_array_data; |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * index data to be used for glDrawElements*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| */ |
| glw::GLuint GeometryShaderRenderingPointsCase::getUnorderedElementsDataBufferSize(bool /*instanced*/) |
| { |
| |
| /* Note: No difference between non-instanced and instanced cases for this class */ |
| return 8 /* indices */ * sizeof(unsigned char); |
| } |
| |
| /** Returns index data for the test. Only to be used for glDrawElements*() calls. |
| * |
| * @param instanced Ignored. |
| * |
| * @return As per description. |
| **/ |
| const void* GeometryShaderRenderingPointsCase::getUnorderedElementsDataBuffer(bool /*instanced*/) |
| { |
| |
| /* Note: No difference between non-instanced and instanced cases for this class */ |
| return m_unordered_elements_data; |
| } |
| |
| /** Returns type of the index, to be used for glDrawElements*() calls. |
| * |
| * @return As per description. |
| **/ |
| glw::GLenum GeometryShaderRenderingPointsCase::getUnorderedElementsDataType() |
| { |
| return GL_UNSIGNED_BYTE; |
| } |
| |
| /** Retrieves maximum index value. To be used for glDrawRangeElements() test only. |
| * |
| * @return As per description. |
| **/ |
| glw::GLubyte GeometryShaderRenderingPointsCase::getUnorderedElementsMaxIndex() |
| { |
| return 8 /* up to 8 points will be rendered */; |
| } |
| |
| /** Retrieves minimum index value. To be used for glDrawRangeElements() test only. |
| * |
| * @return As per description. |
| **/ |
| glw::GLubyte GeometryShaderRenderingPointsCase::getUnorderedElementsMinIndex() |
| { |
| return 0; |
| } |
| |
| /** Retrieves vertex shader code to be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingPointsCase::getVertexShaderCode() |
| { |
| static std::string lines_vs_code = |
| "${VERSION}\n" |
| "\n" |
| "in vec4 position;\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "out vec4 vs_gs_color;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| /* non-instanced draw call cases */ |
| " if (renderingTargetSize.y == 7)\n" |
| " {\n" |
| " gl_Position = position;" |
| " }\n" |
| " else\n" |
| " {\n" |
| /* instanced draw call cases: */ |
| " gl_Position = vec4(position.x, \n" |
| " -1.0 + ((float(3 + gl_InstanceID * 7)) / float(renderingTargetSize.y - 1)) * 2.0,\n" |
| " position.zw);\n" |
| " }\n" |
| "\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 0: vs_gs_color = vec4(1, 0, 0, 0); break;\n" |
| " case 1: vs_gs_color = vec4(0, 1, 0, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0, 0, 1, 0); break;\n" |
| " case 3: vs_gs_color = vec4(0, 0, 0, 1); break;\n" |
| " case 4: vs_gs_color = vec4(1, 1, 0, 0); break;\n" |
| " case 5: vs_gs_color = vec4(1, 0, 1, 0); break;\n" |
| " case 6: vs_gs_color = vec4(1, 0, 0, 1); break;\n" |
| " case 7: vs_gs_color = vec4(1, 1, 1, 0); break;\n" |
| " case 8: vs_gs_color = vec4(1, 1, 0, 1); break;\n" |
| " }\n" |
| "}\n"; |
| |
| static std::string points_vs_code = |
| "${VERSION}\n" |
| "\n" |
| "in vec4 position;\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "out vec4 vs_gs_color;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_PointSize = 1.0;\n" |
| "\n" |
| /* non-instanced draw call cases */ |
| " if (renderingTargetSize.y == 3)\n" |
| " {\n" |
| " gl_Position = position;\n" |
| " }\n" |
| /* instanced draw call cases */ |
| " else\n" |
| " {\n" |
| " gl_Position = vec4(position.x,\n" |
| " -1.0 + (1.5 + float(5 * gl_InstanceID)) / float(renderingTargetSize.y) * 2.0,\n" |
| " position.zw);\n" |
| " }\n" |
| "\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 0: vs_gs_color = vec4(1, 0, 0, 0); break;\n" |
| " case 1: vs_gs_color = vec4(0, 1, 0, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0, 0, 1, 0); break;\n" |
| " case 3: vs_gs_color = vec4(0, 0, 0, 1); break;\n" |
| " case 4: vs_gs_color = vec4(1, 1, 0, 0); break;\n" |
| " case 5: vs_gs_color = vec4(1, 0, 1, 0); break;\n" |
| " case 6: vs_gs_color = vec4(1, 0, 0, 1); break;\n" |
| " case 7: vs_gs_color = vec4(1, 1, 1, 0); break;\n" |
| " case 8: vs_gs_color = vec4(1, 1, 0, 1); break;\n" |
| " }\n" |
| "}\n"; |
| |
| static std::string triangles_vs_code = |
| "${VERSION}\n" |
| "\n" |
| "in vec4 position;\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "out vec4 vs_gs_color;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (renderingTargetSize.y == 6)\n" |
| " {\n" |
| " gl_Position = position;\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " gl_Position = vec4(position.x,\n" |
| " position.y + float(gl_InstanceID) * 6.0 / float(renderingTargetSize.y) * 2.0,\n" |
| " position.zw);\n" |
| " }\n" |
| "\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 0: vs_gs_color = vec4(0.1, 0.8, 0, 0); break;\n" |
| " case 1: vs_gs_color = vec4(0.2, 0.7, 0, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0.3, 0.6, 1, 0); break;\n" |
| " case 3: vs_gs_color = vec4(0.4, 0.5, 0, 1); break;\n" |
| " case 4: vs_gs_color = vec4(0.5, 0.4, 0, 0); break;\n" |
| " case 5: vs_gs_color = vec4(0.6, 0.3, 1, 0); break;\n" |
| " case 6: vs_gs_color = vec4(0.7, 0.2, 0, 1); break;\n" |
| " case 7: vs_gs_color = vec4(0.8, 0.1, 1, 0); break;\n" |
| " }\n" |
| "}\n"; |
| std::string result; |
| |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| result = lines_vs_code; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| result = points_vs_code; |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| result = triangles_vs_code; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unsupported shader output type used"); |
| } |
| } /* switch (m_output_type) */ |
| |
| return result; |
| } |
| |
| /** Verifies that the rendered data is correct. |
| * |
| * @param drawcall_type Type of the draw call that was used to render the geometry. |
| * @param instance_id Instance ID to be verified. Use 0 for non-instanced draw calls. |
| * @param data Contents of the rendertarget after the test has finished rendering. |
| **/ |
| void GeometryShaderRenderingPointsCase::verify(_draw_call_type drawcall_type, unsigned int instance_id, |
| const unsigned char* data) |
| { |
| /* The array is directly related to vertex shader contents for "points" and "line_strip" |
| * outputs */ |
| static const unsigned char ref_data[] = { 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, |
| 0, 0, 0, 255, 255, 255, 0, 0, 255, 0, 255, 0, |
| 255, 0, 0, 255, 255, 255, 255, 0, 255, 255, 0, 255 }; |
| /* The array refers to colors as defined in vertex shader used for "triangle_strip" |
| * output. |
| */ |
| static const unsigned char ref_data_triangle_strip[] = { |
| (unsigned char)(0.1f * 255), (unsigned char)(0.8f * 255), 0, 0, |
| (unsigned char)(0.2f * 255), (unsigned char)(0.7f * 255), 0, 0, |
| (unsigned char)(0.3f * 255), (unsigned char)(0.6f * 255), 255, 0, |
| (unsigned char)(0.4f * 255), (unsigned char)(0.5f * 255), 0, 255, |
| (unsigned char)(0.5f * 255), (unsigned char)(0.4f * 255), 0, 0, |
| (unsigned char)(0.6f * 255), (unsigned char)(0.3f * 255), 255, 0, |
| (unsigned char)(0.7f * 255), (unsigned char)(0.2f * 255), 0, 255, |
| (unsigned char)(0.8f * 255), (unsigned char)(0.1f * 255), 255, 0 |
| }; |
| unsigned int rt_height = 0; |
| unsigned int rt_width = 0; |
| |
| /* Retrieve render-target size */ |
| if (drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED) |
| { |
| getRenderTargetSize(getAmountOfDrawInstances(), &rt_width, &rt_height); |
| } |
| else |
| { |
| getRenderTargetSize(1, &rt_width, &rt_height); |
| } |
| |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| for (unsigned int n_point = 0; n_point < 8 /* points */; ++n_point) |
| { |
| /* Each point takes a 7x7 block. The test should verify that the second "nested" block |
| * is of the valid color. Blocks can be built on top of each other if instanced draw |
| * calls are used. */ |
| const unsigned char* reference_data = NULL; |
| const unsigned char* rendered_data = NULL; |
| const int row_width = rt_width * 4 /* components */; |
| const int sample_region_edge_px = 5 /* pixels */; |
| |
| for (int n_edge = 0; n_edge < 4 /* edges */; ++n_edge) |
| { |
| /* Edge 1: TL->TR |
| * Edge 2: TR->BR |
| * Edge 3: BR->BL |
| * Edge 4: BL->TL |
| */ |
| int dx = 0; |
| int dy = 0; |
| int x = 0; |
| int x_start = 0; |
| int y = 0; |
| int y_start = 0; |
| |
| switch (n_edge) |
| { |
| /* NOTE: The numbers here are as per test spec */ |
| case 0: |
| dx = 1 /* px */; |
| dy = 0 /* px */; |
| x_start = 1 /* px */; |
| y_start = 1 /* px */; |
| break; |
| case 1: |
| dx = 0 /* px */; |
| dy = 1 /* px */; |
| x_start = 5 /* px */; |
| y_start = 1 /* px */; |
| break; |
| case 2: |
| dx = -1 /* px */; |
| dy = 0 /* px */; |
| x_start = 5 /* px */; |
| y_start = 5 /* px */; |
| break; |
| case 3: |
| dx = 0 /* px */; |
| dy = -1 /* px */; |
| x_start = 1 /* px */; |
| y_start = 5 /* px */; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Invalid edge index"); |
| } |
| } /* switch (n_edge) */ |
| |
| /* What color should the pixels have? */ |
| if (drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ARRAYS || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ARRAYS_INSTANCED) |
| { |
| reference_data = ref_data + n_point * 4 /* components */; |
| x = x_start + n_point * 7 /* pixel block size */; |
| y = y_start + instance_id * 7 /* pixel block size */; |
| } |
| else |
| { |
| int index = m_unordered_elements_data[n_point]; |
| |
| reference_data = ref_data + (8 - 1 - index) * 4 /* components */; |
| x = x_start + index * 7 /* pixel block size */; |
| y = y_start + instance_id * 7 /* pixel block size */; |
| } |
| |
| /* Verify edge pixels */ |
| for (int n_pixel = 0; n_pixel < sample_region_edge_px; ++n_pixel) |
| { |
| rendered_data = data + y * row_width + x * 4 /* components */; |
| |
| if (memcmp(rendered_data, reference_data, 4 /* components */) != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "At (" << (int)x << ", " << (int)y |
| << "), " |
| "rendered data (" |
| << (int)rendered_data[0] << ", " << (int)rendered_data[1] << ", " |
| << (int)rendered_data[2] << ", " << (int)rendered_data[3] |
| << ") " |
| "is different from reference data (" |
| << (int)reference_data[0] << ", " << (int)reference_data[1] << ", " |
| << (int)reference_data[2] << ", " << (int)reference_data[3] << ")" |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failed"); |
| } /* if (data comparison failed) */ |
| |
| /* Move to next pixel */ |
| x += dx; |
| y += dy; |
| } /* for (all pixels) */ |
| } /* for (all edges) */ |
| } /* for (all points) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_LINE_STRIP: */ |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| /* For each 3px high row, we want to sample the second row. Area of a single "pixel" (incl. delta) |
| * can take no more than 5px, with the actual sampled area located in the second pixel. |
| */ |
| const int sample_region_width_px = 5; /* pixels */ |
| |
| for (int n = 0; n < 8 /* points */; ++n) |
| { |
| int x = 0; |
| int y = 0; |
| const unsigned char* reference_data = NULL; |
| const unsigned char* rendered_data = NULL; |
| |
| /* Different ordering is used for indexed draw calls */ |
| if (drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS) |
| { |
| /* For indexed calls, vertex data is laid out in a reversed ordered */ |
| int index = m_unordered_elements_data[n]; |
| |
| x = index * sample_region_width_px + 1; |
| y = instance_id * 5 + 1; /* middle row */ |
| reference_data = ref_data + ((8 - 1 - index) * 4 /* components */); |
| rendered_data = data + (y * rt_width + x) * 4 /* components */; |
| } /* if (draw call is indiced) */ |
| else |
| { |
| x = n * sample_region_width_px + 1; |
| y = instance_id * 5 + 1; /* middle row */ |
| reference_data = ref_data + (n * 4 /* components */); |
| rendered_data = data + (y * rt_width + x) * 4 /* components */; |
| } |
| |
| if (memcmp(rendered_data, reference_data, 4 /* components */) != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Reference data: [" << (int)reference_data[0] << ", " |
| << (int)reference_data[1] << ", " << (int)reference_data[2] << ", " |
| << (int)reference_data[3] << "] " |
| "for pixel at (" |
| << x << ", " << y << ") " |
| "does not match [" |
| << (int)rendered_data[0] << ", " << (int)rendered_data[1] << ", " |
| << (int)rendered_data[2] << ", " << (int)rendered_data[3] << ")."; |
| |
| TCU_FAIL("Data comparison failed."); |
| } /* if (memcmp(rendered_data, reference_data, 4) != 0) */ |
| } /* for (all points) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_POINTS: */ |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| /* A pair of adjacent triangles is contained within a 6x6 bounding box. |
| * The box is defined by top-left corner which is located at input point's |
| * location. |
| * The left triangle should only use red channel, the one on the right |
| * should only use green channel. |
| * We find centroid for each triangle, sample its color and make sure |
| * it's valid. |
| */ |
| for (int n_point = 0; n_point < 8 /* points */; ++n_point) |
| { |
| const unsigned int epsilon = 1; |
| int point_x = 0; |
| int point_y = 6 * instance_id; |
| const unsigned char* rendered_data = NULL; |
| const unsigned char* reference_data = 0; |
| const unsigned int row_width = rt_width * 4 /* components */; |
| int t1[6 /* 3 * {x, y} */] = { 0 }; |
| int t2[6 /* 3 * {x, y} */] = { 0 }; |
| int t1_center[2 /* {x, y} */] = { 0 }; |
| int t2_center[2 /* {x, y} */] = { 0 }; |
| |
| /* Different ordering is used for indexed draw calls */ |
| if (drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_ELEMENTS_INSTANCED || |
| drawcall_type == DRAW_CALL_TYPE_GL_DRAW_RANGE_ELEMENTS) |
| { |
| int index = m_unordered_elements_data[n_point]; |
| |
| point_x = 6 * index; |
| reference_data = ref_data_triangle_strip + (8 - 1 - index) * 4 /* components */; |
| } |
| else |
| { |
| point_x = 6 * n_point; |
| reference_data = ref_data_triangle_strip + n_point * 4 /* components */; |
| } |
| |
| /* Calculate triangle vertex locations (corresponds to geometry shader logic) */ |
| t1[0] = point_x; |
| t1[1] = point_y + 6; |
| t1[2] = point_x; |
| t1[3] = point_y; |
| t1[4] = point_x + 6; |
| t1[5] = point_y + 6; |
| |
| t2[0] = point_x + 6; |
| t2[1] = point_y + 6; |
| t2[2] = point_x; |
| t2[3] = point_y; |
| t2[4] = point_x + 6; |
| t2[5] = point_y; |
| |
| /* Calculate centroid locations */ |
| t1_center[0] = (t1[0] + t1[2] + t1[4]) / 3; |
| t2_center[0] = (t2[0] + t2[2] + t2[4]) / 3; |
| t1_center[1] = (t1[1] + t1[3] + t1[5]) / 3; |
| t2_center[1] = (t2[1] + t2[3] + t2[5]) / 3; |
| |
| /* Check the first triangle */ |
| point_x = t1_center[0]; |
| point_y = t1_center[1]; |
| |
| rendered_data = data + point_y * row_width + point_x * 4 /* components */; |
| |
| if ((unsigned int)de::abs((int)rendered_data[0] - reference_data[0]) > epsilon || rendered_data[1] != 0 || |
| rendered_data[2] != 0 || rendered_data[3] != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "At (" << (int)point_x << ", " << (int)point_y << ") " |
| << "rendered pixel (" << (int)rendered_data[0] << ", " << (int)rendered_data[1] |
| << ", " << (int)rendered_data[2] << ", " << (int)rendered_data[3] << ") " |
| << "is different than (" << (int)reference_data[0] << ", 0, 0, 0)." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failed."); |
| } |
| |
| /* Check the other triangle */ |
| point_x = t2_center[0]; |
| point_y = t2_center[1]; |
| |
| rendered_data = data + point_y * row_width + point_x * 4 /* components */; |
| |
| if (rendered_data[0] != 0 || (unsigned int)de::abs((int)rendered_data[1] - reference_data[1]) > epsilon || |
| rendered_data[2] != 0 || rendered_data[3] != 0) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "At (" << (int)point_x << ", " << (int)point_y << ") " |
| << "rendered pixel (" << (int)rendered_data[0] << ", " << (int)rendered_data[1] |
| << ", " << (int)rendered_data[2] << ", " << (int)rendered_data[3] << ") " |
| << "is different than (0, " << (int)reference_data[1] << ", 0, 0)." |
| << tcu::TestLog::EndMessage; |
| |
| TCU_FAIL("Data comparison failed."); |
| } |
| } /* for (all points) */ |
| |
| break; |
| } /* case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP:*/ |
| |
| default: |
| { |
| TCU_FAIL("Unsupported output layout qualifier requested."); |
| |
| break; |
| } |
| } /* switch(m_output_type) */ |
| } |
| |
| /* "lines" input primitive test implementation */ |
| /** Constructor. |
| * |
| * @param use_adjacency_data true if the test case is being instantiated for draw call modes that will |
| * features adjacency data, |
| * false otherwise. |
| * @param drawcall_mode GL draw call mode that will be used for the tests. |
| * @param output_type Shader output type that the test case is being instantiated for. |
| * @param context Rendering context; |
| * @param testContext Test context; |
| * @param name Test name. |
| **/ |
| GeometryShaderRenderingLinesCase::GeometryShaderRenderingLinesCase(Context& context, const ExtParameters& extParams, |
| const char* name, bool use_adjacency_data, |
| glw::GLenum drawcall_mode, |
| _shader_output_type output_type) |
| : GeometryShaderRenderingCase( |
| context, extParams, name, |
| "Verifies all draw calls work correctly for specific input+output+draw call mode combination") |
| , m_output_type(output_type) |
| , m_drawcall_mode(drawcall_mode) |
| , m_use_adjacency_data(use_adjacency_data) |
| , m_raw_array_instanced_data(0) |
| , m_raw_array_instanced_data_size(0) |
| , m_raw_array_noninstanced_data(0) |
| , m_raw_array_noninstanced_data_size(0) |
| , m_unordered_array_instanced_data(0) |
| , m_unordered_array_instanced_data_size(0) |
| , m_unordered_array_noninstanced_data(0) |
| , m_unordered_array_noninstanced_data_size(0) |
| , m_unordered_elements_instanced_data(0) |
| , m_unordered_elements_instanced_data_size(0) |
| , m_unordered_elements_noninstanced_data(0) |
| , m_unordered_elements_noninstanced_data_size(0) |
| , m_unordered_elements_max_index(16) /* maximum amount of vertices generated for this case */ |
| , m_unordered_elements_min_index(0) |
| { |
| /* Sanity checks */ |
| if (!m_use_adjacency_data) |
| { |
| if (drawcall_mode != GL_LINE_LOOP && drawcall_mode != GL_LINE_STRIP && drawcall_mode != GL_LINES) |
| { |
| TCU_FAIL("Only GL_LINE_LOOP or GL_LINE_STRIP or GL_LINES draw call modes are supported for 'lines' " |
| "geometry shader input layout qualifier test implementation"); |
| } |
| } |
| else |
| { |
| if (drawcall_mode != GL_LINES_ADJACENCY_EXT && drawcall_mode != GL_LINE_STRIP_ADJACENCY_EXT) |
| { |
| TCU_FAIL("Only GL_LINES_ADJACENCY_EXT or GL_LINE_STRIP_ADJACENCY_EXT draw call modes are supported for " |
| "'lines_adjacency' geometry shader input layout qualifier test implementation"); |
| } |
| } |
| |
| if (output_type != SHADER_OUTPUT_TYPE_POINTS && output_type != SHADER_OUTPUT_TYPE_LINE_STRIP && |
| output_type != SHADER_OUTPUT_TYPE_TRIANGLE_STRIP) |
| { |
| TCU_FAIL("Unsupported output layout qualifier type requested for 'lines' geometry shader input layout " |
| "qualifier test implementation"); |
| } |
| |
| /* Generate data in two flavors - one for non-instanced case, the other one for instanced case */ |
| for (int n_case = 0; n_case < 2 /* cases */; ++n_case) |
| { |
| bool is_instanced = (n_case != 0); |
| int n_instances = 0; |
| float** raw_arrays_data_ptr = NULL; |
| unsigned int* raw_arrays_data_size_ptr = NULL; |
| unsigned int rendertarget_height = 0; |
| unsigned int rendertarget_width = 0; |
| float** unordered_arrays_data_ptr = NULL; |
| unsigned int* unordered_arrays_data_size_ptr = NULL; |
| unsigned char** unordered_elements_data_ptr = NULL; |
| unsigned int* unordered_elements_data_size_ptr = NULL; |
| |
| if (!is_instanced) |
| { |
| /* Non-instanced case */ |
| n_instances = 1; |
| raw_arrays_data_ptr = &m_raw_array_noninstanced_data; |
| raw_arrays_data_size_ptr = &m_raw_array_noninstanced_data_size; |
| unordered_arrays_data_ptr = &m_unordered_array_noninstanced_data; |
| unordered_arrays_data_size_ptr = &m_unordered_array_noninstanced_data_size; |
| unordered_elements_data_ptr = &m_unordered_elements_noninstanced_data; |
| unordered_elements_data_size_ptr = &m_unordered_elements_noninstanced_data_size; |
| } |
| else |
| { |
| /* Instanced case */ |
| n_instances = getAmountOfDrawInstances(); |
| raw_arrays_data_ptr = &m_raw_array_instanced_data; |
| raw_arrays_data_size_ptr = &m_raw_array_instanced_data_size; |
| unordered_arrays_data_ptr = &m_unordered_array_instanced_data; |
| unordered_arrays_data_size_ptr = &m_unordered_array_instanced_data_size; |
| unordered_elements_data_ptr = &m_unordered_elements_instanced_data; |
| unordered_elements_data_size_ptr = &m_unordered_elements_instanced_data_size; |
| } |
| |
| getRenderTargetSize(n_instances, &rendertarget_width, &rendertarget_height); |
| |
| /* Store full-screen quad coordinates that will be used for actual array data generation. */ |
| float dx = 2.0f / float(rendertarget_width); |
| float dy = 2.0f / float(rendertarget_height); |
| |
| /* Generate raw vertex array data */ |
| |
| float* raw_array_data_traveller = NULL; |
| unsigned int single_rt_height = 0; |
| unsigned int single_rt_width = 0; |
| unsigned int whole_rt_width = 0; |
| unsigned int whole_rt_height = 0; |
| |
| switch (m_drawcall_mode) |
| { |
| case GL_LINE_LOOP: |
| { |
| *raw_arrays_data_size_ptr = 4 /* vertices making up the line strip */ * 4 /* components */ * sizeof(float); |
| |
| break; |
| } |
| |
| case GL_LINE_STRIP: |
| { |
| *raw_arrays_data_size_ptr = 5 /* vertices making up the line strip */ * 4 /* components */ * sizeof(float); |
| |
| break; |
| } |
| |
| case GL_LINE_STRIP_ADJACENCY_EXT: |
| { |
| *raw_arrays_data_size_ptr = |
| (5 /* vertices making up the line strip */ + 2 /* additional start/end adjacency vertices */) * |
| 4 /* components */ |
| * sizeof(float); |
| |
| break; |
| } |
| |
| case GL_LINES: |
| { |
| *raw_arrays_data_size_ptr = |
| 2 /* points per line segment */ * 4 /* lines */ * 4 /* components */ * sizeof(float); |
| |
| break; |
| } |
| |
| case GL_LINES_ADJACENCY_EXT: |
| { |
| *raw_arrays_data_size_ptr = |
| 4 /* points per line segment */ * 4 /* lines */ * 4 /* components */ * sizeof(float); |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (m_drawcall_mode) */ |
| |
| *raw_arrays_data_ptr = new float[*raw_arrays_data_size_ptr / sizeof(float)]; |
| raw_array_data_traveller = *raw_arrays_data_ptr; |
| |
| getRenderTargetSize(1, &single_rt_width, &single_rt_height); |
| getRenderTargetSize(getAmountOfDrawInstances(), &whole_rt_width, &whole_rt_height); |
| |
| /* Generate the data */ |
| float end_y = 0; |
| std::vector<tcu::Vec4> quad_coordinates; |
| float start_y = 0; |
| float w = 1.0f; |
| |
| if (n_instances != 1) |
| { |
| float delta = float(single_rt_height) / float(whole_rt_height); |
| |
| /* Y coordinates are calculated in a vertex shader in multi-instanced case */ |
| start_y = 0.0f; |
| end_y = 0.0f; |
| w = delta; |
| } |
| else |
| { |
| start_y = -1; |
| end_y = 1; |
| } |
| |
| /* X, Y coordinates: correspond to X & Y locations of the vertex. |
| * Z coordinates: set to 0 if the vertex is located on top edge, otherwise set to 1. |
| * W coordinate: stores the delta (single-instanced RT height / multi-instanced RT height). |
| */ |
| float dx_multiplier = 1.5f; /* Default value for lines and line_strip output layout qualifiers */ |
| float dy_multiplier = 1.5f; /* Default value for lines and line_strip output layout qualifiers */ |
| |
| if (m_output_type == SHADER_OUTPUT_TYPE_TRIANGLE_STRIP) |
| { |
| dx_multiplier = 0.0f; |
| dy_multiplier = 0.0f; |
| } |
| |
| quad_coordinates.push_back(tcu::Vec4(-1 + dx_multiplier * dx, start_y + dy_multiplier * dy, 0, w)); /* TL */ |
| quad_coordinates.push_back(tcu::Vec4(1 - dx_multiplier * dx, start_y + dy_multiplier * dy, 0, w)); /* TR */ |
| quad_coordinates.push_back(tcu::Vec4(1 - dx_multiplier * dx, end_y - dy_multiplier * dy, 1, w)); /* BR */ |
| quad_coordinates.push_back(tcu::Vec4(-1 + dx_multiplier * dx, end_y - dy_multiplier * dy, 1, w)); /* BL */ |
| |
| for (int n_line_segment = 0; n_line_segment < 4 /* edges */; ++n_line_segment) |
| { |
| /* Note we need to clamp coordinate indices here */ |
| int coordinate0_index = (4 + n_line_segment - 1) % 4; /* protect against negative modulo values */ |
| int coordinate1_index = (n_line_segment) % 4; |
| int coordinate2_index = (n_line_segment + 1) % 4; |
| int coordinate3_index = (n_line_segment + 2) % 4; |
| const tcu::Vec4& coordinate0 = quad_coordinates[coordinate0_index]; |
| const tcu::Vec4& coordinate1 = quad_coordinates[coordinate1_index]; |
| const tcu::Vec4& coordinate2 = quad_coordinates[coordinate2_index]; |
| const tcu::Vec4& coordinate3 = quad_coordinates[coordinate3_index]; |
| |
| /* For GL_LINES, we need to explicitly define start & end-points for each segment. |
| * For GL_LINE_STRIP, we only need to explicitly define first start point. Following |
| * vertices define subsequent points making up the line strip. |
| * For GL_LINE_LOOP, we need all the data we used for GL_LINE_STRIP excluding the very |
| * last vertex. |
| * |
| * For GL_LINES_ADJACENCY_EXT, we extend GL_LINES data by vertices preceding and following points |
| * that make up a single line segment. |
| * For GL_LINE_STRIP_ADJACENCY_EXT, we extend GL_LINE_STRIP data by including a vertex preceding the |
| * actual first vertex, and by including a vertex that follows the end vertex closing the line |
| * strip. |
| */ |
| |
| /* Preceding vertex */ |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT || |
| (m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT && n_line_segment == 0)) |
| { |
| *raw_array_data_traveller = coordinate0.x(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate0.y(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate0.z(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate0.w(); |
| raw_array_data_traveller++; |
| } |
| |
| /* Vertex 1 */ |
| if ((m_drawcall_mode != GL_LINE_STRIP && m_drawcall_mode != GL_LINE_STRIP_ADJACENCY_EXT && |
| m_drawcall_mode != GL_LINE_LOOP) || |
| ((m_drawcall_mode == GL_LINE_STRIP || m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT || |
| m_drawcall_mode == GL_LINE_LOOP) && |
| n_line_segment == 0)) |
| { |
| *raw_array_data_traveller = coordinate1.x(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate1.y(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate1.z(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate1.w(); |
| raw_array_data_traveller++; |
| } |
| |
| /* Vertex 2 */ |
| if (m_drawcall_mode != GL_LINE_LOOP || (m_drawcall_mode == GL_LINE_LOOP && n_line_segment != 3)) |
| { |
| *raw_array_data_traveller = coordinate2.x(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate2.y(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate2.z(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate2.w(); |
| raw_array_data_traveller++; |
| } |
| |
| /* Following vertex */ |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT || |
| (m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT && n_line_segment == 3)) |
| { |
| *raw_array_data_traveller = coordinate3.x(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate3.y(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate3.z(); |
| raw_array_data_traveller++; |
| *raw_array_data_traveller = coordinate3.w(); |
| raw_array_data_traveller++; |
| } |
| } /* for (all line segments) */ |
| |
| /* Generate unordered data: |
| * |
| * The way we organise data in this case is that: |
| * |
| * - For index data, start and end points are flipped for each line segment. |
| * - For vertex data, vertex locations are stored to correspond to this order. |
| * |
| * We *DO NOT* modify the order in which we draw the line segments, since that could make the verification |
| * process even more complex than it already is. |
| */ |
| switch (m_drawcall_mode) |
| { |
| case GL_LINE_LOOP: |
| { |
| *unordered_arrays_data_size_ptr = *raw_arrays_data_size_ptr; |
| *unordered_arrays_data_ptr = new float[*unordered_arrays_data_size_ptr / sizeof(float)]; |
| |
| *unordered_elements_data_size_ptr = sizeof(unsigned char) * 4 /* points */; |
| *unordered_elements_data_ptr = new unsigned char[*unordered_elements_data_size_ptr]; |
| |
| for (unsigned int index = 0; index < 4 /* points */; ++index) |
| { |
| /* Gives 3-{0, 1, 2, 3} */ |
| int new_index = 3 - index; |
| |
| /* Store index data */ |
| (*unordered_elements_data_ptr)[index] = (unsigned char)new_index; |
| |
| /* Store vertex data */ |
| memcpy((*unordered_arrays_data_ptr) + new_index * 4 /* components */, |
| (*raw_arrays_data_ptr) + index * 4 /* components */, sizeof(float) * 4 /* components */); |
| } /* for (all indices) */ |
| |
| break; |
| } |
| |
| case GL_LINE_STRIP: |
| { |
| *unordered_arrays_data_size_ptr = *raw_arrays_data_size_ptr; |
| *unordered_arrays_data_ptr = new float[*unordered_arrays_data_size_ptr / sizeof(float)]; |
| |
| *unordered_elements_data_size_ptr = sizeof(unsigned char) * 5 /* points */; |
| *unordered_elements_data_ptr = new unsigned char[*unordered_elements_data_size_ptr]; |
| |
| for (unsigned int index = 0; index < 5 /* points */; ++index) |
| { |
| /* Gives 4-{0, 1, 2, 3, 4} */ |
| int new_index = 4 - index; |
| |
| /* Store index data */ |
| (*unordered_elements_data_ptr)[index] = (unsigned char)new_index; |
| |
| /* Store vertex data */ |
| memcpy((*unordered_arrays_data_ptr) + new_index * 4 /* components */, |
| (*raw_arrays_data_ptr) + index * 4 /* components */, sizeof(float) * 4 /* components */); |
| } /* for (all indices) */ |
| |
| break; |
| } |
| |
| case GL_LINES: |
| { |
| *unordered_arrays_data_size_ptr = sizeof(float) * 8 /* points */ * 4 /* components */; |
| *unordered_arrays_data_ptr = new float[*unordered_arrays_data_size_ptr / sizeof(float)]; |
| |
| *unordered_elements_data_size_ptr = sizeof(unsigned char) * 8 /* points */; |
| *unordered_elements_data_ptr = new unsigned char[*unordered_elements_data_size_ptr]; |
| |
| for (unsigned int index = 0; index < 8 /* points */; ++index) |
| { |
| /* Gives 7-{(1, 0), (3, 2), (5, 4), (7, 6)} */ |
| int new_index = 7 - ((index / 2) * 2 + (index + 1) % 2); |
| |
| /* Store index data */ |
| (*unordered_elements_data_ptr)[index] = (unsigned char)new_index; |
| |
| /* Store vertex data */ |
| memcpy((*unordered_arrays_data_ptr) + new_index * 4 /* components */, |
| (*raw_arrays_data_ptr) + index * 4 /* components */, sizeof(float) * 4 /* components */); |
| } /* for (all indices) */ |
| |
| break; |
| } /* case GL_LINES: */ |
| |
| case GL_LINES_ADJACENCY_EXT: |
| case GL_LINE_STRIP_ADJACENCY_EXT: |
| { |
| /* For adjacency case, we may simplify the approach. Since the index data is now also going |
| * to include references to adjacent vertices, we can use the same ordering as in raw arrays data. |
| * Should the implementation misinterpret the data, it will treat adjacent vertex indices as actual |
| * vertex indices, breaking the verification. |
| */ |
| /* For array data, just point to unique vertex locations. Use the same order as in raw arrays data case |
| * to simplify the vertex shader for the pass. |
| **/ |
| *unordered_arrays_data_size_ptr = sizeof(float) * 4 /* points */ * 4 /* components */; |
| *unordered_arrays_data_ptr = new float[*unordered_arrays_data_size_ptr / sizeof(float)]; |
| |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT) |
| { |
| *unordered_elements_data_size_ptr = |
| sizeof(unsigned char) * 4 /* vertices per line segment */ * 4 /* line segments */; |
| } |
| else |
| { |
| *unordered_elements_data_size_ptr = |
| sizeof(unsigned char) * (5 /* vertices making up a line strip */ + 2 /* start/end vertices */); |
| } |
| |
| *unordered_elements_data_ptr = new unsigned char[*unordered_elements_data_size_ptr]; |
| |
| for (int n = 0; n < 4; ++n) |
| { |
| (*unordered_arrays_data_ptr)[4 * n + 0] = quad_coordinates[n].x(); |
| (*unordered_arrays_data_ptr)[4 * n + 1] = quad_coordinates[n].y(); |
| (*unordered_arrays_data_ptr)[4 * n + 2] = quad_coordinates[n].z(); |
| (*unordered_arrays_data_ptr)[4 * n + 3] = quad_coordinates[n].w(); |
| } |
| |
| /* For elements data, we just walk over the quad and make sure we turn a full circle */ |
| unsigned char* elements_data_traveller_ptr = *unordered_elements_data_ptr; |
| |
| for (int n = 0; n < 4; ++n) |
| { |
| int component0_index = (n + 4 - 1) % 4; /* protect against underflow */ |
| int component1_index = (n) % 4; |
| int component2_index = (n + 1) % 4; |
| int component3_index = (n + 2) % 4; |
| |
| if (m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) |
| { |
| /* Vertex adjacent to start vertex - include only at start */ |
| if (n == 0) |
| { |
| *elements_data_traveller_ptr = (unsigned char)component0_index; |
| |
| ++elements_data_traveller_ptr; |
| } |
| |
| /* Vertex index */ |
| *elements_data_traveller_ptr = (unsigned char)component1_index; |
| |
| ++elements_data_traveller_ptr; |
| |
| /* End vertex and the adjacent vertex - include only for final iteration */ |
| if (n == 3) |
| { |
| /* End vertex */ |
| *elements_data_traveller_ptr = (unsigned char)component2_index; |
| |
| ++elements_data_traveller_ptr; |
| |
| /* Adjacent vertex */ |
| *elements_data_traveller_ptr = (unsigned char)component3_index; |
| |
| ++elements_data_traveller_ptr; |
| } |
| } |
| else |
| { |
| /* GL_LINES_ADJACENCY_EXT */ |
| *elements_data_traveller_ptr = (unsigned char)component0_index; |
| ++elements_data_traveller_ptr; |
| *elements_data_traveller_ptr = (unsigned char)component1_index; |
| ++elements_data_traveller_ptr; |
| *elements_data_traveller_ptr = (unsigned char)component2_index; |
| ++elements_data_traveller_ptr; |
| *elements_data_traveller_ptr = (unsigned char)component3_index; |
| ++elements_data_traveller_ptr; |
| } |
| } |
| |
| break; |
| } /* case GL_LINES: */ |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (m_drawcall_mode) */ |
| } /* for (both cases) */ |
| } |
| |
| /** Destructor. */ |
| GeometryShaderRenderingLinesCase::~GeometryShaderRenderingLinesCase() |
| { |
| if (m_raw_array_instanced_data != NULL) |
| { |
| delete[] m_raw_array_instanced_data; |
| |
| m_raw_array_instanced_data = NULL; |
| } |
| |
| if (m_raw_array_noninstanced_data != NULL) |
| { |
| delete[] m_raw_array_noninstanced_data; |
| |
| m_raw_array_noninstanced_data = NULL; |
| } |
| |
| if (m_unordered_array_instanced_data != NULL) |
| { |
| delete[] m_unordered_array_instanced_data; |
| |
| m_unordered_array_instanced_data = NULL; |
| } |
| |
| if (m_unordered_array_noninstanced_data != NULL) |
| { |
| delete[] m_unordered_array_noninstanced_data; |
| |
| m_unordered_array_noninstanced_data = NULL; |
| } |
| |
| if (m_unordered_elements_instanced_data != NULL) |
| { |
| delete[] m_unordered_elements_instanced_data; |
| |
| m_unordered_elements_instanced_data = NULL; |
| } |
| |
| if (m_unordered_elements_noninstanced_data != NULL) |
| { |
| delete[] m_unordered_elements_noninstanced_data; |
| |
| m_unordered_elements_noninstanced_data = NULL; |
| } |
| } |
| |
| /** Retrieves amount of instances that should be drawn with glDraw*Elements() calls. |
| * |
| * @return As per description. |
| **/ |
| unsigned int GeometryShaderRenderingLinesCase::getAmountOfDrawInstances() |
| { |
| return 4; |
| } |
| |
| /** Retrieves amount of indices that should be used for rendering a single instance |
| * (glDraw*Elements() calls only) |
| * |
| * @return As per description. |
| */ |
| unsigned int GeometryShaderRenderingLinesCase::getAmountOfElementsPerInstance() |
| { |
| unsigned int result = 0; |
| |
| switch (m_drawcall_mode) |
| { |
| case GL_LINE_LOOP: |
| result = 4; |
| break; |
| case GL_LINE_STRIP: |
| result = 5; |
| break; |
| case GL_LINE_STRIP_ADJACENCY_EXT: |
| result = 7; |
| break; |
| case GL_LINES: |
| result = 8; |
| break; |
| case GL_LINES_ADJACENCY_EXT: |
| result = 16; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (m_drawcall_mode) */ |
| |
| return result; |
| } |
| |
| /** Retrieves amount of vertices that should be used for rendering a single instance |
| * (glDrawArrays*() calls only) |
| * |
| * @return As per description. |
| **/ |
| unsigned int GeometryShaderRenderingLinesCase::getAmountOfVerticesPerInstance() |
| { |
| unsigned int result = 0; |
| |
| switch (m_drawcall_mode) |
| { |
| case GL_LINE_LOOP: |
| result = 4; |
| break; |
| case GL_LINE_STRIP: |
| result = 5; |
| break; |
| case GL_LINE_STRIP_ADJACENCY_EXT: |
| result = 7; |
| break; |
| case GL_LINES: |
| result = 8; |
| break; |
| case GL_LINES_ADJACENCY_EXT: |
| result = 16; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| } /* switch (m_drawcall_mode) */ |
| |
| return result; |
| } |
| |
| /** Draw call mode that should be used glDraw*() calls. |
| * |
| * @return As per description. |
| **/ |
| glw::GLenum GeometryShaderRenderingLinesCase::getDrawCallMode() |
| { |
| return m_drawcall_mode; |
| } |
| |
| /** Source code for a fragment shader that should be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingLinesCase::getFragmentShaderCode() |
| { |
| static std::string fs_code = "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in vec4 gs_fs_color;\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = gs_fs_color;\n" |
| "}\n"; |
| |
| return fs_code; |
| } |
| |
| /** Source code for a geometry shader that should be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingLinesCase::getGeometryShaderCode() |
| { |
| static const char* lines_in_line_strip_out_gs_code_preamble = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines) in;\n" |
| "layout(line_strip, max_vertices=6) out;\n" |
| "\n" |
| "#define N_VERTICES_IN (2)\n" |
| "#define N_VERTEX0 (0)\n" |
| "#define N_VERTEX1 (1)\n" |
| "\n"; |
| |
| static const char* lines_adjacency_in_line_strip_out_gs_code_preamble = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines_adjacency) in;\n" |
| "layout(line_strip, max_vertices=6) out;\n" |
| "\n" |
| "#define N_VERTICES_IN (4)\n" |
| "#define N_VERTEX0 (1)\n" |
| "#define N_VERTEX1 (2)\n" |
| "\n"; |
| |
| static const char* lines_gs_code_main = "\n" |
| "in vec4 vs_gs_color[N_VERTICES_IN];\n" |
| "out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " float dx = float(2.0) / float(renderingTargetSize.x);\n" |
| " float dy = float(2.0) / float(renderingTargetSize.y);\n" |
| "\n" |
| " vec4 start_pos = gl_in[N_VERTEX0].gl_Position;\n" |
| " vec4 end_pos = gl_in[N_VERTEX1].gl_Position;\n" |
| " vec4 start_col = vs_gs_color[N_VERTEX0];\n" |
| " vec4 end_col = vs_gs_color[N_VERTEX1];\n" |
| "\n" |
| /* Determine if this is a horizontal or vertical edge */ |
| " if (start_pos.x != end_pos.x)\n" |
| " {\n" |
| /* Bottom line segment */ |
| " gl_Position = vec4(-1.0, start_pos.y + dy, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(1.0, end_pos.y + dy, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| /* Middle line segment */ |
| " gl_Position = vec4(-1.0, start_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(1.0, end_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| /* Top line segment */ |
| " gl_Position = vec4(-1.0, start_pos.y - dy, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(1.0, end_pos.y - dy, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| /* Left line segment */ |
| " gl_Position = vec4(start_pos.x - dx, start_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(end_pos.x - dx, end_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| /* Middle line segment */ |
| " gl_Position = vec4(start_pos.x, start_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(end_pos.x, end_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| /* Right line segment */ |
| " gl_Position = vec4(start_pos.x + dx, start_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = vec4(end_pos.x + dx, end_pos.y, 0, 1);\n" |
| " gs_fs_color = mix(start_col, end_col, 0.5);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| " }\n" |
| "}\n"; |
| |
| static const char* lines_in_points_out_gs_code_preamble = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines) in;\n" |
| "layout(points, max_vertices=72) out;\n" |
| "\n" |
| "#define N_VERTEX0 (0)\n" |
| "#define N_VERTEX1 (1)\n" |
| "#define N_VERTICES_IN (2)\n" |
| "\n"; |
| |
| static const char* lines_adjacency_in_points_out_gs_code_preamble = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines_adjacency) in;\n" |
| "layout(points, max_vertices=72) out;\n" |
| "\n" |
| "#define N_VERTEX0 (1)\n" |
| "#define N_VERTEX1 (2)\n" |
| "#define N_VERTICES_IN (4)\n" |
| "\n"; |
| |
| static const char* points_gs_code_main = "\n" |
| "in vec4 vs_gs_color[N_VERTICES_IN];\n" |
| "out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " float dx = float(2.0) / float(renderingTargetSize.x);\n" |
| " float dy = float(2.0) / float(renderingTargetSize.y);\n" |
| "\n" |
| " vec4 start_pos = gl_in[N_VERTEX0].gl_Position;\n" |
| " vec4 end_pos = gl_in[N_VERTEX1].gl_Position;\n" |
| " vec4 start_col = vs_gs_color[N_VERTEX0];\n" |
| " vec4 end_col = vs_gs_color[N_VERTEX1];\n" |
| " vec4 delta_col = (end_col - start_col) / vec4(7.0);\n" |
| " vec4 delta_pos = (end_pos - start_pos) / vec4(7.0);\n" |
| "\n" |
| " for (int n_point = 0; n_point < 8; ++n_point)\n" |
| " {\n" |
| " vec4 ref_color = start_col + vec4(float(n_point)) * delta_col;\n" |
| " vec4 ref_pos = start_pos + vec4(float(n_point)) * delta_pos;\n" |
| "\n" |
| /* TL */ |
| " gl_Position = ref_pos + vec4(-dx, -dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* TM */ |
| " gl_Position = ref_pos + vec4(0, -dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* TR */ |
| " gl_Position = ref_pos + vec4(dx, -dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* ML */ |
| " gl_Position = ref_pos + vec4(-dx, 0, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* MM */ |
| " gl_Position = ref_pos + vec4(0, 0, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* MR */ |
| " gl_Position = ref_pos + vec4(dx, 0, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* BL */ |
| " gl_Position = ref_pos + vec4(-dx, dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* BM */ |
| " gl_Position = ref_pos + vec4(0, dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| /* BR */ |
| " gl_Position = ref_pos + vec4(dx, dy, 0, 0);\n" |
| " gs_fs_color = ref_color;\n" |
| " EmitVertex();\n" |
| " }\n" |
| "}\n"; |
| |
| static const char* lines_adjacency_in_triangle_strip_out_gs_code_preamble = |
| "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines_adjacency) in;\n" |
| "layout(triangle_strip, max_vertices=3) out;\n" |
| "\n" |
| "#define N_VERTEX0 (1)\n" |
| "#define N_VERTEX1 (2)\n" |
| "#define N_VERTICES_IN (4)\n"; |
| |
| static const char* lines_in_triangle_strip_out_gs_code_preamble = "${VERSION}\n" |
| "\n" |
| "${GEOMETRY_SHADER_ENABLE}\n" |
| "\n" |
| "layout(lines) in;\n" |
| "layout(triangle_strip, max_vertices=3) out;\n" |
| "\n" |
| "#define N_VERTEX0 (0)\n" |
| "#define N_VERTEX1 (1)\n" |
| "#define N_VERTICES_IN (2)\n"; |
| |
| static const char* triangles_gs_code_main = "flat in int instance_id[N_VERTICES_IN];\n" |
| " in vec4 vs_gs_color[N_VERTICES_IN];\n" |
| " out vec4 gs_fs_color;\n" |
| "\n" |
| "uniform ivec2 renderingTargetSize;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " float dx = float(1.5) / float(renderingTargetSize.x);\n" |
| " float dy = float(1.5) / float(renderingTargetSize.y);\n" |
| "\n" |
| " gl_Position = gl_in[N_VERTEX0].gl_Position;\n" |
| " gs_fs_color = vs_gs_color[N_VERTEX0];\n" |
| " EmitVertex();\n" |
| "\n" |
| " gl_Position = gl_in[N_VERTEX1].gl_Position;\n" |
| " gs_fs_color = vs_gs_color[N_VERTEX0];\n" |
| " EmitVertex();\n" |
| "\n" |
| " if (renderingTargetSize.y == 45 /* block size */)\n" |
| " {\n" |
| " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| /* Each block takes 1/4th of the total render target. |
| * Third vertex should be placed in the middle of the block. |
| */ |
| " float y = -1.0 + 1.0 / 4.0 + float(instance_id[0]) * 0.5;\n" |
| "\n" |
| " gl_Position = vec4(0.0, y, 0.0, 1.0);\n" |
| " }\n" |
| "\n" |
| " gs_fs_color = vs_gs_color[N_VERTEX0];\n" |
| " EmitVertex();\n" |
| "\n" |
| " EndPrimitive();\n" |
| "}\n"; |
| std::string result; |
| |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| { |
| std::stringstream lines_adjacency_gs_code_stringstream; |
| std::string lines_adjacency_gs_code_string; |
| std::stringstream lines_gs_code_stringstream; |
| std::string lines_gs_code_string; |
| |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT || m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) |
| { |
| /* First request for lines_adjacency GS, form the string */ |
| lines_adjacency_gs_code_stringstream << lines_adjacency_in_line_strip_out_gs_code_preamble |
| << lines_gs_code_main; |
| |
| lines_adjacency_gs_code_string = lines_adjacency_gs_code_stringstream.str(); |
| result = lines_adjacency_gs_code_string; |
| } |
| else if (m_drawcall_mode == GL_LINES || m_drawcall_mode == GL_LINE_LOOP || m_drawcall_mode == GL_LINE_STRIP) |
| { |
| /* First request for lines GS, form the string */ |
| lines_gs_code_stringstream << lines_in_line_strip_out_gs_code_preamble << lines_gs_code_main; |
| |
| lines_gs_code_string = lines_gs_code_stringstream.str(); |
| result = lines_gs_code_string; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_POINTS: |
| { |
| std::stringstream lines_adjacency_gs_code_stringstream; |
| std::string lines_adjacency_gs_code_string; |
| std::stringstream lines_gs_code_stringstream; |
| std::string lines_gs_code_string; |
| |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT || m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) |
| { |
| /* First request for lines_adjacency GS, form the string */ |
| lines_adjacency_gs_code_stringstream << lines_adjacency_in_points_out_gs_code_preamble |
| << points_gs_code_main; |
| |
| lines_adjacency_gs_code_string = lines_adjacency_gs_code_stringstream.str(); |
| result = lines_adjacency_gs_code_string; |
| } |
| else if (m_drawcall_mode == GL_LINES || m_drawcall_mode == GL_LINE_LOOP || m_drawcall_mode == GL_LINE_STRIP) |
| { |
| /* First request for lines GS, form the string */ |
| lines_gs_code_stringstream << lines_in_points_out_gs_code_preamble << points_gs_code_main; |
| |
| lines_gs_code_string = lines_gs_code_stringstream.str(); |
| result = lines_gs_code_string; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } |
| |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| std::stringstream lines_adjacency_gs_code_stringstream; |
| std::string lines_adjacency_gs_code_string; |
| std::stringstream lines_gs_code_stringstream; |
| std::string lines_gs_code_string; |
| |
| if (m_drawcall_mode == GL_LINES_ADJACENCY_EXT || m_drawcall_mode == GL_LINE_STRIP_ADJACENCY_EXT) |
| { |
| /* First request for lines_adjacency GS, form the string */ |
| lines_adjacency_gs_code_stringstream << lines_adjacency_in_triangle_strip_out_gs_code_preamble |
| << triangles_gs_code_main; |
| |
| lines_adjacency_gs_code_string = lines_adjacency_gs_code_stringstream.str(); |
| result = lines_adjacency_gs_code_string; |
| } |
| else if (m_drawcall_mode == GL_LINES || m_drawcall_mode == GL_LINE_LOOP || m_drawcall_mode == GL_LINE_STRIP) |
| { |
| /* First request for lines GS, form the string */ |
| lines_gs_code_stringstream << lines_in_triangle_strip_out_gs_code_preamble << triangles_gs_code_main; |
| |
| lines_gs_code_string = lines_gs_code_stringstream.str(); |
| result = lines_gs_code_string; |
| } |
| else |
| { |
| TCU_FAIL("Unrecognized draw call mode"); |
| } |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Requested shader output layout qualifier is unsupported"); |
| } |
| } /* switch (m_output_type) */ |
| |
| return result; |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * vertex data to be used for glDrawArrays*() calls. |
| * |
| * @param instanced True if the data is to be used in regard to instanced draw calls, |
| * false otherwise. |
| * |
| * @return As per description. |
| **/ |
| glw::GLuint GeometryShaderRenderingLinesCase::getRawArraysDataBufferSize(bool instanced) |
| { |
| return instanced ? m_raw_array_instanced_data_size : m_raw_array_noninstanced_data_size; |
| } |
| |
| /** Returns vertex data for the test. Only to be used for glDrawArrays*() calls. |
| * |
| * @param instanced True if the data is to be used in regard to instanced draw calls, |
| * false otherwise. |
| * |
| * @return As per description. |
| **/ |
| const void* GeometryShaderRenderingLinesCase::getRawArraysDataBuffer(bool instanced) |
| { |
| return instanced ? m_raw_array_instanced_data : m_raw_array_noninstanced_data; |
| } |
| |
| /** Retrieves resolution of off-screen rendering buffer that should be used for the test. |
| * |
| * @param n_instances Amount of draw call instances this render target will be used for. |
| * @param out_width Deref will be used to store rendertarget's width. Must not be NULL. |
| * @param out_height Deref will be used to store rendertarget's height. Must not be NULL. |
| **/ |
| void GeometryShaderRenderingLinesCase::getRenderTargetSize(unsigned int n_instances, unsigned int* out_width, |
| unsigned int* out_height) |
| { |
| switch (m_output_type) |
| { |
| case SHADER_OUTPUT_TYPE_LINE_STRIP: |
| case SHADER_OUTPUT_TYPE_POINTS: |
| case SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| { |
| /* For SHADER_OUTPUT_TYPE_POINTS: |
| * An edge size of 45px should be used. Given that each input will generate a 3x3 block, |
| * this should give us a delta of 3px between the "quads". |
| * |
| * For instanced draw calls, use a delta of 3px as well. |
| * |
| * For SHADER_OUTPUT_TYPE_LINE_STRIP: |
| * Each rectangle outline will take a 45x45 block. No vertical delta needs to be used. |
| * |
| * For SHADER_OUTPUT_TYPE_TRIANGLE_STRIP: |
| * Each combination of 4 triangles makes up a triangles that takes 45x45 area. |
| * No vertical delta needs to be used. |
| */ |
| *out_width = 3 /* 'pixel' size */ * 8 + 3 /* Delta size */ * 7; |
| *out_height = (3 /* 'pixel' size */ * 8 + 3 /* Delta size */ * 7) * n_instances; |
| |
| break; |
| } |
| |
| default: |
| { |
| TCU_FAIL("Unsupported shader output type"); |
| } |
| } /* switch (m_output_type) */ |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * vertex data to be used for glDrawElements*() calls. |
| * |
| * @param instanced true if the call is being made for an instanced draw call, false otherwise. |
| * |
| * @return As per description. |
| **/ |
| glw::GLuint GeometryShaderRenderingLinesCase::getUnorderedArraysDataBufferSize(bool instanced) |
| { |
| return (instanced) ? m_unordered_array_instanced_data_size : m_unordered_array_noninstanced_data_size; |
| } |
| |
| /** Returns vertex data for the test. Only to be used for glDrawElements*() calls. |
| * |
| * @param instanced true if the call is being made for an instanced draw call, false otherwise. |
| * |
| * @return As per description. |
| **/ |
| const void* GeometryShaderRenderingLinesCase::getUnorderedArraysDataBuffer(bool instanced) |
| { |
| return instanced ? m_unordered_array_instanced_data : m_unordered_array_noninstanced_data; |
| } |
| |
| /** Returns amount of bytes that should be allocated for a buffer object to hold |
| * index data to be used for glDrawElements*() calls. |
| * |
| * @param instanced true if the call is being made for an instanced draw call, false otherwise. |
| * |
| * @return As per description. |
| **/ |
| glw::GLuint GeometryShaderRenderingLinesCase::getUnorderedElementsDataBufferSize(bool instanced) |
| { |
| return instanced ? m_unordered_elements_instanced_data_size : m_unordered_elements_noninstanced_data_size; |
| } |
| |
| /** Returns index data for the test. Only to be used for glDrawElements*() calls. |
| * |
| * @param instanced true if the call is being made for an instanced draw call, false otherwise. |
| * |
| **/ |
| const void* GeometryShaderRenderingLinesCase::getUnorderedElementsDataBuffer(bool instanced) |
| { |
| return instanced ? m_unordered_elements_instanced_data : m_unordered_elements_noninstanced_data; |
| } |
| |
| /** Returns type of the index, to be used for glDrawElements*() calls. |
| * |
| * @return As per description. |
| **/ |
| glw::GLenum GeometryShaderRenderingLinesCase::getUnorderedElementsDataType() |
| { |
| return GL_UNSIGNED_BYTE; |
| } |
| |
| /** Retrieves maximum index value. To be used for glDrawRangeElements() test only. |
| * |
| * @return As per description. |
| **/ |
| glw::GLubyte GeometryShaderRenderingLinesCase::getUnorderedElementsMaxIndex() |
| { |
| return m_unordered_elements_max_index; |
| } |
| |
| /** Retrieves minimum index value. To be used for glDrawRangeElements() test only. |
| * |
| * @return As per description. |
| **/ |
| glw::GLubyte GeometryShaderRenderingLinesCase::getUnorderedElementsMinIndex() |
| { |
| return m_unordered_elements_min_index; |
| } |
| |
| /** Retrieves vertex shader code to be used for the test. |
| * |
| * @return As per description. |
| **/ |
| std::string GeometryShaderRenderingLinesCase::getVertexShaderCode() |
| { |
| static std::string vs_code = |
| "${VERSION}\n" |
| "\n" |
| " in vec4 position;\n" |
| " uniform bool is_indexed_draw_call;\n" |
| " uniform bool is_gl_lines_adjacency_draw_call;\n" |
| " uniform bool is_gl_line_strip_adjacency_draw_call;\n" |
| " uniform bool is_gl_lines_draw_call;\n" |
| " uniform bool is_gl_line_loop_draw_call;\n" |
| " uniform ivec2 renderingTargetSize;\n" |
| "flat out int instance_id;\n" |
| " out vec4 vs_gs_color;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " instance_id = gl_InstanceID;\n" |
| "\n" |
| /* non-instanced */ |
| " if (renderingTargetSize.y == 45 /* block size */)\n" |
| " {\n" |
| " gl_Position = position;\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " bool represents_top_edge = (position.z == 0.0);\n" |
| " float delta = position.w;\n" |
| " float y = 0.0;\n" |
| "\n" |
| " if (represents_top_edge)\n" |
| " {\n" |
| /* top vertices */ |
| " y = position.y + float(gl_InstanceID) * delta * 2.0 - 1.0;\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " y = position.y + float(gl_InstanceID) * delta * 2.0 - 1.0 + delta * 2.0;\n" |
| /* bottom vertices */ |
| " }\n" |
| "\n" |
| " gl_Position = vec4(position.x,\n" |
| " y,\n" |
| " position.z,\n" |
| " 1.0);\n" |
| " }\n" |
| "\n" |
| " vs_gs_color = vec4(0, 0, 0, 0);\n" |
| "\n" |
| " if (is_gl_line_loop_draw_call)\n" |
| " {\n" |
| /* GL_LINE_LOOP */ |
| " if (!is_indexed_draw_call)\n" |
| " {\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 0: vs_gs_color = vec4(1, 0, 0, 0); break;\n" |
| " case 1: vs_gs_color = vec4(0, 1, 0, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0, 0, 1, 0); break;\n" |
| " case 3: vs_gs_color = vec4(0, 0, 0, 1); break;\n" |
| " }\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 3: vs_gs_color = vec4(1, 0, 0, 0); break;\n" |
| " case 0: vs_gs_color = vec4(0, 0, 0, 1); break;\n" |
| " case 1: vs_gs_color = vec4(0, 0, 1, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0, 1, 0, 0); break;\n" |
| " }\n" |
| " }\n" |
| " }\n" |
| " else\n" |
| " if (is_gl_line_strip_adjacency_draw_call)\n" |
| " {\n" |
| /* GL_LINE_STRIP_ADJACENCY_EXT */ |
| " if (!is_indexed_draw_call)\n" |
| " {\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 1:\n" |
| " case 5: vs_gs_color = vec4(1, 0, 0, 0); break;\n" |
| " case 2: vs_gs_color = vec4(0, 1, 0, 0); break;\n" |
| " case 3: vs_gs_color = vec4(0, 0, 1, 0); break;\n" |
| " case 0:\n" |
| " case 4: vs_gs_color = vec4(0, 0, 0, 1); break;\n" |
| " }\n" |
| " }\n" |
| " else\n" |
|