| /*------------------------------------------------------------------------- |
| * 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 "esextcTessellationShaderMaxPatchVertices.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| #include <cstddef> |
| #include <cstdlib> |
| |
| /* The test creates a patch with max patch vertices count size. |
| * The output from the tesselation stage is a single segment (2 vertices). |
| * Use this define when allocating/using the output TF buffer. |
| */ |
| #define OUTPUT_VERTEX_COUNT 2 |
| |
| namespace glcts |
| { |
| |
| /* Vertex Shader code */ |
| const char* TessellationShaderMaxPatchVertices::m_vs_code = "${VERSION}\n" |
| "\n" |
| "${SHADER_IO_BLOCKS_ENABLE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "layout(location = 0) in vec4 in_fv;\n" |
| "layout(location = 1) in ivec4 in_iv;\n" |
| "\n" |
| "out Vertex\n" |
| "{\n" |
| " ivec4 iv;\n" |
| " vec4 fv;\n" |
| "} outVertex;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = in_fv;\n" |
| " outVertex.iv = in_iv;\n" |
| " outVertex.fv = in_fv;\n" |
| "}\n"; |
| |
| /* Tessellation Control Shader code (for case with explicit array size) */ |
| const char* TessellationShaderMaxPatchVertices::m_tc_code = |
| "${VERSION}\n" |
| "\n" |
| "${TESSELLATION_SHADER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in Vertex\n" |
| "{\n" |
| " ivec4 iv;\n" |
| " vec4 fv;\n" |
| "} inVertex[];\n" |
| "\n" |
| "layout(vertices = 2) out;\n" /* One segment only. */ |
| "\n" |
| "out Vertex\n" |
| "{\n" |
| " ivec4 iv;\n" |
| " vec4 fv;\n" |
| "} outVertex[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" |
| " outVertex[gl_InvocationID].iv = ivec4(0);\n" |
| " outVertex[gl_InvocationID].fv = vec4(0);\n" |
| "\n" |
| " for (int i = 0; i < gl_PatchVerticesIn; i++)\n" |
| " {\n" |
| " outVertex[gl_InvocationID].iv += inVertex[i].iv;\n" |
| " outVertex[gl_InvocationID].fv += inVertex[i].fv;\n" |
| " }\n" |
| "\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| "}\n"; |
| |
| /* Tessellation Evaluation Shader code (for case */ |
| const char* TessellationShaderMaxPatchVertices::m_te_code = "${VERSION}\n" |
| "\n" |
| "${TESSELLATION_SHADER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "layout (isolines, point_mode) in;\n" |
| "\n" |
| "in Vertex\n" |
| "{\n" |
| " ivec4 iv;\n" |
| " vec4 fv;\n" |
| "} inVertex[];\n" |
| "\n" |
| "out vec4 result_fv;\n" |
| "out ivec4 result_iv;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| " result_iv = ivec4(0);\n" |
| " result_fv = vec4(0.0);\n" |
| "\n" |
| " for (int i = 0 ; i < gl_PatchVerticesIn; i++)\n" |
| " {\n" |
| " result_iv += inVertex[i].iv;\n" |
| " result_fv += inVertex[i].fv;\n" |
| " }\n" |
| "}\n"; |
| |
| /* Fragment Shader code */ |
| const char* TessellationShaderMaxPatchVertices::m_fs_code = "${VERSION}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| /* Transform Feedback varyings */ |
| const char* const TessellationShaderMaxPatchVertices::m_tf_varyings[] = { "result_fv", "result_iv" }; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TessellationShaderMaxPatchVertices::TessellationShaderMaxPatchVertices(Context& context, const ExtParameters& extParams) |
| : TestCaseBase(context, extParams, "max_patch_vertices", |
| "Make sure it is possible to use up to gl_MaxPatchVertices vertices." |
| " TCS must be able to correctly access all vertices in an input patch") |
| , m_bo_id_f_1(0) |
| , m_bo_id_f_2(0) |
| , m_bo_id_i_1(0) |
| , m_bo_id_i_2(0) |
| , m_fs_id(0) |
| , m_po_id_1(0) |
| , m_po_id_2(0) |
| , m_tc_id(0) |
| , m_te_id(0) |
| , m_tf_id_1(0) |
| , m_tf_id_2(0) |
| , m_vs_id(0) |
| , m_vao_id(0) |
| , m_gl_max_patch_vertices(0) |
| , m_patch_vertices_bo_f_id(0) |
| , m_patch_vertices_bo_i_id(0) |
| , m_patch_vertices_f(DE_NULL) |
| , m_patch_vertices_i(DE_NULL) |
| { |
| } |
| |
| /** Deinitializes all ES objects created for the test. */ |
| void TessellationShaderMaxPatchVertices::deinit(void) |
| { |
| /* Deinitialize parent. */ |
| TestCaseBase::deinit(); |
| |
| if (!m_is_tessellation_shader_supported) |
| { |
| return; |
| } |
| |
| /* Dealocate input array of patch vertices. */ |
| if (m_patch_vertices_f != DE_NULL) |
| { |
| free(m_patch_vertices_f); |
| |
| m_patch_vertices_f = DE_NULL; |
| } |
| |
| if (m_patch_vertices_i != DE_NULL) |
| { |
| free(m_patch_vertices_i); |
| |
| m_patch_vertices_i = DE_NULL; |
| } |
| |
| /* Retrieve ES entry-points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Set back to default program */ |
| gl.useProgram(0); |
| |
| /* Revert GL_PATCH_VERTICES_EXT value to the default setting */ |
| gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3); |
| |
| if (!glu::isContextTypeES(m_context.getRenderContext().getType())) |
| { |
| /* Revert GL_PATCH_DEFAULT_INNER_LEVEL and GL_PATCH_DEFAULT_OUTER_LEVEL pname |
| * values to the default settings */ |
| const float default_levels[] = { 1.0f, 1.0f, 1.0f, 1.0f }; |
| |
| gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, default_levels); |
| gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, default_levels); |
| } |
| |
| /* Disable vertex attribute arrays that may have been enabled for the test */ |
| gl.disableVertexAttribArray(0); |
| gl.disableVertexAttribArray(1); |
| |
| /* Unbind buffer objects from TF binding points */ |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */); |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */); |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1 /* index */, 0 /* buffer */); |
| |
| /* Unbind transform feedback object */ |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0 /* id */); |
| |
| /* Disable GL_RASTERIZER_DISCARD mode */ |
| gl.disable(GL_RASTERIZER_DISCARD); |
| |
| /* Unbind vertex array object */ |
| gl.bindVertexArray(0); |
| |
| /* Delete OpenGL objects */ |
| if (m_bo_id_f_1 != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id_f_1); |
| |
| m_bo_id_f_1 = 0; |
| } |
| |
| if (m_bo_id_f_2 != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id_f_2); |
| |
| m_bo_id_f_2 = 0; |
| } |
| |
| if (m_bo_id_i_1 != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id_i_1); |
| |
| m_bo_id_i_1 = 0; |
| } |
| |
| if (m_bo_id_i_2 != 0) |
| { |
| gl.deleteBuffers(1, &m_bo_id_i_2); |
| |
| m_bo_id_i_2 = 0; |
| } |
| |
| if (m_patch_vertices_bo_f_id != 0) |
| { |
| gl.deleteBuffers(1, &m_patch_vertices_bo_f_id); |
| |
| m_patch_vertices_bo_f_id = 0; |
| } |
| |
| if (m_patch_vertices_bo_i_id != 0) |
| { |
| gl.deleteBuffers(1, &m_patch_vertices_bo_i_id); |
| |
| m_patch_vertices_bo_i_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| |
| if (m_tc_id != 0) |
| { |
| gl.deleteShader(m_tc_id); |
| |
| m_tc_id = 0; |
| } |
| |
| if (m_te_id != 0) |
| { |
| gl.deleteShader(m_te_id); |
| |
| m_te_id = 0; |
| } |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| |
| m_fs_id = 0; |
| } |
| |
| if (m_tf_id_1 != 0) |
| { |
| gl.deleteTransformFeedbacks(1, &m_tf_id_1); |
| |
| m_tf_id_1 = 0; |
| } |
| |
| if (m_tf_id_2 != 0) |
| { |
| gl.deleteTransformFeedbacks(1, &m_tf_id_2); |
| |
| m_tf_id_2 = 0; |
| } |
| |
| if (m_po_id_1 != 0) |
| { |
| gl.deleteProgram(m_po_id_1); |
| |
| m_po_id_1 = 0; |
| } |
| |
| if (m_po_id_2 != 0) |
| { |
| gl.deleteProgram(m_po_id_2); |
| |
| m_po_id_2 = 0; |
| } |
| |
| if (m_vao_id != 0) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| |
| m_vao_id = 0; |
| } |
| } |
| |
| /** Initializes all ES objects and reference values for the test. */ |
| void TessellationShaderMaxPatchVertices::initTest(void) |
| { |
| /* This test runs for two cases: |
| * |
| * 1) The patch size is explicitly defined to be equal to gl_MaxPatchVertices. |
| * (The Tessellation Control Shader gets 32 vertices, then it access them |
| * and it outputs 2 vertices to Tessllation Evaluation Shader. Next Tessllation |
| * Evaluation Shader sends 1 segment of an isoline to the output). |
| * 2) The patch size is implicitly defined to be equal to gl_MaxPatchVertices. |
| * (There is no Tessellation Control Shader. Tessllation Evaluation Shader |
| * gets 32 vertices, then it access them. Next (gl_MaxPatchVertices-1) segments |
| * of the isoline are send to the output.) |
| */ |
| |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Initialize vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); |
| |
| /* Query GL_MAX_PATCH_VERTICES_EXT value */ |
| gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &m_gl_max_patch_vertices); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_PATCH_VERTICES_EXT pname!"); |
| |
| /* Set maximum number of vertices in the patch. */ |
| gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, m_gl_max_patch_vertices); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname!"); |
| |
| /* Build programs */ |
| initProgramObjects(); |
| |
| /* Initialize tessellation buffers */ |
| initTransformFeedbackBufferObjects(); |
| |
| /* Initialize input vertices */ |
| initVertexBufferObjects(); |
| |
| /* Reference values setup */ |
| initReferenceValues(); |
| } |
| |
| /** Initializes buffer objects for the test. */ |
| void TessellationShaderMaxPatchVertices::initVertexBufferObjects(void) |
| { |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Input patch vertices buffer setup. */ |
| m_patch_vertices_f = (glw::GLfloat*)malloc(m_gl_max_patch_vertices * 4 /* components */ * sizeof(glw::GLfloat)); |
| |
| if (m_patch_vertices_f == DE_NULL) |
| { |
| TCU_FAIL("Memory allocation failed!"); |
| } |
| |
| m_patch_vertices_i = (glw::GLint*)malloc(m_gl_max_patch_vertices * 4 /* components */ * sizeof(glw::GLint)); |
| |
| if (m_patch_vertices_i == DE_NULL) |
| { |
| TCU_FAIL("Memory allocation failed!"); |
| } |
| |
| for (int i = 0; i < m_gl_max_patch_vertices * 4 /* components */; i += 4 /* components */) |
| { |
| m_patch_vertices_f[i] = 1.0f; |
| m_patch_vertices_f[i + 1] = 2.0f; |
| m_patch_vertices_f[i + 2] = 3.0f; |
| m_patch_vertices_f[i + 3] = 4.0f; |
| |
| m_patch_vertices_i[i] = 1; |
| m_patch_vertices_i[i + 1] = 2; |
| m_patch_vertices_i[i + 2] = 3; |
| m_patch_vertices_i[i + 3] = 4; |
| } |
| |
| /* Vec4 vertex attribute array setup. */ |
| gl.genBuffers(1, &m_patch_vertices_bo_f_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_patch_vertices_bo_f_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| gl.bufferData(GL_ARRAY_BUFFER, m_gl_max_patch_vertices * 4 /* components */ * sizeof(glw::GLfloat), |
| m_patch_vertices_f, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed!"); |
| |
| gl.vertexAttribPointer(0, /* index */ |
| 4, /* size */ |
| GL_FLOAT, /* type */ |
| GL_FALSE, /* normalized */ |
| 0, /* stride */ |
| 0); /* pointer */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer(fv) failed!"); |
| |
| gl.enableVertexAttribArray(0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray(fv) failed!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| /* Ivec4 vertex attribute array setup. */ |
| gl.genBuffers(1, &m_patch_vertices_bo_i_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers(ARRAY_BUFFER) failed!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_patch_vertices_bo_i_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer(ARRAY_BUFFER) failed!"); |
| |
| gl.bufferData(GL_ARRAY_BUFFER, m_gl_max_patch_vertices * 4 /* components */ * sizeof(glw::GLint), |
| m_patch_vertices_i, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData(ARRAY_BUFFER) failed!"); |
| |
| gl.vertexAttribIPointer(1, /* index */ |
| 4, /* size */ |
| GL_INT, 0, /* stride */ |
| 0); /* pointer */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer(iv) failed!"); |
| |
| gl.enableVertexAttribArray(1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray(iv) failed!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| } |
| |
| /** Initializes buffer objects for the test. */ |
| void TessellationShaderMaxPatchVertices::initTransformFeedbackBufferObjects(void) |
| { |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Creating Transform Feedback buffer objects. */ |
| gl.genBuffers(1, &m_bo_id_f_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); |
| |
| gl.genBuffers(1, &m_bo_id_f_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); |
| |
| gl.genBuffers(1, &m_bo_id_i_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); |
| |
| gl.genBuffers(1, &m_bo_id_i_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); |
| |
| /* Transform feedback buffers for case 1*/ |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_f_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, |
| ((sizeof(glw::GLfloat)) * 4 /* components */ * OUTPUT_VERTEX_COUNT /* vertices */), DE_NULL, |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_i_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, |
| ((sizeof(glw::GLint)) * 4 /* components */ * OUTPUT_VERTEX_COUNT /* vertices */), DE_NULL, |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback(0) failed"); |
| |
| if (!glu::isContextTypeES(m_context.getRenderContext().getType())) |
| { |
| /* Transform feedback buffers for case 2*/ |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_f_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, |
| ((sizeof(glw::GLfloat)) * 4 /* components */ * OUTPUT_VERTEX_COUNT /* vertices */), DE_NULL, |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_i_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, |
| ((sizeof(glw::GLint)) * 4 /* components */ * OUTPUT_VERTEX_COUNT /* vertices */), DE_NULL, |
| GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback(0) failed"); |
| |
| gl.transformFeedbackVaryings(m_po_id_2, 2 /* count */, m_tf_varyings, GL_SEPARATE_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!"); |
| } |
| } |
| |
| /** Initializes program objects for the test. */ |
| void TessellationShaderMaxPatchVertices::initProgramObjects(void) |
| { |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Create and configure shader objects. */ |
| m_po_id_1 = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!"); |
| |
| m_po_id_2 = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!"); |
| |
| /* Creating Transform Feedback objects. */ |
| gl.genTransformFeedbacks(1, &m_tf_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks() failed!"); |
| |
| gl.genTransformFeedbacks(1, &m_tf_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks() failed!"); |
| |
| /* Create and configure shader objects. */ |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(VERTEX_SHADER) failed!"); |
| |
| m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed!"); |
| |
| m_te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed!"); |
| |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed!"); |
| |
| /* Transform Feedback setup case 1 (explicit arrays).*/ |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.transformFeedbackVaryings(m_po_id_1, 2 /* count */, m_tf_varyings, GL_SEPARATE_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!"); |
| |
| /* Build the program object case 1 (explicit arrays).*/ |
| if (!buildProgram(m_po_id_1, m_vs_id, 1, &m_vs_code, m_tc_id, 1, &m_tc_code, m_te_id, 1, &m_te_code, m_fs_id, 1, |
| &m_fs_code)) |
| { |
| TCU_FAIL("Program linking failed!"); |
| } |
| |
| if (!glu::isContextTypeES(m_context.getRenderContext().getType())) |
| { |
| /* Transform Feedback setup case 2 (implicit arrays).*/ |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.transformFeedbackVaryings(m_po_id_2, 2 /* count */, m_tf_varyings, GL_SEPARATE_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!"); |
| |
| /* Build the program object case 2 (implicit arrays). */ |
| if (!buildProgram(m_po_id_2, m_vs_id, 1, &m_vs_code, m_te_id, 1, &m_te_code, m_fs_id, 1, &m_fs_code)) |
| { |
| TCU_FAIL("Program linking failed!"); |
| } |
| } |
| } |
| |
| /** Initializes reference values for the test. */ |
| void TessellationShaderMaxPatchVertices::initReferenceValues(void) |
| { |
| /* Reference values setup. */ |
| m_ref_fv_case_1[0] = ((glw::GLfloat)(m_gl_max_patch_vertices * 2) * 1.0f); |
| m_ref_fv_case_1[1] = ((glw::GLfloat)(m_gl_max_patch_vertices * 2) * 2.0f); |
| m_ref_fv_case_1[2] = ((glw::GLfloat)(m_gl_max_patch_vertices * 2) * 3.0f); |
| m_ref_fv_case_1[3] = ((glw::GLfloat)(m_gl_max_patch_vertices * 2) * 4.0f); |
| |
| m_ref_iv_case_1[0] = (m_gl_max_patch_vertices * 2 * 1); |
| m_ref_iv_case_1[1] = (m_gl_max_patch_vertices * 2 * 2); |
| m_ref_iv_case_1[2] = (m_gl_max_patch_vertices * 2 * 3); |
| m_ref_iv_case_1[3] = (m_gl_max_patch_vertices * 2 * 4); |
| |
| if (!glu::isContextTypeES(m_context.getRenderContext().getType())) |
| { |
| m_ref_fv_case_2[0] = ((glw::GLfloat)m_gl_max_patch_vertices * 1.0f); |
| m_ref_fv_case_2[1] = ((glw::GLfloat)m_gl_max_patch_vertices * 2.0f); |
| m_ref_fv_case_2[2] = ((glw::GLfloat)m_gl_max_patch_vertices * 3.0f); |
| m_ref_fv_case_2[3] = ((glw::GLfloat)m_gl_max_patch_vertices * 4.0f); |
| |
| m_ref_iv_case_2[0] = (m_gl_max_patch_vertices * 1); |
| m_ref_iv_case_2[1] = (m_gl_max_patch_vertices * 2); |
| m_ref_iv_case_2[2] = (m_gl_max_patch_vertices * 3); |
| m_ref_iv_case_2[3] = (m_gl_max_patch_vertices * 4); |
| } |
| } |
| |
| /** Compares values of vec4 results with the reference data. |
| * |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed. |
| * |
| * Note the function throws exception should an error occur! |
| * |
| * @param description Test case's description. |
| * @param ref_fv Reference value. |
| * |
| * @return true if test passed; |
| * false if test failed. |
| **/ |
| bool TessellationShaderMaxPatchVertices::compareResults(const char* description, glw::GLfloat ref_fv[4]) |
| { |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const glw::GLfloat* resultFloats = DE_NULL; |
| |
| resultFloats = (const glw::GLfloat*)gl.mapBufferRange( |
| GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ |
| (sizeof(glw::GLfloat) /* GLfloat size */ * 4 /* components */ * OUTPUT_VERTEX_COUNT), GL_MAP_READ_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(floats) failed"); |
| |
| /* Comparison of vec4. */ |
| const glw::GLfloat epsilon = (glw::GLfloat)1e-5f; |
| bool test_failed = false; |
| |
| for (int i = 0; i < 4 /* components */; i++) |
| { |
| if (de::abs(resultFloats[i] - ref_fv[i]) > epsilon) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << description << " captured results " |
| << "vec4(" << resultFloats[0] << ", " << resultFloats[1] << ", " << resultFloats[2] |
| << ", " << resultFloats[3] << ") " |
| << "are different from the expected values " |
| << "vec4(" << ref_fv[0] << ", " << ref_fv[1] << ", " << ref_fv[2] << ", " << ref_fv[3] |
| << ")." << tcu::TestLog::EndMessage; |
| |
| test_failed = true; |
| break; |
| } |
| } |
| |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed!"); |
| |
| return !test_failed; |
| } |
| |
| /** Compares values of ivec4 results with the reference data. |
| * |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed. |
| * |
| * Note the function throws exception should an error occur! |
| * |
| * @param description Test case's description. |
| * @param ref_iv Reference value. |
| * |
| * @return true if test passed. |
| * false if test failed. |
| **/ |
| bool TessellationShaderMaxPatchVertices::compareResults(const char* description, glw::GLint ref_iv[4]) |
| { |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const glw::GLint* resultInts = DE_NULL; |
| |
| resultInts = (const glw::GLint*)gl.mapBufferRange( |
| GL_TRANSFORM_FEEDBACK_BUFFER, 0, |
| (sizeof(glw::GLint) /* GLfloat size */ * 4 /* components */ * OUTPUT_VERTEX_COUNT), GL_MAP_READ_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(ints) failed"); |
| |
| bool test_failed = false; |
| |
| /* Comparison of ivec4. */ |
| for (int i = 0; i < 4 /* components */; i++) |
| { |
| if (resultInts[i] != ref_iv[i]) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << description << " captured results ivec4(" << resultInts[0] |
| << ", " << resultInts[1] << ", " << resultInts[2] << ", " << resultInts[3] << ") " |
| << "are different from the expected values ivec4(" << ref_iv[0] << ", " << ref_iv[1] |
| << ", " << ref_iv[2] << ", " << ref_iv[3] << ")." << tcu::TestLog::EndMessage; |
| |
| test_failed = true; |
| break; |
| } |
| } |
| |
| gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed!"); |
| |
| return !test_failed; |
| } |
| |
| /** Executes the test. |
| * |
| * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. |
| * |
| * Note the function throws exception should an error occur! |
| * |
| * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. |
| **/ |
| tcu::TestNode::IterateResult TessellationShaderMaxPatchVertices::iterate(void) |
| { |
| /* Skip if required extensions are not supported. */ |
| if (!m_is_tessellation_shader_supported) |
| { |
| throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); |
| } |
| |
| /* Retrieve ES entry/state points. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Initialization */ |
| initTest(); |
| |
| /* Render setup case 1. */ |
| gl.useProgram(m_po_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!"); |
| |
| gl.enable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(RASTERIZER_DISCARD) failed!"); |
| |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_id_f_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() failed!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_bo_id_i_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() failed!"); |
| |
| /* Rendering case 1 with transform feedback.*/ |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed"); |
| |
| gl.drawArrays(m_glExtTokens.PATCHES, 0, m_gl_max_patch_vertices); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed"); |
| |
| /* Compare vec4 results from transform feedback for case 1. */ |
| bool test_passed = true; |
| |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_f_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| test_passed &= compareResults("Case 1 (explicit arrays)", m_ref_fv_case_1); |
| |
| /* Compare ivec4 results from transform feedback for case 2. */ |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_i_1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| test_passed &= compareResults("Case 1 (explicit arrays)", m_ref_iv_case_1); |
| |
| // Case 2 tests with no TCS (default TCS is expected to be used). |
| // Since this is not allowed by ES 3.1, just skip it. |
| // Leaving the code for Desktop |
| if (!glu::isContextTypeES(m_context.getRenderContext().getType())) |
| { |
| /* Set up rendering for case 2. */ |
| gl.useProgram(m_po_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!"); |
| |
| gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback() failed!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id_f_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() failed!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1 /* index */, m_bo_id_i_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() failed!"); |
| |
| /* Tessellation Control Levels setup. */ |
| const glw::GLfloat inner[] = { 1.0, 1.0 }; |
| const glw::GLfloat outer[] = { 1.0, 1.0, 1.0, 1.0 }; |
| |
| gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, outer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() failed!"); |
| |
| gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, inner); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() failed!"); |
| |
| /* Rendering case 2 with transform feedback. */ |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed"); |
| |
| gl.drawArrays(GL_PATCHES, 0, m_gl_max_patch_vertices); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed"); |
| |
| /* Compare vec4 results from transform feedback for case 2. */ |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_f_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| test_passed &= compareResults("Case 2 (implicit arrays)", m_ref_fv_case_2); |
| |
| /* Compare ivec4 results from transform feedback for case 2. */ |
| gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_i_2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!"); |
| |
| test_passed &= compareResults("Case 2 (implicit arrays)", m_ref_iv_case_2); |
| } |
| /* All done */ |
| if (test_passed) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| |
| return STOP; |
| } |
| |
| } /* namespace glcts */ |