1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite 3e5c31af7Sopenharmony_ci * ----------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright (c) 2014-2016 The Khronos Group Inc. 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci */ /*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief 22e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "esextcTessellationShaderXFB.hpp" 25e5c31af7Sopenharmony_ci#include "esextcTessellationShaderUtils.hpp" 26e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp" 27e5c31af7Sopenharmony_ci#include "gluDefs.hpp" 28e5c31af7Sopenharmony_ci#include "glwEnums.hpp" 29e5c31af7Sopenharmony_ci#include "glwFunctions.hpp" 30e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp" 31e5c31af7Sopenharmony_ci 32e5c31af7Sopenharmony_cinamespace glcts 33e5c31af7Sopenharmony_ci{ 34e5c31af7Sopenharmony_ci 35e5c31af7Sopenharmony_ci/** Constructor 36e5c31af7Sopenharmony_ci * 37e5c31af7Sopenharmony_ci * @param context Test context 38e5c31af7Sopenharmony_ci **/ 39e5c31af7Sopenharmony_ciTessellationShaderXFB::TessellationShaderXFB(Context& context, const ExtParameters& extParams) 40e5c31af7Sopenharmony_ci : TestCaseBase(context, extParams, "xfb_captures_data_from_correct_stage", 41e5c31af7Sopenharmony_ci "Verifies transform-feedback captures data from appropriate shader stage.") 42e5c31af7Sopenharmony_ci , m_bo_id(0) 43e5c31af7Sopenharmony_ci , m_fs_id(0) 44e5c31af7Sopenharmony_ci , m_gs_id(0) 45e5c31af7Sopenharmony_ci , m_po_id(0) 46e5c31af7Sopenharmony_ci , m_tc_id(0) 47e5c31af7Sopenharmony_ci , m_te_id(0) 48e5c31af7Sopenharmony_ci , m_vs_id(0) 49e5c31af7Sopenharmony_ci , m_pipeline_id(0) 50e5c31af7Sopenharmony_ci , m_fs_program_id(0) 51e5c31af7Sopenharmony_ci , m_gs_program_id(0) 52e5c31af7Sopenharmony_ci , m_tc_program_id(0) 53e5c31af7Sopenharmony_ci , m_te_program_id(0) 54e5c31af7Sopenharmony_ci , m_vs_program_id(0) 55e5c31af7Sopenharmony_ci , m_vao_id(0) 56e5c31af7Sopenharmony_ci{ 57e5c31af7Sopenharmony_ci /* Left blank on purpose */ 58e5c31af7Sopenharmony_ci} 59e5c31af7Sopenharmony_ci 60e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */ 61e5c31af7Sopenharmony_civoid TessellationShaderXFB::deinit() 62e5c31af7Sopenharmony_ci{ 63e5c31af7Sopenharmony_ci /* Call base class' deinit() */ 64e5c31af7Sopenharmony_ci TestCaseBase::deinit(); 65e5c31af7Sopenharmony_ci 66e5c31af7Sopenharmony_ci if (!m_is_tessellation_shader_supported) 67e5c31af7Sopenharmony_ci { 68e5c31af7Sopenharmony_ci return; 69e5c31af7Sopenharmony_ci } 70e5c31af7Sopenharmony_ci 71e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 72e5c31af7Sopenharmony_ci 73e5c31af7Sopenharmony_ci /* Reset GL_PATCH_VERTICES_EXT value */ 74e5c31af7Sopenharmony_ci gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3); 75e5c31af7Sopenharmony_ci 76e5c31af7Sopenharmony_ci /* Disable any pipeline object that may still be active */ 77e5c31af7Sopenharmony_ci gl.bindProgramPipeline(0); 78e5c31af7Sopenharmony_ci 79e5c31af7Sopenharmony_ci /* Reset TF buffer object bindings */ 80e5c31af7Sopenharmony_ci gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */); 81e5c31af7Sopenharmony_ci gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */); 82e5c31af7Sopenharmony_ci 83e5c31af7Sopenharmony_ci /* Unbind vertex array object */ 84e5c31af7Sopenharmony_ci gl.bindVertexArray(0); 85e5c31af7Sopenharmony_ci 86e5c31af7Sopenharmony_ci /* Free all ES objects we allocated for the test */ 87e5c31af7Sopenharmony_ci if (m_bo_id != 0) 88e5c31af7Sopenharmony_ci { 89e5c31af7Sopenharmony_ci gl.deleteBuffers(1, &m_bo_id); 90e5c31af7Sopenharmony_ci 91e5c31af7Sopenharmony_ci m_bo_id = 0; 92e5c31af7Sopenharmony_ci } 93e5c31af7Sopenharmony_ci 94e5c31af7Sopenharmony_ci if (m_fs_id != 0) 95e5c31af7Sopenharmony_ci { 96e5c31af7Sopenharmony_ci gl.deleteShader(m_fs_id); 97e5c31af7Sopenharmony_ci 98e5c31af7Sopenharmony_ci m_fs_id = 0; 99e5c31af7Sopenharmony_ci } 100e5c31af7Sopenharmony_ci 101e5c31af7Sopenharmony_ci if (m_fs_program_id != 0) 102e5c31af7Sopenharmony_ci { 103e5c31af7Sopenharmony_ci gl.deleteProgram(m_fs_program_id); 104e5c31af7Sopenharmony_ci 105e5c31af7Sopenharmony_ci m_fs_program_id = 0; 106e5c31af7Sopenharmony_ci } 107e5c31af7Sopenharmony_ci 108e5c31af7Sopenharmony_ci if (m_gs_id != 0) 109e5c31af7Sopenharmony_ci { 110e5c31af7Sopenharmony_ci gl.deleteShader(m_gs_id); 111e5c31af7Sopenharmony_ci 112e5c31af7Sopenharmony_ci m_gs_id = 0; 113e5c31af7Sopenharmony_ci } 114e5c31af7Sopenharmony_ci 115e5c31af7Sopenharmony_ci if (m_gs_program_id != 0) 116e5c31af7Sopenharmony_ci { 117e5c31af7Sopenharmony_ci gl.deleteProgram(m_gs_program_id); 118e5c31af7Sopenharmony_ci 119e5c31af7Sopenharmony_ci m_gs_program_id = 0; 120e5c31af7Sopenharmony_ci } 121e5c31af7Sopenharmony_ci 122e5c31af7Sopenharmony_ci if (m_pipeline_id != 0) 123e5c31af7Sopenharmony_ci { 124e5c31af7Sopenharmony_ci gl.deleteProgramPipelines(1, &m_pipeline_id); 125e5c31af7Sopenharmony_ci 126e5c31af7Sopenharmony_ci m_pipeline_id = 0; 127e5c31af7Sopenharmony_ci } 128e5c31af7Sopenharmony_ci 129e5c31af7Sopenharmony_ci if (m_po_id != 0) 130e5c31af7Sopenharmony_ci { 131e5c31af7Sopenharmony_ci gl.deleteProgram(m_po_id); 132e5c31af7Sopenharmony_ci 133e5c31af7Sopenharmony_ci m_po_id = 0; 134e5c31af7Sopenharmony_ci } 135e5c31af7Sopenharmony_ci 136e5c31af7Sopenharmony_ci if (m_tc_id != 0) 137e5c31af7Sopenharmony_ci { 138e5c31af7Sopenharmony_ci gl.deleteShader(m_tc_id); 139e5c31af7Sopenharmony_ci 140e5c31af7Sopenharmony_ci m_tc_id = 0; 141e5c31af7Sopenharmony_ci } 142e5c31af7Sopenharmony_ci 143e5c31af7Sopenharmony_ci if (m_tc_program_id != 0) 144e5c31af7Sopenharmony_ci { 145e5c31af7Sopenharmony_ci gl.deleteProgram(m_tc_program_id); 146e5c31af7Sopenharmony_ci 147e5c31af7Sopenharmony_ci m_tc_program_id = 0; 148e5c31af7Sopenharmony_ci } 149e5c31af7Sopenharmony_ci 150e5c31af7Sopenharmony_ci if (m_te_id != 0) 151e5c31af7Sopenharmony_ci { 152e5c31af7Sopenharmony_ci gl.deleteShader(m_te_id); 153e5c31af7Sopenharmony_ci 154e5c31af7Sopenharmony_ci m_te_id = 0; 155e5c31af7Sopenharmony_ci } 156e5c31af7Sopenharmony_ci 157e5c31af7Sopenharmony_ci if (m_te_program_id != 0) 158e5c31af7Sopenharmony_ci { 159e5c31af7Sopenharmony_ci gl.deleteProgram(m_te_program_id); 160e5c31af7Sopenharmony_ci 161e5c31af7Sopenharmony_ci m_te_program_id = 0; 162e5c31af7Sopenharmony_ci } 163e5c31af7Sopenharmony_ci 164e5c31af7Sopenharmony_ci if (m_vs_id != 0) 165e5c31af7Sopenharmony_ci { 166e5c31af7Sopenharmony_ci gl.deleteShader(m_vs_id); 167e5c31af7Sopenharmony_ci 168e5c31af7Sopenharmony_ci m_vs_id = 0; 169e5c31af7Sopenharmony_ci } 170e5c31af7Sopenharmony_ci 171e5c31af7Sopenharmony_ci if (m_vs_program_id != 0) 172e5c31af7Sopenharmony_ci { 173e5c31af7Sopenharmony_ci gl.deleteProgram(m_vs_program_id); 174e5c31af7Sopenharmony_ci 175e5c31af7Sopenharmony_ci m_vs_program_id = 0; 176e5c31af7Sopenharmony_ci } 177e5c31af7Sopenharmony_ci 178e5c31af7Sopenharmony_ci if (m_vao_id != 0) 179e5c31af7Sopenharmony_ci { 180e5c31af7Sopenharmony_ci gl.deleteVertexArrays(1, &m_vao_id); 181e5c31af7Sopenharmony_ci 182e5c31af7Sopenharmony_ci m_vao_id = 0; 183e5c31af7Sopenharmony_ci } 184e5c31af7Sopenharmony_ci} 185e5c31af7Sopenharmony_ci 186e5c31af7Sopenharmony_ci/** Create separable programs **/ 187e5c31af7Sopenharmony_ciglw::GLuint TessellationShaderXFB::createSeparableProgram(glw::GLenum shader_type, unsigned int n_strings, 188e5c31af7Sopenharmony_ci const char* const* strings, unsigned int n_varyings, 189e5c31af7Sopenharmony_ci const char* const* varyings, bool should_succeed) 190e5c31af7Sopenharmony_ci{ 191e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 192e5c31af7Sopenharmony_ci glw::GLuint po_id = 0; 193e5c31af7Sopenharmony_ci glw::GLuint so_id = 0; 194e5c31af7Sopenharmony_ci 195e5c31af7Sopenharmony_ci /* Create a shader object */ 196e5c31af7Sopenharmony_ci so_id = gl.createShader(shader_type); 197e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed"); 198e5c31af7Sopenharmony_ci 199e5c31af7Sopenharmony_ci /* Create a program object */ 200e5c31af7Sopenharmony_ci po_id = gl.createProgram(); 201e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed"); 202e5c31af7Sopenharmony_ci 203e5c31af7Sopenharmony_ci /* Mark the program object as separable */ 204e5c31af7Sopenharmony_ci gl.programParameteri(po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); 205e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed"); 206e5c31af7Sopenharmony_ci 207e5c31af7Sopenharmony_ci /* Configure XFB for the program object */ 208e5c31af7Sopenharmony_ci if (n_varyings != 0) 209e5c31af7Sopenharmony_ci { 210e5c31af7Sopenharmony_ci gl.transformFeedbackVaryings(po_id, n_varyings, varyings, GL_SEPARATE_ATTRIBS); 211e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed"); 212e5c31af7Sopenharmony_ci } 213e5c31af7Sopenharmony_ci 214e5c31af7Sopenharmony_ci bool build_success = buildProgram(po_id, so_id, n_strings, strings); 215e5c31af7Sopenharmony_ci 216e5c31af7Sopenharmony_ci /* Safe to delete the shader object at this point */ 217e5c31af7Sopenharmony_ci gl.deleteShader(so_id); 218e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed"); 219e5c31af7Sopenharmony_ci 220e5c31af7Sopenharmony_ci if (!build_success) 221e5c31af7Sopenharmony_ci { 222e5c31af7Sopenharmony_ci gl.deleteProgram(po_id); 223e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed"); 224e5c31af7Sopenharmony_ci po_id = 0; 225e5c31af7Sopenharmony_ci 226e5c31af7Sopenharmony_ci if (should_succeed) 227e5c31af7Sopenharmony_ci { 228e5c31af7Sopenharmony_ci TCU_FAIL("Separable program should have succeeded"); 229e5c31af7Sopenharmony_ci } 230e5c31af7Sopenharmony_ci } 231e5c31af7Sopenharmony_ci else if (!should_succeed) 232e5c31af7Sopenharmony_ci { 233e5c31af7Sopenharmony_ci std::string shader_source = getShaderSource(so_id); 234e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Shader source:\n\n" 235e5c31af7Sopenharmony_ci << shader_source << "\n\n" 236e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 237e5c31af7Sopenharmony_ci TCU_FAIL("Separable program should have failed"); 238e5c31af7Sopenharmony_ci } 239e5c31af7Sopenharmony_ci 240e5c31af7Sopenharmony_ci return po_id; 241e5c31af7Sopenharmony_ci} 242e5c31af7Sopenharmony_ci 243e5c31af7Sopenharmony_ci/** Initializes ES objects necessary to run the test. */ 244e5c31af7Sopenharmony_civoid TessellationShaderXFB::initTest() 245e5c31af7Sopenharmony_ci{ 246e5c31af7Sopenharmony_ci /* Skip if required extensions are not supported. */ 247e5c31af7Sopenharmony_ci if (!m_is_tessellation_shader_supported) 248e5c31af7Sopenharmony_ci { 249e5c31af7Sopenharmony_ci return; 250e5c31af7Sopenharmony_ci } 251e5c31af7Sopenharmony_ci 252e5c31af7Sopenharmony_ci /* Generate all objects needed for the test */ 253e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 254e5c31af7Sopenharmony_ci 255e5c31af7Sopenharmony_ci gl.genVertexArrays(1, &m_vao_id); 256e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); 257e5c31af7Sopenharmony_ci 258e5c31af7Sopenharmony_ci gl.bindVertexArray(m_vao_id); 259e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); 260e5c31af7Sopenharmony_ci 261e5c31af7Sopenharmony_ci gl.genBuffers(1, &m_bo_id); 262e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); 263e5c31af7Sopenharmony_ci 264e5c31af7Sopenharmony_ci m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); 265e5c31af7Sopenharmony_ci m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER); 266e5c31af7Sopenharmony_ci m_te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER); 267e5c31af7Sopenharmony_ci m_vs_id = gl.createShader(GL_VERTEX_SHADER); 268e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed"); 269e5c31af7Sopenharmony_ci 270e5c31af7Sopenharmony_ci m_po_id = gl.createProgram(); 271e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed"); 272e5c31af7Sopenharmony_ci 273e5c31af7Sopenharmony_ci if (m_is_geometry_shader_extension_supported) 274e5c31af7Sopenharmony_ci { 275e5c31af7Sopenharmony_ci m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); 276e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed for GL_GEOMETRY_SHADER_EXT"); 277e5c31af7Sopenharmony_ci } 278e5c31af7Sopenharmony_ci 279e5c31af7Sopenharmony_ci gl.genProgramPipelines(1, &m_pipeline_id); 280e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() failed"); 281e5c31af7Sopenharmony_ci 282e5c31af7Sopenharmony_ci /* Configure fragment shader body */ 283e5c31af7Sopenharmony_ci const char* fs_body = "${VERSION}\n" 284e5c31af7Sopenharmony_ci "\n" 285e5c31af7Sopenharmony_ci "${SHADER_IO_BLOCKS_REQUIRE}\n" 286e5c31af7Sopenharmony_ci "\n" 287e5c31af7Sopenharmony_ci "precision highp float;\n" 288e5c31af7Sopenharmony_ci "in BLOCK_INOUT { vec4 value; } user_in;\n" 289e5c31af7Sopenharmony_ci "\n" 290e5c31af7Sopenharmony_ci "void main()\n" 291e5c31af7Sopenharmony_ci "{\n" 292e5c31af7Sopenharmony_ci "}\n"; 293e5c31af7Sopenharmony_ci 294e5c31af7Sopenharmony_ci shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body); 295e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader"); 296e5c31af7Sopenharmony_ci 297e5c31af7Sopenharmony_ci /* Create a fragment shader program */ 298e5c31af7Sopenharmony_ci glw::GLint link_status = GL_FALSE; 299e5c31af7Sopenharmony_ci const glw::GLchar* varying_name = "BLOCK_INOUT.value"; 300e5c31af7Sopenharmony_ci 301e5c31af7Sopenharmony_ci m_fs_program_id = createSeparableProgram(GL_FRAGMENT_SHADER, 1, /* n_strings */ 302e5c31af7Sopenharmony_ci &fs_body, 0, /* n_varyings */ 303e5c31af7Sopenharmony_ci DE_NULL, /* varyings */ 304e5c31af7Sopenharmony_ci true); /* should_succeed */ 305e5c31af7Sopenharmony_ci 306e5c31af7Sopenharmony_ci gl.getProgramiv(m_fs_program_id, GL_LINK_STATUS, &link_status); 307e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); 308e5c31af7Sopenharmony_ci 309e5c31af7Sopenharmony_ci if (link_status != GL_TRUE) 310e5c31af7Sopenharmony_ci { 311e5c31af7Sopenharmony_ci TCU_FAIL("Fragment shader program failed to link."); 312e5c31af7Sopenharmony_ci } 313e5c31af7Sopenharmony_ci 314e5c31af7Sopenharmony_ci /* Configure geometry shader body */ 315e5c31af7Sopenharmony_ci const char* gs_body = "${VERSION}\n" 316e5c31af7Sopenharmony_ci "\n" 317e5c31af7Sopenharmony_ci "${GEOMETRY_SHADER_REQUIRE}\n" 318e5c31af7Sopenharmony_ci "\n" 319e5c31af7Sopenharmony_ci "layout(points) in;\n" 320e5c31af7Sopenharmony_ci "layout(points, max_vertices = 1) out;\n" 321e5c31af7Sopenharmony_ci "\n" 322e5c31af7Sopenharmony_ci "precision highp float;\n" 323e5c31af7Sopenharmony_ci "${IN_PER_VERTEX_DECL_ARRAY}" 324e5c31af7Sopenharmony_ci "${OUT_PER_VERTEX_DECL}" 325e5c31af7Sopenharmony_ci "in BLOCK_INOUT { vec4 value; } user_in[];\n" 326e5c31af7Sopenharmony_ci "out BLOCK_INOUT { vec4 value; } user_out;\n" 327e5c31af7Sopenharmony_ci "\n" 328e5c31af7Sopenharmony_ci "void main()\n" 329e5c31af7Sopenharmony_ci "{\n" 330e5c31af7Sopenharmony_ci " user_out.value = vec4(1.0, 2.0, 3.0, 4.0);\n" 331e5c31af7Sopenharmony_ci " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 332e5c31af7Sopenharmony_ci "\n" 333e5c31af7Sopenharmony_ci " EmitVertex();\n" 334e5c31af7Sopenharmony_ci "}\n"; 335e5c31af7Sopenharmony_ci 336e5c31af7Sopenharmony_ci if (m_is_geometry_shader_extension_supported) 337e5c31af7Sopenharmony_ci { 338e5c31af7Sopenharmony_ci shaderSourceSpecialized(m_gs_id, 1 /* count */, &gs_body); 339e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for geometry shader"); 340e5c31af7Sopenharmony_ci 341e5c31af7Sopenharmony_ci /* Create a geometry shader program */ 342e5c31af7Sopenharmony_ci m_gs_program_id = createSeparableProgram(m_glExtTokens.GEOMETRY_SHADER, 1, /* n_strings */ 343e5c31af7Sopenharmony_ci &gs_body, 1, /* n_varyings */ 344e5c31af7Sopenharmony_ci &varying_name, true); /* should_succeed */ 345e5c31af7Sopenharmony_ci 346e5c31af7Sopenharmony_ci if (m_gs_program_id == 0) 347e5c31af7Sopenharmony_ci { 348e5c31af7Sopenharmony_ci TCU_FAIL("Could not create a separate geometry program object"); 349e5c31af7Sopenharmony_ci } 350e5c31af7Sopenharmony_ci 351e5c31af7Sopenharmony_ci gl.getProgramiv(m_gs_program_id, GL_LINK_STATUS, &link_status); 352e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); 353e5c31af7Sopenharmony_ci 354e5c31af7Sopenharmony_ci if (link_status != GL_TRUE) 355e5c31af7Sopenharmony_ci { 356e5c31af7Sopenharmony_ci TCU_FAIL("Geometry shader program failed to link."); 357e5c31af7Sopenharmony_ci } 358e5c31af7Sopenharmony_ci } 359e5c31af7Sopenharmony_ci 360e5c31af7Sopenharmony_ci /* Configure tessellation control shader body */ 361e5c31af7Sopenharmony_ci const char* tc_body = "${VERSION}\n" 362e5c31af7Sopenharmony_ci "\n" 363e5c31af7Sopenharmony_ci "${TESSELLATION_SHADER_REQUIRE}\n" 364e5c31af7Sopenharmony_ci "\n" 365e5c31af7Sopenharmony_ci "layout (vertices=4) out;\n" 366e5c31af7Sopenharmony_ci "\n" 367e5c31af7Sopenharmony_ci "precision highp float;\n" 368e5c31af7Sopenharmony_ci "${IN_PER_VERTEX_DECL_ARRAY}" 369e5c31af7Sopenharmony_ci "${OUT_PER_VERTEX_DECL_ARRAY}" 370e5c31af7Sopenharmony_ci "in BLOCK_INOUT { vec4 value; } user_in[];\n" 371e5c31af7Sopenharmony_ci "out BLOCK_INOUT { vec4 value; } user_out[];\n" 372e5c31af7Sopenharmony_ci "\n" 373e5c31af7Sopenharmony_ci "void main()\n" 374e5c31af7Sopenharmony_ci "{\n" 375e5c31af7Sopenharmony_ci " gl_out [gl_InvocationID].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 376e5c31af7Sopenharmony_ci " user_out [gl_InvocationID].value = vec4(2.0, 3.0, 4.0, 5.0);\n" 377e5c31af7Sopenharmony_ci "\n" 378e5c31af7Sopenharmony_ci " gl_TessLevelOuter[0] = 1.0;\n" 379e5c31af7Sopenharmony_ci " gl_TessLevelOuter[1] = 1.0;\n" 380e5c31af7Sopenharmony_ci "}\n"; 381e5c31af7Sopenharmony_ci 382e5c31af7Sopenharmony_ci shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body); 383e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader"); 384e5c31af7Sopenharmony_ci 385e5c31af7Sopenharmony_ci /* Test creating a tessellation control shader program with feedback. 386e5c31af7Sopenharmony_ci * For ES, this will fail, and so we will create a different 387e5c31af7Sopenharmony_ci * program without the feedback varyings that we can use for our testing. 388e5c31af7Sopenharmony_ci * (We can safely ignore the return value for the expected failure case. 389e5c31af7Sopenharmony_ci * In the event that the failure case incorrectly succeeds, 390e5c31af7Sopenharmony_ci * createSeparableProgram will generate a test failure exception.) 391e5c31af7Sopenharmony_ci */ 392e5c31af7Sopenharmony_ci 393e5c31af7Sopenharmony_ci bool tc_feedback_valid; 394e5c31af7Sopenharmony_ci if (!glu::isContextTypeES(m_context.getRenderContext().getType())) 395e5c31af7Sopenharmony_ci { 396e5c31af7Sopenharmony_ci tc_feedback_valid = true; 397e5c31af7Sopenharmony_ci } 398e5c31af7Sopenharmony_ci else 399e5c31af7Sopenharmony_ci { 400e5c31af7Sopenharmony_ci tc_feedback_valid = false; 401e5c31af7Sopenharmony_ci } 402e5c31af7Sopenharmony_ci 403e5c31af7Sopenharmony_ci /* Create a tessellation control shader program */ 404e5c31af7Sopenharmony_ci m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */ 405e5c31af7Sopenharmony_ci &tc_body, 1, /* n_varyings */ 406e5c31af7Sopenharmony_ci &varying_name, /* varyings */ 407e5c31af7Sopenharmony_ci tc_feedback_valid); /* should_succeed */ 408e5c31af7Sopenharmony_ci 409e5c31af7Sopenharmony_ci if (!tc_feedback_valid) 410e5c31af7Sopenharmony_ci { 411e5c31af7Sopenharmony_ci /* Create a valid tessellation control shader program for ES */ 412e5c31af7Sopenharmony_ci m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */ 413e5c31af7Sopenharmony_ci &tc_body, 0, /* n_varyings */ 414e5c31af7Sopenharmony_ci DE_NULL, /* varyings */ 415e5c31af7Sopenharmony_ci true); /* should_succeed */ 416e5c31af7Sopenharmony_ci } 417e5c31af7Sopenharmony_ci 418e5c31af7Sopenharmony_ci if (m_tc_program_id == 0) 419e5c31af7Sopenharmony_ci { 420e5c31af7Sopenharmony_ci TCU_FAIL("Could not create a separate tessellation control program object"); 421e5c31af7Sopenharmony_ci } 422e5c31af7Sopenharmony_ci 423e5c31af7Sopenharmony_ci gl.getProgramiv(m_tc_program_id, GL_LINK_STATUS, &link_status); 424e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); 425e5c31af7Sopenharmony_ci 426e5c31af7Sopenharmony_ci if (link_status != GL_TRUE) 427e5c31af7Sopenharmony_ci { 428e5c31af7Sopenharmony_ci TCU_FAIL("Tessellation control shader program failed to link."); 429e5c31af7Sopenharmony_ci } 430e5c31af7Sopenharmony_ci 431e5c31af7Sopenharmony_ci /* Configure tessellation evaluation shader body */ 432e5c31af7Sopenharmony_ci const char* te_body = "${VERSION}\n" 433e5c31af7Sopenharmony_ci "\n" 434e5c31af7Sopenharmony_ci "${TESSELLATION_SHADER_REQUIRE}\n" 435e5c31af7Sopenharmony_ci "\n" 436e5c31af7Sopenharmony_ci "layout (isolines, point_mode) in;\n" 437e5c31af7Sopenharmony_ci "\n" 438e5c31af7Sopenharmony_ci "precision highp float;\n" 439e5c31af7Sopenharmony_ci "${IN_PER_VERTEX_DECL_ARRAY}" 440e5c31af7Sopenharmony_ci "${OUT_PER_VERTEX_DECL}" 441e5c31af7Sopenharmony_ci "in BLOCK_INOUT { vec4 value; } user_in[];\n" 442e5c31af7Sopenharmony_ci "out BLOCK_INOUT { vec4 value; } user_out;\n" 443e5c31af7Sopenharmony_ci "\n" 444e5c31af7Sopenharmony_ci "void main()\n" 445e5c31af7Sopenharmony_ci "{\n" 446e5c31af7Sopenharmony_ci " gl_Position = gl_in[0].gl_Position;\n" 447e5c31af7Sopenharmony_ci " user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n" 448e5c31af7Sopenharmony_ci "}\n"; 449e5c31af7Sopenharmony_ci 450e5c31af7Sopenharmony_ci shaderSourceSpecialized(m_te_id, 1 /* count */, &te_body); 451e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader"); 452e5c31af7Sopenharmony_ci 453e5c31af7Sopenharmony_ci /* Create a tessellation evaluation shader program */ 454e5c31af7Sopenharmony_ci m_te_program_id = createSeparableProgram(m_glExtTokens.TESS_EVALUATION_SHADER, 1, /* n_strings */ 455e5c31af7Sopenharmony_ci &te_body, 1, /* n_varyings */ 456e5c31af7Sopenharmony_ci &varying_name, true); /* should_succeed */ 457e5c31af7Sopenharmony_ci 458e5c31af7Sopenharmony_ci if (m_te_program_id == 0) 459e5c31af7Sopenharmony_ci { 460e5c31af7Sopenharmony_ci TCU_FAIL("Could not create a separate tessellation evaluation program object"); 461e5c31af7Sopenharmony_ci } 462e5c31af7Sopenharmony_ci 463e5c31af7Sopenharmony_ci gl.getProgramiv(m_te_program_id, GL_LINK_STATUS, &link_status); 464e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); 465e5c31af7Sopenharmony_ci 466e5c31af7Sopenharmony_ci if (link_status != GL_TRUE) 467e5c31af7Sopenharmony_ci { 468e5c31af7Sopenharmony_ci TCU_FAIL("Tessellation evaluation shader program failed to link."); 469e5c31af7Sopenharmony_ci } 470e5c31af7Sopenharmony_ci 471e5c31af7Sopenharmony_ci /* Configure vertex shader body */ 472e5c31af7Sopenharmony_ci const char* vs_body = "${VERSION}\n" 473e5c31af7Sopenharmony_ci "\n" 474e5c31af7Sopenharmony_ci "${SHADER_IO_BLOCKS_REQUIRE}\n" 475e5c31af7Sopenharmony_ci "\n" 476e5c31af7Sopenharmony_ci "precision highp float;\n" 477e5c31af7Sopenharmony_ci "${OUT_PER_VERTEX_DECL}" 478e5c31af7Sopenharmony_ci "out BLOCK_INOUT { vec4 value; } user_out;\n" 479e5c31af7Sopenharmony_ci "\n" 480e5c31af7Sopenharmony_ci "void main()\n" 481e5c31af7Sopenharmony_ci "{\n" 482e5c31af7Sopenharmony_ci " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" 483e5c31af7Sopenharmony_ci " user_out.value = vec4(4.0, 5.0, 6.0, 7.0);\n" 484e5c31af7Sopenharmony_ci "}\n"; 485e5c31af7Sopenharmony_ci 486e5c31af7Sopenharmony_ci shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body); 487e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader"); 488e5c31af7Sopenharmony_ci 489e5c31af7Sopenharmony_ci /* Configure vertex shader program */ 490e5c31af7Sopenharmony_ci m_vs_program_id = createSeparableProgram(GL_VERTEX_SHADER, 1, /* n_strings */ 491e5c31af7Sopenharmony_ci &vs_body, 1, /* n_varyings */ 492e5c31af7Sopenharmony_ci &varying_name, true); /* should_succeed */ 493e5c31af7Sopenharmony_ci 494e5c31af7Sopenharmony_ci /* Compile all the shaders */ 495e5c31af7Sopenharmony_ci const glw::GLuint shaders[] = { m_fs_id, (m_is_geometry_shader_extension_supported) ? m_gs_id : 0, m_tc_id, m_te_id, 496e5c31af7Sopenharmony_ci m_vs_id }; 497e5c31af7Sopenharmony_ci const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]); 498e5c31af7Sopenharmony_ci 499e5c31af7Sopenharmony_ci for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader) 500e5c31af7Sopenharmony_ci { 501e5c31af7Sopenharmony_ci glw::GLuint shader = shaders[n_shader]; 502e5c31af7Sopenharmony_ci 503e5c31af7Sopenharmony_ci if (shader != 0) 504e5c31af7Sopenharmony_ci { 505e5c31af7Sopenharmony_ci glw::GLint compile_status = GL_FALSE; 506e5c31af7Sopenharmony_ci 507e5c31af7Sopenharmony_ci gl.compileShader(shader); 508e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed"); 509e5c31af7Sopenharmony_ci 510e5c31af7Sopenharmony_ci gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status); 511e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed"); 512e5c31af7Sopenharmony_ci 513e5c31af7Sopenharmony_ci if (compile_status != GL_TRUE) 514e5c31af7Sopenharmony_ci { 515e5c31af7Sopenharmony_ci const char* src[] = { fs_body, gs_body, tc_body, te_body, vs_body }; 516e5c31af7Sopenharmony_ci 517e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader 518e5c31af7Sopenharmony_ci << " failed.\n" 519e5c31af7Sopenharmony_ci << "Info log:\n" 520e5c31af7Sopenharmony_ci << getCompilationInfoLog(shader) << "Shader:\n" 521e5c31af7Sopenharmony_ci << src[n_shader] << tcu::TestLog::EndMessage; 522e5c31af7Sopenharmony_ci 523e5c31af7Sopenharmony_ci TCU_FAIL("Shader compilation failed"); 524e5c31af7Sopenharmony_ci } 525e5c31af7Sopenharmony_ci } 526e5c31af7Sopenharmony_ci } /* for (all shaders) */ 527e5c31af7Sopenharmony_ci 528e5c31af7Sopenharmony_ci /* Attach fragment & vertex shaders to the program object */ 529e5c31af7Sopenharmony_ci gl.attachShader(m_po_id, m_fs_id); 530e5c31af7Sopenharmony_ci gl.attachShader(m_po_id, m_vs_id); 531e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed"); 532e5c31af7Sopenharmony_ci 533e5c31af7Sopenharmony_ci /* Configure pipeline object's fragment & vertex stages */ 534e5c31af7Sopenharmony_ci gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, m_fs_program_id); 535e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for fragment stage"); 536e5c31af7Sopenharmony_ci 537e5c31af7Sopenharmony_ci gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, m_vs_program_id); 538e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for vertex stage"); 539e5c31af7Sopenharmony_ci 540e5c31af7Sopenharmony_ci /* Set up XFB for conventional program object */ 541e5c31af7Sopenharmony_ci gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &varying_name, GL_SEPARATE_ATTRIBS); 542e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed"); 543e5c31af7Sopenharmony_ci 544e5c31af7Sopenharmony_ci /* Set up buffer object storage. 545e5c31af7Sopenharmony_ci * We allocate enough space for a 4 vertex patch, which is the size 546e5c31af7Sopenharmony_ci * needed by desktop GL for the tessellation control shader feedback 547e5c31af7Sopenharmony_ci * whenever GL_NV_gpu_shader5 is present. */ 548e5c31af7Sopenharmony_ci gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); 549e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed"); 550e5c31af7Sopenharmony_ci 551e5c31af7Sopenharmony_ci gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4 /* components */ * 4 /* vertices per patch */, 552e5c31af7Sopenharmony_ci NULL, /* data */ 553e5c31af7Sopenharmony_ci GL_STATIC_DRAW); 554e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); 555e5c31af7Sopenharmony_ci 556e5c31af7Sopenharmony_ci /* Bind the buffer object to indiced TF binding point */ 557e5c31af7Sopenharmony_ci gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); 558e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed"); 559e5c31af7Sopenharmony_ci} 560e5c31af7Sopenharmony_ci 561e5c31af7Sopenharmony_ci/** Executes the test. 562e5c31af7Sopenharmony_ci * 563e5c31af7Sopenharmony_ci * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 564e5c31af7Sopenharmony_ci * 565e5c31af7Sopenharmony_ci * Note the function throws exception should an error occur! 566e5c31af7Sopenharmony_ci * 567e5c31af7Sopenharmony_ci * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. 568e5c31af7Sopenharmony_ci **/ 569e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderXFB::iterate(void) 570e5c31af7Sopenharmony_ci{ 571e5c31af7Sopenharmony_ci /* Do not execute if required extensions are not supported. */ 572e5c31af7Sopenharmony_ci if (!m_is_tessellation_shader_supported) 573e5c31af7Sopenharmony_ci { 574e5c31af7Sopenharmony_ci throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); 575e5c31af7Sopenharmony_ci } 576e5c31af7Sopenharmony_ci 577e5c31af7Sopenharmony_ci typedef std::vector<_test_descriptor> _tests; 578e5c31af7Sopenharmony_ci typedef _tests::const_iterator _tests_const_iterator; 579e5c31af7Sopenharmony_ci 580e5c31af7Sopenharmony_ci /* Initialize ES test objects */ 581e5c31af7Sopenharmony_ci initTest(); 582e5c31af7Sopenharmony_ci 583e5c31af7Sopenharmony_ci /* Describe test iterations */ 584e5c31af7Sopenharmony_ci _test_descriptor test_1; /* vs+tc+te+gs */ 585e5c31af7Sopenharmony_ci _test_descriptor test_2; /* vs+tc+te */ 586e5c31af7Sopenharmony_ci _test_descriptor test_3; /* vs+tc */ 587e5c31af7Sopenharmony_ci _tests tests; 588e5c31af7Sopenharmony_ci 589e5c31af7Sopenharmony_ci if (m_is_geometry_shader_extension_supported) 590e5c31af7Sopenharmony_ci { 591e5c31af7Sopenharmony_ci test_1.expected_data_source = m_glExtTokens.GEOMETRY_SHADER; 592e5c31af7Sopenharmony_ci test_1.expected_n_values = 2; 593e5c31af7Sopenharmony_ci test_1.should_draw_call_fail = false; 594e5c31af7Sopenharmony_ci test_1.requires_pipeline = false; 595e5c31af7Sopenharmony_ci test_1.tf_mode = GL_POINTS; 596e5c31af7Sopenharmony_ci test_1.use_gs = true; 597e5c31af7Sopenharmony_ci test_1.use_tc = true; 598e5c31af7Sopenharmony_ci test_1.use_te = true; 599e5c31af7Sopenharmony_ci 600e5c31af7Sopenharmony_ci tests.push_back(test_1); 601e5c31af7Sopenharmony_ci } 602e5c31af7Sopenharmony_ci 603e5c31af7Sopenharmony_ci test_2.expected_data_source = m_glExtTokens.TESS_EVALUATION_SHADER; 604e5c31af7Sopenharmony_ci test_2.expected_n_values = 2; 605e5c31af7Sopenharmony_ci test_2.should_draw_call_fail = false; 606e5c31af7Sopenharmony_ci test_2.requires_pipeline = false; 607e5c31af7Sopenharmony_ci test_2.tf_mode = GL_POINTS; 608e5c31af7Sopenharmony_ci test_2.use_gs = false; 609e5c31af7Sopenharmony_ci test_2.use_tc = true; 610e5c31af7Sopenharmony_ci test_2.use_te = true; 611e5c31af7Sopenharmony_ci 612e5c31af7Sopenharmony_ci tests.push_back(test_2); 613e5c31af7Sopenharmony_ci 614e5c31af7Sopenharmony_ci /* Note: This is a special negative case */ 615e5c31af7Sopenharmony_ci test_3.expected_data_source = m_glExtTokens.TESS_CONTROL_SHADER; 616e5c31af7Sopenharmony_ci test_3.expected_n_values = 4; 617e5c31af7Sopenharmony_ci if (!glu::isContextTypeES(m_context.getRenderContext().getType()) && isExtensionSupported("GL_NV_gpu_shader5")) 618e5c31af7Sopenharmony_ci { 619e5c31af7Sopenharmony_ci test_3.should_draw_call_fail = false; 620e5c31af7Sopenharmony_ci test_3.tf_mode = m_glExtTokens.PATCHES; 621e5c31af7Sopenharmony_ci } 622e5c31af7Sopenharmony_ci else 623e5c31af7Sopenharmony_ci { 624e5c31af7Sopenharmony_ci test_3.should_draw_call_fail = true; 625e5c31af7Sopenharmony_ci test_3.tf_mode = GL_POINTS; 626e5c31af7Sopenharmony_ci } 627e5c31af7Sopenharmony_ci test_3.requires_pipeline = true; 628e5c31af7Sopenharmony_ci test_3.use_gs = false; 629e5c31af7Sopenharmony_ci test_3.use_tc = true; 630e5c31af7Sopenharmony_ci test_3.use_te = false; 631e5c31af7Sopenharmony_ci 632e5c31af7Sopenharmony_ci tests.push_back(test_3); 633e5c31af7Sopenharmony_ci 634e5c31af7Sopenharmony_ci /* Use only one vertex per patch */ 635e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 636e5c31af7Sopenharmony_ci 637e5c31af7Sopenharmony_ci gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1); 638e5c31af7Sopenharmony_ci 639e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed."); 640e5c31af7Sopenharmony_ci 641e5c31af7Sopenharmony_ci /* This test runs in two iterations: 642e5c31af7Sopenharmony_ci * 643e5c31af7Sopenharmony_ci * 1) Shaders are attached to a program object at the beginning of 644e5c31af7Sopenharmony_ci * each test. The test then executes. Once it's completed, the 645e5c31af7Sopenharmony_ci * shaders are detached from the program object; 646e5c31af7Sopenharmony_ci * 2) A pipeline object is used instead of a program object. 647e5c31af7Sopenharmony_ci */ 648e5c31af7Sopenharmony_ci for (int n_iteration = 0; n_iteration < 2; ++n_iteration) 649e5c31af7Sopenharmony_ci { 650e5c31af7Sopenharmony_ci bool use_pipeline_object = (n_iteration == 1); 651e5c31af7Sopenharmony_ci 652e5c31af7Sopenharmony_ci if (use_pipeline_object) 653e5c31af7Sopenharmony_ci { 654e5c31af7Sopenharmony_ci gl.bindProgramPipeline(m_pipeline_id); 655e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed."); 656e5c31af7Sopenharmony_ci 657e5c31af7Sopenharmony_ci gl.useProgram(0); 658e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed"); 659e5c31af7Sopenharmony_ci } 660e5c31af7Sopenharmony_ci else 661e5c31af7Sopenharmony_ci { 662e5c31af7Sopenharmony_ci gl.bindProgramPipeline(0); 663e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed."); 664e5c31af7Sopenharmony_ci 665e5c31af7Sopenharmony_ci /* The program object will be shortly re-linked so defer the glUseProgram() call */ 666e5c31af7Sopenharmony_ci } 667e5c31af7Sopenharmony_ci 668e5c31af7Sopenharmony_ci /* Iterate through all tests */ 669e5c31af7Sopenharmony_ci for (_tests_const_iterator test_iterator = tests.begin(); test_iterator != tests.end(); test_iterator++) 670e5c31af7Sopenharmony_ci { 671e5c31af7Sopenharmony_ci const _test_descriptor& test = *test_iterator; 672e5c31af7Sopenharmony_ci 673e5c31af7Sopenharmony_ci if (use_pipeline_object) 674e5c31af7Sopenharmony_ci { 675e5c31af7Sopenharmony_ci /* Configure the pipeline object */ 676e5c31af7Sopenharmony_ci if (m_is_geometry_shader_extension_supported) 677e5c31af7Sopenharmony_ci { 678e5c31af7Sopenharmony_ci gl.useProgramStages(m_pipeline_id, m_glExtTokens.GEOMETRY_SHADER_BIT, 679e5c31af7Sopenharmony_ci test.use_gs ? m_gs_program_id : 0); 680e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_GEOMETRY_SHADER_BIT_EXT"); 681e5c31af7Sopenharmony_ci } 682e5c31af7Sopenharmony_ci 683e5c31af7Sopenharmony_ci gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT, 684e5c31af7Sopenharmony_ci test.use_tc ? m_tc_program_id : 0); 685e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_CONTROL_SHADER_BIT_EXT"); 686e5c31af7Sopenharmony_ci 687e5c31af7Sopenharmony_ci gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT, 688e5c31af7Sopenharmony_ci test.use_te ? m_te_program_id : 0); 689e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_EVALUATION_SHADER_BIT_EXT"); 690e5c31af7Sopenharmony_ci 691e5c31af7Sopenharmony_ci /* Validate the pipeline object */ 692e5c31af7Sopenharmony_ci gl.validateProgramPipeline(m_pipeline_id); 693e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() failed"); 694e5c31af7Sopenharmony_ci 695e5c31af7Sopenharmony_ci /* Retrieve the validation result */ 696e5c31af7Sopenharmony_ci glw::GLint validate_status = GL_FALSE; 697e5c31af7Sopenharmony_ci 698e5c31af7Sopenharmony_ci gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status); 699e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed"); 700e5c31af7Sopenharmony_ci 701e5c31af7Sopenharmony_ci if (validate_status == GL_FALSE && !test.should_draw_call_fail) 702e5c31af7Sopenharmony_ci { 703e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "A pipeline object consisting of: " 704e5c31af7Sopenharmony_ci << "[fragment stage] " << ((test.use_gs) ? "[geometry stage] " : "") 705e5c31af7Sopenharmony_ci << ((test.use_tc) ? "[tessellation control stage] " : "") 706e5c31af7Sopenharmony_ci << ((test.use_te) ? "[tessellation evaluation stage] " : "") << "[vertex stage] " 707e5c31af7Sopenharmony_ci << "was not validated successfully, even though it should." 708e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 709e5c31af7Sopenharmony_ci 710e5c31af7Sopenharmony_ci TCU_FAIL("Pipeline object is considered invalid, even though the stage combination is valid"); 711e5c31af7Sopenharmony_ci } 712e5c31af7Sopenharmony_ci } 713e5c31af7Sopenharmony_ci else 714e5c31af7Sopenharmony_ci { 715e5c31af7Sopenharmony_ci if (test.requires_pipeline) 716e5c31af7Sopenharmony_ci { 717e5c31af7Sopenharmony_ci continue; 718e5c31af7Sopenharmony_ci } 719e5c31af7Sopenharmony_ci 720e5c31af7Sopenharmony_ci /* Attach the shaders to the program object as described in 721e5c31af7Sopenharmony_ci * the test descriptor */ 722e5c31af7Sopenharmony_ci if (test.use_gs) 723e5c31af7Sopenharmony_ci { 724e5c31af7Sopenharmony_ci gl.attachShader(m_po_id, m_gs_id); 725e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach geometry shader"); 726e5c31af7Sopenharmony_ci } 727e5c31af7Sopenharmony_ci 728e5c31af7Sopenharmony_ci if (test.use_tc) 729e5c31af7Sopenharmony_ci { 730e5c31af7Sopenharmony_ci gl.attachShader(m_po_id, m_tc_id); 731e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation control shader"); 732e5c31af7Sopenharmony_ci } 733e5c31af7Sopenharmony_ci 734e5c31af7Sopenharmony_ci if (test.use_te) 735e5c31af7Sopenharmony_ci { 736e5c31af7Sopenharmony_ci gl.attachShader(m_po_id, m_te_id); 737e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation evaluation shader"); 738e5c31af7Sopenharmony_ci } 739e5c31af7Sopenharmony_ci 740e5c31af7Sopenharmony_ci /* Link the program object */ 741e5c31af7Sopenharmony_ci gl.linkProgram(m_po_id); 742e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not link program object"); 743e5c31af7Sopenharmony_ci 744e5c31af7Sopenharmony_ci /* Has the linking succeeded? */ 745e5c31af7Sopenharmony_ci glw::GLint link_status = GL_FALSE; 746e5c31af7Sopenharmony_ci 747e5c31af7Sopenharmony_ci gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); 748e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); 749e5c31af7Sopenharmony_ci 750e5c31af7Sopenharmony_ci if (link_status != GL_TRUE) 751e5c31af7Sopenharmony_ci { 752e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "A program object consisting of: " 753e5c31af7Sopenharmony_ci << "[fragment shader] " << ((test.use_gs) ? "[geometry shader] " : "") 754e5c31af7Sopenharmony_ci << ((test.use_tc) ? "[tessellation control shader] " : "") 755e5c31af7Sopenharmony_ci << ((test.use_te) ? "[tessellation evaluation shader] " : "") 756e5c31af7Sopenharmony_ci << "[vertex shader] " 757e5c31af7Sopenharmony_ci << "failed to link, even though it should link successfully." 758e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 759e5c31af7Sopenharmony_ci 760e5c31af7Sopenharmony_ci TCU_FAIL("Program linking failed, even though the shader combination was valid"); 761e5c31af7Sopenharmony_ci } 762e5c31af7Sopenharmony_ci 763e5c31af7Sopenharmony_ci gl.useProgram(m_po_id); 764e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed."); 765e5c31af7Sopenharmony_ci } 766e5c31af7Sopenharmony_ci 767e5c31af7Sopenharmony_ci /* Render a single point */ 768e5c31af7Sopenharmony_ci gl.enable(GL_RASTERIZER_DISCARD); 769e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed"); 770e5c31af7Sopenharmony_ci 771e5c31af7Sopenharmony_ci gl.beginTransformFeedback(test.tf_mode); 772e5c31af7Sopenharmony_ci 773e5c31af7Sopenharmony_ci bool didBeginXFBFail = false; 774e5c31af7Sopenharmony_ci if (!test.should_draw_call_fail) 775e5c31af7Sopenharmony_ci { 776e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed"); 777e5c31af7Sopenharmony_ci } 778e5c31af7Sopenharmony_ci else 779e5c31af7Sopenharmony_ci { 780e5c31af7Sopenharmony_ci /* For the negative case, i.e. beginTransformFeedback with an invalid pipeline of {VS, TCS, FS}, 781e5c31af7Sopenharmony_ci * ES spec is not clear if beginTransformFeedback should error, so relax the requirment here so 782e5c31af7Sopenharmony_ci * that test passes as long as either beginTransformFeedback or the next draw call raises 783e5c31af7Sopenharmony_ci * INVALID_OPERATION */ 784e5c31af7Sopenharmony_ci glw::GLint err = gl.getError(); 785e5c31af7Sopenharmony_ci if (err == GL_INVALID_OPERATION) 786e5c31af7Sopenharmony_ci { 787e5c31af7Sopenharmony_ci didBeginXFBFail = true; 788e5c31af7Sopenharmony_ci } 789e5c31af7Sopenharmony_ci else if (err != GL_NO_ERROR) 790e5c31af7Sopenharmony_ci { 791e5c31af7Sopenharmony_ci TCU_FAIL("Unexpected GL error in a beginTransformFeedback made on the program pipeline whose" 792e5c31af7Sopenharmony_ci "program closest to TFB has no output varying specified"); 793e5c31af7Sopenharmony_ci } 794e5c31af7Sopenharmony_ci } 795e5c31af7Sopenharmony_ci 796e5c31af7Sopenharmony_ci { 797e5c31af7Sopenharmony_ci gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */); 798e5c31af7Sopenharmony_ci 799e5c31af7Sopenharmony_ci if (!test.should_draw_call_fail) 800e5c31af7Sopenharmony_ci { 801e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed"); 802e5c31af7Sopenharmony_ci } 803e5c31af7Sopenharmony_ci else 804e5c31af7Sopenharmony_ci { 805e5c31af7Sopenharmony_ci if (gl.getError() != GL_INVALID_OPERATION && !didBeginXFBFail) 806e5c31af7Sopenharmony_ci { 807e5c31af7Sopenharmony_ci TCU_FAIL("A draw call made using a program object lacking TES stage has" 808e5c31af7Sopenharmony_ci " not generated a GL_INVALID_OPERATION as specified"); 809e5c31af7Sopenharmony_ci } 810e5c31af7Sopenharmony_ci } 811e5c31af7Sopenharmony_ci } 812e5c31af7Sopenharmony_ci gl.endTransformFeedback(); 813e5c31af7Sopenharmony_ci 814e5c31af7Sopenharmony_ci if (!didBeginXFBFail) 815e5c31af7Sopenharmony_ci { 816e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed"); 817e5c31af7Sopenharmony_ci } 818e5c31af7Sopenharmony_ci else 819e5c31af7Sopenharmony_ci { 820e5c31af7Sopenharmony_ci if (gl.getError() != GL_INVALID_OPERATION) 821e5c31af7Sopenharmony_ci { 822e5c31af7Sopenharmony_ci TCU_FAIL("An endTransformFeedback made on inactive xfb has not generated a " 823e5c31af7Sopenharmony_ci "GL_INVALID_OPERATION as specified"); 824e5c31af7Sopenharmony_ci } 825e5c31af7Sopenharmony_ci } 826e5c31af7Sopenharmony_ci 827e5c31af7Sopenharmony_ci gl.disable(GL_RASTERIZER_DISCARD); 828e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed"); 829e5c31af7Sopenharmony_ci 830e5c31af7Sopenharmony_ci if (!test.should_draw_call_fail) 831e5c31af7Sopenharmony_ci { 832e5c31af7Sopenharmony_ci /* Retrieve the captured result values */ 833e5c31af7Sopenharmony_ci glw::GLfloat* result_ptr = (glw::GLfloat*)gl.mapBufferRange( 834e5c31af7Sopenharmony_ci GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 835e5c31af7Sopenharmony_ci sizeof(float) * 4 /* components */ * test.expected_n_values, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); 836e5c31af7Sopenharmony_ci 837e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed"); 838e5c31af7Sopenharmony_ci 839e5c31af7Sopenharmony_ci /* Verify the data */ 840e5c31af7Sopenharmony_ci const glw::GLfloat epsilon = (glw::GLfloat)1e-5; 841e5c31af7Sopenharmony_ci const glw::GLfloat expected_gs_data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; 842e5c31af7Sopenharmony_ci const glw::GLfloat expected_tc_data[] = { 2.0f, 3.0f, 4.0f, 5.0f }; 843e5c31af7Sopenharmony_ci const glw::GLfloat expected_te_data[] = { 3.0f, 4.0f, 5.0f, 6.0f }; 844e5c31af7Sopenharmony_ci const glw::GLfloat expected_vs_data[] = { 4.0f, 5.0f, 6.0f, 7.0f }; 845e5c31af7Sopenharmony_ci 846e5c31af7Sopenharmony_ci for (int n_value = 0; n_value < test.expected_n_values; ++n_value) 847e5c31af7Sopenharmony_ci { 848e5c31af7Sopenharmony_ci const glw::GLfloat* expected_data_ptr = NULL; 849e5c31af7Sopenharmony_ci const glw::GLfloat* captured_data_ptr = result_ptr + n_value * 4 /* components */; 850e5c31af7Sopenharmony_ci 851e5c31af7Sopenharmony_ci if (test.expected_data_source == m_glExtTokens.GEOMETRY_SHADER) 852e5c31af7Sopenharmony_ci { 853e5c31af7Sopenharmony_ci expected_data_ptr = expected_gs_data; 854e5c31af7Sopenharmony_ci } 855e5c31af7Sopenharmony_ci else if (test.expected_data_source == m_glExtTokens.TESS_CONTROL_SHADER) 856e5c31af7Sopenharmony_ci { 857e5c31af7Sopenharmony_ci expected_data_ptr = expected_tc_data; 858e5c31af7Sopenharmony_ci } 859e5c31af7Sopenharmony_ci else if (test.expected_data_source == m_glExtTokens.TESS_EVALUATION_SHADER) 860e5c31af7Sopenharmony_ci { 861e5c31af7Sopenharmony_ci expected_data_ptr = expected_te_data; 862e5c31af7Sopenharmony_ci } 863e5c31af7Sopenharmony_ci else if (test.expected_data_source == GL_VERTEX_SHADER) 864e5c31af7Sopenharmony_ci { 865e5c31af7Sopenharmony_ci expected_data_ptr = expected_vs_data; 866e5c31af7Sopenharmony_ci } 867e5c31af7Sopenharmony_ci else 868e5c31af7Sopenharmony_ci { 869e5c31af7Sopenharmony_ci TCU_FAIL("Unrecognized expected data source"); 870e5c31af7Sopenharmony_ci } 871e5c31af7Sopenharmony_ci 872e5c31af7Sopenharmony_ci if (de::abs(captured_data_ptr[0] - expected_data_ptr[0]) > epsilon || 873e5c31af7Sopenharmony_ci de::abs(captured_data_ptr[1] - expected_data_ptr[1]) > epsilon || 874e5c31af7Sopenharmony_ci de::abs(captured_data_ptr[2] - expected_data_ptr[2]) > epsilon || 875e5c31af7Sopenharmony_ci de::abs(captured_data_ptr[3] - expected_data_ptr[3]) > epsilon) 876e5c31af7Sopenharmony_ci { 877e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Captured data " 878e5c31af7Sopenharmony_ci << "(" << captured_data_ptr[0] << ", " << captured_data_ptr[1] << ", " 879e5c31af7Sopenharmony_ci << captured_data_ptr[2] << ", " << captured_data_ptr[3] << ")" 880e5c31af7Sopenharmony_ci << "is different from the expected value " 881e5c31af7Sopenharmony_ci << "(" << expected_data_ptr[0] << ", " << expected_data_ptr[1] << ", " 882e5c31af7Sopenharmony_ci << expected_data_ptr[2] << ", " << expected_data_ptr[3] << ")" 883e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 884e5c31af7Sopenharmony_ci 885e5c31af7Sopenharmony_ci TCU_FAIL("Invalid data captured"); 886e5c31af7Sopenharmony_ci } 887e5c31af7Sopenharmony_ci } 888e5c31af7Sopenharmony_ci 889e5c31af7Sopenharmony_ci /* Unmap the buffer object, since we're done */ 890e5c31af7Sopenharmony_ci memset(result_ptr, 0, sizeof(float) * 4 /* components */ * test.expected_n_values); 891e5c31af7Sopenharmony_ci 892e5c31af7Sopenharmony_ci gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 893e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed"); 894e5c31af7Sopenharmony_ci } /* if (!test.should_draw_call_fail) */ 895e5c31af7Sopenharmony_ci 896e5c31af7Sopenharmony_ci if (!use_pipeline_object) 897e5c31af7Sopenharmony_ci { 898e5c31af7Sopenharmony_ci /* Detach all shaders we attached to the program object at the beginning 899e5c31af7Sopenharmony_ci * of the iteration */ 900e5c31af7Sopenharmony_ci if (test.use_gs) 901e5c31af7Sopenharmony_ci { 902e5c31af7Sopenharmony_ci gl.detachShader(m_po_id, m_gs_id); 903e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach geometry shader"); 904e5c31af7Sopenharmony_ci } 905e5c31af7Sopenharmony_ci 906e5c31af7Sopenharmony_ci if (test.use_tc) 907e5c31af7Sopenharmony_ci { 908e5c31af7Sopenharmony_ci gl.detachShader(m_po_id, m_tc_id); 909e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation control shader"); 910e5c31af7Sopenharmony_ci } 911e5c31af7Sopenharmony_ci 912e5c31af7Sopenharmony_ci if (test.use_te) 913e5c31af7Sopenharmony_ci { 914e5c31af7Sopenharmony_ci gl.detachShader(m_po_id, m_te_id); 915e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation evaluation shader"); 916e5c31af7Sopenharmony_ci } 917e5c31af7Sopenharmony_ci 918e5c31af7Sopenharmony_ci } /* if (!use_pipeline_object) */ 919e5c31af7Sopenharmony_ci else 920e5c31af7Sopenharmony_ci { 921e5c31af7Sopenharmony_ci /* We don't need to do anything with the pipeline object - stages will be 922e5c31af7Sopenharmony_ci * re-defined in next iteration */ 923e5c31af7Sopenharmony_ci } 924e5c31af7Sopenharmony_ci } /* for (all tests) */ 925e5c31af7Sopenharmony_ci } /* for (all iterations) */ 926e5c31af7Sopenharmony_ci 927e5c31af7Sopenharmony_ci /* All done */ 928e5c31af7Sopenharmony_ci m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 929e5c31af7Sopenharmony_ci return STOP; 930e5c31af7Sopenharmony_ci} 931e5c31af7Sopenharmony_ci 932e5c31af7Sopenharmony_ci} /* namespace glcts */ 933