/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2015-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 "esextcGeometryShaderAPI.hpp" #include "gluDefs.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuTestLog.hpp" #include namespace glcts { static const char* dummy_fs_code = "${VERSION}\n" "\n" "precision highp float;\n" "\n" "out vec4 result;\n" "\n" "void main()\n" "{\n" " result = vec4(1.0);\n" "}\n"; static const char* dummy_gs_code = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${OUT_PER_VERTEX_DECL}" "${IN_DATA_DECL}" "void main()\n" "{\n" "${POSITION_WITH_IN_DATA}" " EmitVertex();\n" "}\n"; static const char* dummy_vs_code = "${VERSION}\n" "\n" "${OUT_PER_VERTEX_DECL}" "\n" "void main()\n" "{\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; /* createShaderProgramv conformance test shaders */ const char* GeometryShaderCreateShaderProgramvTest::fs_code = "${VERSION}\n" "\n" "precision highp float;\n" "\n" "out vec4 result;\n" "\n" "void main()\n" "{\n" " result = vec4(0.0, 1.0, 0.0, 0.0);\n" "}\n"; const char* GeometryShaderCreateShaderProgramvTest::gs_code = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (triangle_strip, max_vertices = 4) out;\n" "\n" "${OUT_PER_VERTEX_DECL}" "\n" "void main()\n" "{\n" " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" " EmitVertex();\n" "\n" " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" " EmitVertex();\n" "\n" " gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n" " EmitVertex();\n" "\n" " gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n" " EmitVertex();\n" " EndPrimitive();\n" "}\n"; const char* GeometryShaderCreateShaderProgramvTest::vs_code = "${VERSION}\n" "\n" "${OUT_PER_VERTEX_DECL}" "\n" "void main()\n" "{\n" " gl_Position = vec4(-10.0, -10.0, -10.0, 0.0);\n" "}\n"; const unsigned int GeometryShaderCreateShaderProgramvTest::m_to_height = 4; const unsigned int GeometryShaderCreateShaderProgramvTest::m_to_width = 4; /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderCreateShaderProgramvTest::GeometryShaderCreateShaderProgramvTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fbo_id(0) , m_fs_po_id(0) , m_gs_po_id(0) , m_pipeline_object_id(0) , m_to_id(0) , m_vao_id(0) , m_vs_po_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderCreateShaderProgramvTest::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_po_id != 0) { gl.deleteProgram(m_fs_po_id); m_fs_po_id = 0; } if (m_gs_po_id != 0) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } if (m_pipeline_object_id != 0) { gl.deleteProgramPipelines(1, &m_pipeline_object_id); m_pipeline_object_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_po_id != 0) { gl.deleteProgram(m_vs_po_id); m_vs_po_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Initializes a framebuffer object used by the conformance test. */ void GeometryShaderCreateShaderProgramvTest::initFBO() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Generate a FBO */ gl.genFramebuffers(1, &m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed."); /* Generate a TO */ gl.genTextures(1, &m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); /* Set the TO up */ gl.bindTexture(GL_TEXTURE_2D, m_to_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ GL_RGBA8, m_to_width, m_to_height); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); /* Set up the FBO */ gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */ GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); /* Set up the viewport */ gl.viewport(0, /* x */ 0, /* y */ m_to_width, m_to_height); GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed."); } /* Initializes a pipeline object used by the conformance test */ void GeometryShaderCreateShaderProgramvTest::initPipelineObject() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); DE_ASSERT(m_fs_po_id != 0 && m_gs_po_id != 0 && m_vs_po_id != 0); gl.genProgramPipelines(1, &m_pipeline_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed."); gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id); gl.useProgramStages(m_pipeline_object_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id); gl.useProgramStages(m_pipeline_object_id, GL_VERTEX_SHADER_BIT, m_vs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed."); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderCreateShaderProgramvTest::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); const unsigned int n_so_po_ids = 3; bool result = true; glw::GLuint so_po_ids[n_so_po_ids]; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Initialize off-screen rendering */ initFBO(); /* Form shader sources */ std::string fs_specialized_code = specializeShader(1, /* parts */ &fs_code); const char* fs_specialized_code_raw = fs_specialized_code.c_str(); std::string gs_specialized_code = specializeShader(1, /* parts */ &gs_code); const char* gs_specialized_code_raw = gs_specialized_code.c_str(); std::string vs_specialized_code = specializeShader(1, /* parts */ &vs_code); const char* vs_specialized_code_raw = vs_specialized_code.c_str(); /* Try to create an invalid geometry shader program first */ glw::GLint link_status = GL_TRUE; m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */ &gs_code); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed."); if (m_gs_po_id == 0) { m_testCtx.getLog() << tcu::TestLog::Message << "glCreateShaderProgramv() call returned 0." << tcu::TestLog::EndMessage; result = false; goto end; } gl.getProgramiv(m_gs_po_id, GL_LINK_STATUS, &link_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); if (link_status != GL_FALSE) { m_testCtx.getLog() << tcu::TestLog::Message << "An invalid shader program was linked successfully." << tcu::TestLog::EndMessage; result = false; goto end; } gl.deleteProgram(m_gs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed."); /* Create shader programs */ m_fs_po_id = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, /* count */ &fs_specialized_code_raw); m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */ &gs_specialized_code_raw); m_vs_po_id = gl.createShaderProgramv(GL_VERTEX_SHADER, 1, /* count */ &vs_specialized_code_raw); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call(s) failed."); if (m_fs_po_id == 0 || m_gs_po_id == 0 || m_vs_po_id == 0) { m_testCtx.getLog() << tcu::TestLog::Message << "At least one glCreateShaderProgramv() call returned 0." << tcu::TestLog::EndMessage; result = false; goto end; } /* Make sure all shader programs were linked successfully */ so_po_ids[0] = m_fs_po_id; so_po_ids[1] = m_gs_po_id; so_po_ids[2] = m_vs_po_id; for (unsigned int n_po_id = 0; n_po_id != n_so_po_ids; ++n_po_id) { gl.getProgramiv(so_po_ids[n_po_id], GL_LINK_STATUS, &link_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); if (link_status != GL_TRUE) { m_testCtx.getLog() << tcu::TestLog::Message << "A valid shader program with id [" << so_po_ids[n_po_id] << "] was not linked successfully." << tcu::TestLog::EndMessage; result = false; goto end; } } /* Set up the vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Set up the pipeline object */ initPipelineObject(); /* Render a full-screen quad */ gl.bindProgramPipeline(m_pipeline_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed."); gl.drawArrays(GL_POINTS, 0, /* first */ 1); /* count */ GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); /* Verify the rendering result */ unsigned char result_data[m_to_width * m_to_height * 4 /* rgba */]; gl.readPixels(0, /* x */ 0, /* y */ m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, result_data); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); for (unsigned int y = 0; y < m_to_height; ++y) { unsigned char* traveller_ptr = result_data + 4 * y; for (unsigned int x = 0; x < m_to_width; ++x) { if (traveller_ptr[0] != 0 || traveller_ptr[1] != 255 || traveller_ptr[2] != 0 || traveller_ptr[3] != 0) { m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result texel found at (" << x << ", " << y << ")." << tcu::TestLog::EndMessage; result = false; } traveller_ptr += 4; /* rgba */ } } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderGetShaderivTest::GeometryShaderGetShaderivTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description), m_gs_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderGetShaderivTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_gs_id != 0) { gl.deleteShader(m_gs_id); m_gs_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderGetShaderivTest::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bool result = true; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Create a GS */ m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); /* Check the type reported for the SO */ glw::GLint shader_type = GL_NONE; gl.getShaderiv(m_gs_id, GL_SHADER_TYPE, &shader_type); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); if ((glw::GLenum)shader_type != m_glExtTokens.GEOMETRY_SHADER) { m_testCtx.getLog() << tcu::TestLog::Message << "Invalid shader type [" << shader_type << "] reported for a Geometry Shader" << tcu::TestLog::EndMessage; result = false; } if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderGetProgramivTest::GeometryShaderGetProgramivTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description), m_po_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderGetProgramivTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderGetProgramivTest::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bool result = true; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Create a program object */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Verify that GS-specific queries cause a GL_INVALID_OPERATION error */ const glw::GLenum pnames[] = { m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE, m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE, m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS }; const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]); for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname) { glw::GLenum error_code = GL_NO_ERROR; glw::GLenum pname = pnames[n_pname]; glw::GLint rv = -1; gl.getProgramiv(m_po_id, pname, &rv); error_code = gl.getError(); if (error_code != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "No error generated by glGetProgramiv() for pname [" << pname << "]" << tcu::TestLog::EndMessage; result = false; } } /* for (all pnames) */ if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderGetProgramiv2Test::GeometryShaderGetProgramiv2Test(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description), m_fs_id(0), m_po_id(0), m_vs_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderGetProgramiv2Test::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_id != 0) { gl.deleteShader(m_fs_id); m_fs_id = 0; } if (m_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } if (m_vs_id != 0) { gl.deleteShader(m_vs_id); m_vs_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderGetProgramiv2Test::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); const glw::GLenum pnames[] = { m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE, m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE, m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS }; const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]); bool result = true; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Initialize the program object */ std::string specialized_dummy_fs = specializeShader(1, /* parts */ &dummy_fs_code); const char* specialized_dummy_fs_raw = specialized_dummy_fs.c_str(); std::string specialized_dummy_vs = specializeShader(1, /* parts */ &dummy_vs_code); const char* specialized_dummy_vs_raw = specialized_dummy_vs.c_str(); m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); if (!TestCaseBase::buildProgram(m_po_id, m_fs_id, 1, &specialized_dummy_fs_raw, m_vs_id, 1, &specialized_dummy_vs_raw)) { m_testCtx.getLog() << tcu::TestLog::Message << "Failed to build a dummy test program object" << tcu::TestLog::EndMessage; result = false; goto end; } /* Verify that GS-specific queries cause a GL_INVALID_OPERATION error * for a linked PO lacking the GS stage. */ for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname) { glw::GLenum error_code = GL_NO_ERROR; glw::GLenum pname = pnames[n_pname]; glw::GLint rv = -1; gl.getProgramiv(m_po_id, pname, &rv); error_code = gl.getError(); if (error_code != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "No error generated by glGetProgramiv() for pname [" << pname << "]" << tcu::TestLog::EndMessage; result = false; } } /* for (all pnames) */ end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderGetProgramiv3Test::GeometryShaderGetProgramiv3Test(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_id(0) , m_fs_po_id(0) , m_gs_id(0) , m_gs_po_id(0) , m_pipeline_object_id(0) , m_po_id(0) , m_vs_id(0) , m_vs_po_id(0) { } /* Compiles a shader object using caller-specified data. * * @param so_id ID of a Shader Object to compile. * @param so_body Body to use for the compilation process. * * @return true if the compilation succeeded, false otherwise */ bool GeometryShaderGetProgramiv3Test::buildShader(glw::GLuint so_id, const char* so_body) { glw::GLint compile_status = GL_FALSE; const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bool result = false; gl.shaderSource(so_id, 1, /* count */ &so_body, DE_NULL); /* length */ GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); gl.compileShader(so_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); result = (compile_status == GL_TRUE); return result; } /** Builds a single shader program object using caller-specified data. * * @param out_spo_id Deref will be set to the ID of the created shader program object. * Must not be NULL. * @param spo_bits Bits to be passed to the glCreateShaderProgramv() call. * @param spo_body Body to use for the glCreateShaderProgramv() call. * * @return true if the shader program object was linked successfully, false otherwise. */ bool GeometryShaderGetProgramiv3Test::buildShaderProgram(glw::GLuint* out_spo_id, glw::GLenum spo_bits, const char* spo_body) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint link_status = GL_FALSE; bool result = true; *out_spo_id = gl.createShaderProgramv(spo_bits, 1, /* count */ &spo_body); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed."); gl.getProgramiv(*out_spo_id, GL_LINK_STATUS, &link_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); result = (link_status == GL_TRUE); return result; } /** Deinitializes GLES objects created during the test. */ void GeometryShaderGetProgramiv3Test::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); deinitPO(); deinitSOs(true); deinitSPOs(true); if (m_pipeline_object_id != 0) { gl.deleteProgramPipelines(1, &m_pipeline_object_id); m_pipeline_object_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Deinitializes a program object created for the conformance test. */ void GeometryShaderGetProgramiv3Test::deinitPO() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } } /** Deinitializes shader objects created for the conformance test. */ void GeometryShaderGetProgramiv3Test::deinitSOs(bool release_all_SOs) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_id != 0 && release_all_SOs) { 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_vs_id != 0 && release_all_SOs) { gl.deleteShader(m_vs_id); m_vs_id = 0; } } /** Deinitializes shader program objects created for the conformance test. */ void GeometryShaderGetProgramiv3Test::deinitSPOs(bool release_all_SPOs) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_po_id != 0 && release_all_SPOs) { gl.deleteProgram(m_fs_po_id); m_fs_po_id = 0; } if (m_gs_po_id != 0) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } if (m_vs_po_id != 0 && release_all_SPOs) { gl.deleteProgram(m_vs_po_id); m_vs_po_id = 0; } } /** Retrieves ES SL layout qualifier, corresponding to user-specified * primitive type. * * @param primitive_type Primitive type (described by a GLenum value) * to use for the query. * * @return Requested layout qualifier. */ std::string GeometryShaderGetProgramiv3Test::getLayoutQualifierForPrimitiveType(glw::GLenum primitive_type) { std::string result; switch (primitive_type) { case GL_LINE_STRIP: result = "line_strip"; break; case GL_LINES_ADJACENCY: result = "lines_adjacency"; break; case GL_POINTS: result = "points"; break; case GL_TRIANGLES: result = "triangles"; break; case GL_TRIANGLE_STRIP: result = "triangle_strip"; break; default: { DE_ASSERT(0); } } /* switch (primitive_type) */ return result; } /** Retrieves body of a geometry shadet to be used for the conformance test. * The body is generated, according to the properties described by the * run descriptor passed as an argument. * * @param run Test run descriptor. * * @return Requested string. */ std::string GeometryShaderGetProgramiv3Test::getGSCode(const _run& run) { std::stringstream code_sstream; code_sstream << "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout(" << getLayoutQualifierForPrimitiveType(run.input_primitive_type) << ", " "invocations = " << run.invocations << ") in;\n" "layout(" << getLayoutQualifierForPrimitiveType(run.output_primitive_type) << ", " "max_vertices = " << run.max_vertices << ") out;\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "\n" "void main()\n" "{\n" " for (int n = 0; n < " << run.max_vertices << "; ++n)\n" " {\n" " gl_Position = vec4(n, 0.0, 0.0, 1.0);\n" " EmitVertex();\n" " }\n" "\n" " EndPrimitive();\n" "}\n"; return code_sstream.str(); } /** Initializes internal _runs member with test iteration settings for all test runs. */ void GeometryShaderGetProgramiv3Test::initTestRuns() { /* input primitive type | invocations | max vertices | output primitive type * *----------------------------------------+-------------+--------------+-----------------------*/ _runs.push_back(_run(GL_LINES_ADJACENCY, 3, 16, GL_POINTS)); _runs.push_back(_run(GL_TRIANGLES, 12, 37, GL_LINE_STRIP)); _runs.push_back(_run(GL_POINTS, 31, 75, GL_TRIANGLE_STRIP)); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderGetProgramiv3Test::iterate() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint gs_spo_id = 0; unsigned int n_run = 0; unsigned int n_separable_object_case = 0; bool result = true; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Prepare specialized versions of dummy fragment & vertex shaders */ std::string dummy_fs_specialized = specializeShader(1, /* parts */ &dummy_fs_code); const char* dummy_fs_specialized_raw = dummy_fs_specialized.c_str(); std::string dummy_vs_specialized = specializeShader(1, &dummy_vs_code); const char* dummy_vs_specialized_raw = dummy_vs_specialized.c_str(); /* Set up the fragment & the vertex shaders */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); if (!buildShader(m_fs_id, dummy_fs_specialized_raw) || !buildShader(m_vs_id, dummy_vs_specialized_raw)) { m_testCtx.getLog() << tcu::TestLog::Message << "Either FS or VS failed to build." << tcu::TestLog::EndMessage; result = false; goto end; } /* Set up the test program object */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); gl.attachShader(m_po_id, m_fs_id); gl.attachShader(m_po_id, m_gs_id); gl.attachShader(m_po_id, m_vs_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); /* Set up the fragment & the vertex shader programs */ if (!buildShaderProgram(&m_fs_po_id, GL_FRAGMENT_SHADER, dummy_fs_specialized_raw) || !buildShaderProgram(&m_vs_po_id, GL_VERTEX_SHADER, dummy_vs_specialized_raw)) { m_testCtx.getLog() << tcu::TestLog::Message << "Either FS or VS SPOs failed to build." << tcu::TestLog::EndMessage; result = false; goto end; } /* Set up test runs */ initTestRuns(); /* The test should check both a geometry shader program object and a full-blown PO * consisting of FS, GS and VS. */ for (n_separable_object_case = 0; n_separable_object_case < 2; /* PO, SPO cases */ ++n_separable_object_case) { bool should_use_separable_object = (n_separable_object_case != 0); /* Iterate over all test runs */ for (n_run = 0; n_run < _runs.size(); ++n_run) { const _run& current_run = _runs[n_run]; std::string gs_code = getGSCode(current_run); const char* gs_code_raw = gs_code.c_str(); std::string gs_code_specialized = specializeShader(1, /* parts */ &gs_code_raw); const char* gs_code_specialized_raw = gs_code_specialized.c_str(); if (should_use_separable_object) { /* Deinitialize any objects that may have been created in previous iterations */ deinitSPOs(false); /* Set up the geometry shader program object */ if (!buildShaderProgram(&m_gs_po_id, GL_GEOMETRY_SHADER, gs_code_specialized_raw)) { m_testCtx.getLog() << tcu::TestLog::Message << "Failed to compile a geometry shader program object" << tcu::TestLog::EndMessage; result = false; goto end; } } /* if (should_use_pipeline_object) */ else { gl.bindProgramPipeline(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed."); /* Set up the geometry shader object */ if (!buildShader(m_gs_id, gs_code_specialized_raw)) { m_testCtx.getLog() << tcu::TestLog::Message << "Failed to compile a geometry shader object." << tcu::TestLog::EndMessage; result = false; goto end; } /* Set up the program object */ glw::GLint link_status = GL_FALSE; gl.linkProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); if (link_status == GL_FALSE) { m_testCtx.getLog() << tcu::TestLog::Message << "Test program object failed to link" << tcu::TestLog::EndMessage; result = false; goto end; } /* Bind the PO to the rendering context */ gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); } /* Execute the queries */ glw::GLuint po_id = (should_use_separable_object) ? m_gs_po_id : m_po_id; glw::GLint result_geometry_linked_vertices_out = 0; glw::GLint result_geometry_linked_input_type = 0; glw::GLint result_geometry_linked_output_type = 0; glw::GLint result_geometry_shader_invocations = 0; gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, &result_geometry_linked_vertices_out); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed for GL_GEOMETRY_LINKED_VERTICES_OUT_EXT query."); gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE, &result_geometry_linked_input_type); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed for GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query."); gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE, &result_geometry_linked_output_type); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed for GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT query."); gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS, &result_geometry_shader_invocations); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed for GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query."); if (current_run.input_primitive_type != (glw::GLenum)result_geometry_linked_input_type) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query value " << "[" << result_geometry_linked_input_type << "]" " does not match the test run setting " "[" << current_run.input_primitive_type << "]" << tcu::TestLog::EndMessage; result = false; } if (current_run.invocations != result_geometry_shader_invocations) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_SHADER_INVOCATIONS_EXT query value " << "[" << result_geometry_shader_invocations << "]" " does not match the test run setting " "[" << current_run.input_primitive_type << "]" << tcu::TestLog::EndMessage; result = false; } if (current_run.max_vertices != result_geometry_linked_vertices_out) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_VERTICES_OUT query value " << "[" << result_geometry_linked_vertices_out << "]" " does not match the test run setting " "[" << current_run.max_vertices << "]" << tcu::TestLog::EndMessage; result = false; } if (current_run.output_primitive_type != (glw::GLenum)result_geometry_linked_output_type) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT query value " << "[" << result_geometry_linked_output_type << "]" " does not match the test run setting " "[" << current_run.output_primitive_type << "]" << tcu::TestLog::EndMessage; result = false; } } /* for (all test runs) */ } /* for (PO & SPO cases) */ /* One more check: build a pipeline object which only defines a FS & VS stages, * and check what GS SPO ID the object reports. */ gl.genProgramPipelines(1, &m_pipeline_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed."); gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id); gl.useProgramStages(m_pipeline_object_id, GL_VERTEX_SHADER_BIT, m_vs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed."); gl.getProgramPipelineiv(m_pipeline_object_id, m_glExtTokens.GEOMETRY_SHADER, &gs_spo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed."); if (gs_spo_id != 0) { m_testCtx.getLog() << tcu::TestLog::Message << "Pipeline object reported [" << gs_spo_id << "]" << " for GL_GEOMETRY_SHADER_EXT query, even though no GS SPO was bound." << tcu::TestLog::EndMessage; result = false; } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderDrawCallWithFSAndGS::GeometryShaderDrawCallWithFSAndGS(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_po_id(0) , m_gs_po_id(0) , m_pipeline_object_id(0) , m_vao_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderDrawCallWithFSAndGS::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_po_id != 0) { gl.deleteProgram(m_fs_po_id); m_fs_po_id = 0; } if (m_gs_po_id != 0) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } if (m_pipeline_object_id != 0) { gl.deleteProgramPipelines(1, &m_pipeline_object_id); m_pipeline_object_id = 0; } if (m_vao_id != 0) { gl.deleteVertexArrays(1, &m_vao_id); m_vao_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderDrawCallWithFSAndGS::iterate() { glw::GLenum error_code = GL_NO_ERROR; const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bool result = true; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Create & bind a VAO */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Create shader program objects */ std::string code_fs_specialized = specializeShader(1, /* parts */ &dummy_fs_code); const char* code_fs_specialized_raw = code_fs_specialized.c_str(); std::string code_gs_specialized = specializeShader(1, /* parts */ &dummy_gs_code); const char* code_gs_specialized_raw = code_gs_specialized.c_str(); glw::GLint link_status = GL_FALSE; m_fs_po_id = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, /* count */ &code_fs_specialized_raw); m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */ &code_gs_specialized_raw); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call(s) failed."); gl.getProgramiv(m_fs_po_id, GL_LINK_STATUS, &link_status); if (link_status != GL_TRUE) { m_testCtx.getLog() << tcu::TestLog::Message << "Dummy fragment shader program failed to link." << tcu::TestLog::EndMessage; result = false; goto end; } gl.getProgramiv(m_gs_po_id, GL_LINK_STATUS, &link_status); if (link_status != GL_TRUE) { m_testCtx.getLog() << tcu::TestLog::Message << "Dummy geometry shader program failed to link." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create & set up a pipeline object */ gl.genProgramPipelines(1, &m_pipeline_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed."); gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id); gl.useProgramStages(m_pipeline_object_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed."); gl.bindProgramPipeline(m_pipeline_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed."); /* Try to do a draw call */ gl.drawArrays(GL_POINTS, 0, /* first */ 1); /* count */ error_code = gl.getError(); if (error_code != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "Invalid draw call generated an error code [" << error_code << "]" " which is different from the expected GL_INVALID_OPERATION." << tcu::TestLog::EndMessage; result = false; } end: // m_pipeline_object_id is generated in this function, need to be freed if (m_pipeline_object_id) { gl.deleteProgramPipelines(1, &m_pipeline_object_id); m_pipeline_object_id = 0; } // m_gs_po_id is generated in this function, need to be freed if (m_gs_po_id) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } // m_fs_po_id is generated in this function, need to be freed if (m_fs_po_id) { gl.deleteProgram(m_fs_po_id); m_fs_po_id = 0; } // m_vao_id is generated in this function, need to be freed if (m_vao_id) { gl.deleteVertexArrays(1, &m_vao_id); m_vao_id = 0; } /* All done */ if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderMaxImageUniformsTest::GeometryShaderMaxImageUniformsTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_id(0) , m_gl_max_geometry_image_uniforms_ext_value(0) , m_gs_id(0) , m_po_id(0) , m_texture_ids(NULL) , m_tfbo_id(0) , m_vao_id(0) , m_vs_id(0) { //Bug-15063 Only GLSL 4.50 supports opaque types if (m_glslVersion >= glu::GLSL_VERSION_130) { m_glslVersion = glu::GLSL_VERSION_450; } } /** Deinitializes GLES objects created during the test. */ void GeometryShaderMaxImageUniformsTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 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_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } if (m_texture_ids != NULL) { gl.deleteTextures(m_gl_max_geometry_image_uniforms_ext_value, m_texture_ids); delete[] m_texture_ids; m_texture_ids = NULL; } if (m_tfbo_id != 0) { gl.deleteBuffers(1, &m_tfbo_id); m_tfbo_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; } /* Set GL_PACK_ALIGNMENT to default value. */ gl.pixelStorei(GL_PACK_ALIGNMENT, 4 /*default value taken from specification*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed for GL_PACK_ALIGNMENT pname."); /* Release base class */ TestCaseBase::deinit(); } /* Retrieves test-specific geometry shader source code. * * @return Requested string. */ std::string GeometryShaderMaxImageUniformsTest::getGSCode() { std::stringstream code_sstream; /* Form the GS */ code_sstream << "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "precision highp iimage2D;\n" "\n" "ivec4 counter = ivec4(0);\n" "\n"; for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img) { code_sstream << "layout(binding = " << n_img << ", r32i) uniform iimage2D img" << n_img << ";\n"; } code_sstream << "\n" "void main()\n" "{\n"; for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img) { code_sstream << " counter += imageLoad(img" << n_img << ", ivec2(0, 0));\n"; } code_sstream << "\n" " gl_Position = vec4(float(counter.x), 0.0, 0.0, 1.0);\n" " EmitVertex();\n" "}\n"; /* Form a specialized version of the GS source code */ std::string gs_code = code_sstream.str(); const char* gs_code_raw = gs_code.c_str(); std::string gs_code_specialized = specializeShader(1 /* parts */, &gs_code_raw); return gs_code_specialized; } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderMaxImageUniformsTest::iterate() { glw::GLint counter = 0; glw::GLint expectedValue = 0; bool has_shader_compilation_failed = true; glw::GLfloat* ptr = DE_NULL; bool result = true; const glw::GLchar* feedbackVaryings[] = { "gl_Position" }; std::string fs_code_specialized = ""; const char* fs_code_specialized_raw = DE_NULL; std::string gs_code_specialized = ""; const char* gs_code_specialized_raw = DE_NULL; std::string vs_code_specialized = ""; const char* vs_code_specialized_raw = DE_NULL; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Retrieve GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname value */ gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_IMAGE_UNIFORMS, &m_gl_max_geometry_image_uniforms_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname"); /* Retrieve GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT pname value */ glw::GLint m_gl_max_geometry_texture_image_units_ext_value = 0; gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &m_gl_max_geometry_texture_image_units_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname"); /* Retrieve GL_MAX_IMAGE_UNITS pname value */ glw::GLint m_gl_max_image_units_value = 0; gl.getIntegerv(GL_MAX_IMAGE_UNITS, &m_gl_max_image_units_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_IMAGE_UNITS pname"); /* Check if m_gl_max_geometry_image_uniforms_value is less than or equal zero. */ if (m_gl_max_geometry_image_uniforms_ext_value <= 0) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT query value " << "[" << m_gl_max_geometry_image_uniforms_ext_value << "]" " is less than or equal zero. Image uniforms in Geometry Shader" " are not supported." << tcu::TestLog::EndMessage; if (m_gl_max_geometry_image_uniforms_ext_value == 0) { throw tcu::NotSupportedError("GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT is 0"); } else { result = false; goto end; } } /* Check if m_gl_max_image_units_value is less than m_gl_max_geometry_image_uniforms_value. */ if (m_gl_max_image_units_value < m_gl_max_geometry_image_uniforms_ext_value) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT query value " << "[" << m_gl_max_geometry_image_uniforms_ext_value << "]" " is greater than GL_MAX_IMAGE_UNITS query value " "[" << m_gl_max_image_units_value << "]." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create a program object. */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Configure which outputs should be captured by Transform Feedback. */ gl.transformFeedbackVaryings(m_po_id, 1 /* varyings count */, feedbackVaryings, GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); /* Try to link the test program object */ fs_code_specialized = specializeShader(1, &dummy_fs_code); fs_code_specialized_raw = fs_code_specialized.c_str(); gs_code_specialized = getGSCode(); gs_code_specialized_raw = gs_code_specialized.c_str(); vs_code_specialized = specializeShader(1, &dummy_vs_code); vs_code_specialized_raw = vs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */ &vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */ &fs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Use program. */ gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); /* Allocate memory for m_max_image_units_value Texture Objects. */ m_texture_ids = new glw::GLuint[m_gl_max_geometry_image_uniforms_ext_value]; /* Generate m_max_image_units_value Texture Objects. */ gl.genTextures(m_gl_max_geometry_image_uniforms_ext_value, m_texture_ids); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); /* Set GL_PACK_ALIGNMENT to 1. */ gl.pixelStorei(GL_PACK_ALIGNMENT, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed for GL_PACK_ALIGNMENT pname."); /* Bind integer 2D texture objects of resolution 1x1 to image units. */ for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img) { glw::GLint texture = m_texture_ids[n_img]; glw::GLint value = n_img + 1; gl.bindTexture(GL_TEXTURE_2D, texture); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.texStorage2D(GL_TEXTURE_2D, 1 /*levels*/, GL_R32I, 1 /*width*/, 1 /*height*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); gl.texSubImage2D(GL_TEXTURE_2D, 0 /*level*/, 0 /*xoffset*/, 0 /*yoffset*/, 1 /*width*/, 1 /*height*/, GL_RED_INTEGER, GL_INT, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed."); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri() call failed."); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri() call failed."); gl.bindImageTexture(n_img, texture, 0 /*level*/, GL_FALSE /*is layered?*/, 0 /*layer*/, GL_READ_ONLY, GL_R32I); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed."); } /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Create a Buffer Object for Transform Feedback's outputs. */ gl.genBuffers(1, &m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4 /* four float vector components */, NULL, GL_STATIC_READ); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); /* Bind Buffer Object m_tfbo_id to GL_TRANSFORM_FEEDBACK_BUFFER binding point. */ gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); /* Disable rasterization and make a draw call. After that, turn on rasterization. */ gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed for GL_RASTERIZER_DISCARD pname."); gl.beginTransformFeedback(GL_POINTS); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname."); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); gl.disable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed for GL_RASTERIZER_DISCARD pname."); /* Retrieve value from Transform Feedback. */ counter = 0; ptr = (glw::GLfloat*)gl.mapBufferRange( GL_ARRAY_BUFFER, 0, sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); counter = int(ptr[0] + 0.5f); gl.unmapBuffer(GL_ARRAY_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); /* Calculate expected value. */ expectedValue = m_gl_max_geometry_image_uniforms_ext_value * (m_gl_max_geometry_image_uniforms_ext_value + 1) / 2; if (counter != expectedValue) { result = false; } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderMaxShaderStorageBlocksTest::GeometryShaderMaxShaderStorageBlocksTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_id(0) , m_gl_max_geometry_shader_storage_blocks_ext_value(0) , m_gs_id(0) , m_po_id(0) , m_ssbo_id(0) , m_tfbo_id(0) , m_vao_id(0) , m_vs_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderMaxShaderStorageBlocksTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 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_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } if (m_ssbo_id != 0) { gl.deleteBuffers(1, &m_ssbo_id); m_ssbo_id = 0; } if (m_tfbo_id != 0) { gl.deleteBuffers(1, &m_tfbo_id); m_tfbo_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; } /* Release base class */ TestCaseBase::deinit(); } /* Retrieves test-specific geometry shader source code. * * @return Requested string. */ std::string GeometryShaderMaxShaderStorageBlocksTest::getGSCode() { std::stringstream code_sstream; /* Form the GS */ code_sstream << "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "int counter = 0;\n" "\n"; for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb) { code_sstream << "layout(binding = " << n_ssb << ") buffer ssb" << n_ssb << " \n{\n" << " int value;\n" << "} S_SSB" << n_ssb << ";\n\n"; } code_sstream << "\n" "void main()\n" "{\n"; for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb) { code_sstream << " counter += S_SSB" << n_ssb << ".value++;\n"; } code_sstream << "\n" " gl_Position = vec4(float(counter), 0.0, 0.0, 1.0);\n" " EmitVertex();\n" "}\n"; /* Form a specialized version of the GS source code */ std::string gs_code = code_sstream.str(); const char* gs_code_raw = gs_code.c_str(); std::string gs_code_specialized = specializeShader(1 /* parts */, &gs_code_raw); return gs_code_specialized; } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderMaxShaderStorageBlocksTest::iterate() { glw::GLint counter = 0; glw::GLint expectedValue = 0; const glw::GLchar* feedbackVaryings[] = { "gl_Position" }; bool has_shader_compilation_failed = true; const glw::GLfloat initial_buffer_data[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glw::GLint int_alignment = 0; const glw::GLint int_size = sizeof(glw::GLint); glw::GLint* ptrSSBO_data = DE_NULL; glw::GLfloat* ptrTF_data = DE_NULL; bool result = true; glw::GLint ssbo_alignment = 0; glw::GLint* ssbo_data = DE_NULL; glw::GLint ssbo_data_size = 0; std::string fs_code_specialized = ""; const char* fs_code_specialized_raw = DE_NULL; std::string gs_code_specialized = ""; const char* gs_code_specialized_raw = DE_NULL; std::string vs_code_specialized = ""; const char* vs_code_specialized_raw = DE_NULL; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Retrieve GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT pname value */ gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &m_gl_max_geometry_shader_storage_blocks_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT pname"); /* Retrieve GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS pname value */ glw::GLint m_gl_max_shader_storage_buffer_bindings_value = 0; gl.getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &m_gl_max_shader_storage_buffer_bindings_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS pname"); /* Check if m_gl_max_shader_storage_blocks_value is less than or equal zero. */ if (m_gl_max_geometry_shader_storage_blocks_ext_value <= 0) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT query value " << "[" << m_gl_max_geometry_shader_storage_blocks_ext_value << "]" " is less than or equal zero. Shader Storage Blocks" " in Geometry Shader are not supported." << tcu::TestLog::EndMessage; if (m_gl_max_geometry_shader_storage_blocks_ext_value == 0) { throw tcu::NotSupportedError("GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT is 0"); } else { result = false; goto end; } } /* Check if m_gl_max_shader_storage_buffer_bindings_value is less than m_gl_max_shader_storage_blocks_value. */ if (m_gl_max_shader_storage_buffer_bindings_value < m_gl_max_geometry_shader_storage_blocks_ext_value) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT query value " << "[" << m_gl_max_geometry_shader_storage_blocks_ext_value << "]" " is greater than GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS query value " "[" << m_gl_max_shader_storage_buffer_bindings_value << "]." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create a program object. */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Configure which outputs should be captured by Transform Feedback. */ gl.transformFeedbackVaryings(m_po_id, 1 /* varyings count */, feedbackVaryings, GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); /* Try to link the test program object */ fs_code_specialized = specializeShader(1, &dummy_fs_code); fs_code_specialized_raw = fs_code_specialized.c_str(); gs_code_specialized = getGSCode(); gs_code_specialized_raw = gs_code_specialized.c_str(); vs_code_specialized = specializeShader(1, &dummy_vs_code); vs_code_specialized_raw = vs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */ &vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */ &fs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Prepare data for Shader Storage Buffer Object. */ gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &ssbo_alignment); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed."); int_alignment = ssbo_alignment / int_size; ssbo_data_size = m_gl_max_geometry_shader_storage_blocks_ext_value * ssbo_alignment; ssbo_data = new glw::GLint[ssbo_data_size]; if ((ssbo_alignment % int_size) != 0) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT query value " "[" << ssbo_alignment << "]" "divide with remainder by the size of GLint " "[" << int_size << "]" << tcu::TestLog::EndMessage; result = false; goto end; } for (int i = 0; i < m_gl_max_geometry_shader_storage_blocks_ext_value; ++i) { ssbo_data[i * int_alignment] = i + 1; } /* Create Shader Storage Buffer Object. */ gl.genBuffers(1, &m_ssbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname."); gl.bufferData(GL_SHADER_STORAGE_BUFFER, ssbo_data_size, ssbo_data, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); /* Free unused memory. */ delete[] ssbo_data; ssbo_data = NULL; /* Bind specific m_ssbo_id buffer region to a specific Shader Storage Buffer binding point. */ for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb) { glw::GLuint offset = n_ssb * ssbo_alignment; gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, n_ssb /*binding index*/, m_ssbo_id, offset, int_size); GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed."); } /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Create a Buffer Object for Transform Feedback's outputs. */ gl.genBuffers(1, &m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4 /* four float vector components */, initial_buffer_data, GL_STATIC_READ); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); /* Bind Buffer Object m_tfbo_id to GL_TRANSFORM_FEEDBACK_BUFFER binding point. */ gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed."); /* Use program. */ gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); /* Disable rasterization and make a draw call. After that, turn on rasterization. */ gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed for GL_RASTERIZER_DISCARD pname."); gl.beginTransformFeedback(GL_POINTS); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname."); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); gl.disable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed for GL_RASTERIZER_DISCARD pname."); /* Retrieve value from Transform Feedback. */ ptrTF_data = (glw::GLfloat*)gl.mapBufferRange( GL_ARRAY_BUFFER, 0 /*offset*/, sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); counter = int(ptrTF_data[0] + 0.5f); gl.unmapBuffer(GL_ARRAY_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrTF_data = NULL; /* Retrieve values from Shader Storage Buffer Object. */ ptrSSBO_data = (glw::GLint*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0 /*offset*/, ssbo_data_size, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); for (int i = 0; i < m_gl_max_geometry_shader_storage_blocks_ext_value; ++i) { if (ptrSSBO_data[i * int_alignment] != i + 2) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Value read from Shader Storage Buffer " "[" << ptrSSBO_data[i * int_alignment] << "] " "at index " "[" << i * int_alignment << "]" "is not equal to expected value " "[" << i + 2 << "]" << tcu::TestLog::EndMessage; break; } } gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrSSBO_data = NULL; /* Calculate expected value. */ expectedValue = m_gl_max_geometry_shader_storage_blocks_ext_value * (m_gl_max_geometry_shader_storage_blocks_ext_value + 1) / 2; if (counter != expectedValue) { result = false; } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderMaxAtomicCountersTest::GeometryShaderMaxAtomicCountersTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_acbo_id(0) , m_fs_id(0) , m_gl_max_geometry_atomic_counters_ext_value(0) , m_gs_id(0) , m_po_id(0) , m_vao_id(0) , m_vs_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderMaxAtomicCountersTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_acbo_id != 0) { gl.deleteBuffers(1, &m_acbo_id); m_acbo_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_po_id != 0) { gl.deleteProgram(m_po_id); m_po_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; } /* Release base class */ TestCaseBase::deinit(); } /* Retrieves test-specific geometry shader source code. * * @return Requested string. */ std::string GeometryShaderMaxAtomicCountersTest::getGSCode() { std::stringstream code_sstream; /* Form the GS */ code_sstream << "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "uniform int n_loop_iterations;\n" "flat in int vertex_id[];\n" "\n"; code_sstream << "layout(binding = 0) uniform atomic_uint acs[" << m_gl_max_geometry_atomic_counters_ext_value << "];\n" << "\n" "void main()\n" "{\n" " for (int counter_id = 1;\n" " counter_id <= n_loop_iterations;\n" " ++counter_id)\n" " {\n" " if ((vertex_id[0] % counter_id) == 0)\n" " {\n" " atomicCounterIncrement(acs[counter_id - 1]);\n" " }\n" " }\n" "\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" " EmitVertex();\n" "}\n"; /* Form a specialized version of the GS source code */ std::string gs_code = code_sstream.str(); const char* gs_code_raw = gs_code.c_str(); std::string gs_code_specialized = specializeShader(1, /* parts */ &gs_code_raw); return gs_code_specialized; } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderMaxAtomicCountersTest::iterate() { /* Define Vertex Shader's code for the purpose of this test. */ const char* vs_code = "${VERSION}\n" "\n" "flat out int vertex_id;\n" "\n" "void main()\n" "{\n" " vertex_id = gl_VertexID;\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; bool has_shader_compilation_failed = true; glw::GLuint* initial_ac_data = DE_NULL; const unsigned int n_draw_call_vertices = 4; glw::GLint n_loop_iterations_uniform_location = -1; glw::GLuint* ptrACBO_data = DE_NULL; bool result = true; std::string fs_code_specialized = ""; const char* fs_code_specialized_raw = DE_NULL; std::string gs_code_specialized = ""; const char* gs_code_specialized_raw = DE_NULL; std::string vs_code_specialized = ""; const char* vs_code_specialized_raw = DE_NULL; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Retrieve GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT pname value */ gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_ATOMIC_COUNTERS, &m_gl_max_geometry_atomic_counters_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT pname"); /* Check if m_gl_max_atomic_counters_value is less than or equal zero. */ if (m_gl_max_geometry_atomic_counters_ext_value <= 0) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT query value " << "[" << m_gl_max_geometry_atomic_counters_ext_value << "]" " is less than or equal to zero. Atomic Counters" " in Geometry Shader are not supported." << tcu::TestLog::EndMessage; if (m_gl_max_geometry_atomic_counters_ext_value == 0) { throw tcu::NotSupportedError("GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT is 0"); } else { result = false; goto end; } } /* Create a program object. */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ fs_code_specialized = specializeShader(1, &dummy_fs_code); fs_code_specialized_raw = fs_code_specialized.c_str(); gs_code_specialized = getGSCode(); gs_code_specialized_raw = gs_code_specialized.c_str(); vs_code_specialized = specializeShader(1, &vs_code); vs_code_specialized_raw = vs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */ &vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */ &fs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create Atomic Counter Buffer Objects. */ gl.genBuffers(1, &m_acbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); /* Prepare initial data - zeroes - to fill the Atomic Counter Buffer Object. */ initial_ac_data = new glw::GLuint[m_gl_max_geometry_atomic_counters_ext_value]; memset(initial_ac_data, 0, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value); gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname."); gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value, NULL, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value, initial_ac_data /*initialize with zeroes*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed."); gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0 /*binding index*/, m_acbo_id /*buffer*/); GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed."); /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Use program. */ n_loop_iterations_uniform_location = gl.getUniformLocation(m_po_id, "n_loop_iterations"); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call failed."); if (n_loop_iterations_uniform_location == -1) { TCU_FAIL("n_loop_iterations uniform is considered inactive"); } else { gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); gl.uniform1i(n_loop_iterations_uniform_location, m_gl_max_geometry_atomic_counters_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); } /* Issue the draw call */ gl.drawArrays(GL_POINTS, 0, n_draw_call_vertices); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname."); /* Retrieve values from Atomic Counter Buffer Objects and check if these values are valid. */ ptrACBO_data = (glw::GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); for (glw::GLint n_ac = 0; n_ac < m_gl_max_geometry_atomic_counters_ext_value; ++n_ac) { unsigned int expected_value = 0; for (unsigned int n_draw_call_vertex = 0; n_draw_call_vertex < n_draw_call_vertices; ++n_draw_call_vertex) { if ((n_draw_call_vertex % (n_ac + 1)) == 0) { ++expected_value; } } if (ptrACBO_data[n_ac] != expected_value) { result = false; break; } } gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrACBO_data = NULL; end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderMaxAtomicCounterBuffersTest::GeometryShaderMaxAtomicCounterBuffersTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_acbo_ids(NULL) , m_fs_id(0) , m_gl_max_atomic_counter_buffer_bindings_value(0) , m_gl_max_geometry_atomic_counter_buffers_ext_value(0) , m_gs_id(0) , m_po_id(0) , m_vao_id(0) , m_vs_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderMaxAtomicCounterBuffersTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_acbo_ids != NULL) { if (m_gl_max_geometry_atomic_counter_buffers_ext_value > 0) { gl.deleteBuffers(m_gl_max_geometry_atomic_counter_buffers_ext_value, m_acbo_ids); delete[] m_acbo_ids; m_acbo_ids = NULL; } } 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_po_id != 0) { gl.deleteProgram(m_po_id); m_po_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; } /* Release base class */ TestCaseBase::deinit(); } /* Retrieves test-specific geometry shader source code. * * @return Requested string. */ std::string GeometryShaderMaxAtomicCounterBuffersTest::getGSCode() { std::stringstream code_sstream; /* Form the GS */ code_sstream << "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "flat in int vertex_id[];\n" "\n"; for (glw::GLint n_ac = 0; n_ac < (m_gl_max_geometry_atomic_counter_buffers_ext_value); ++n_ac) { code_sstream << "layout(binding = " << n_ac << ") uniform atomic_uint ac" << n_ac << ";\n"; } code_sstream << "\n" "void main()\n" "{\n" " for(int counter_id = 1; counter_id <= " << m_gl_max_geometry_atomic_counter_buffers_ext_value << "; ++counter_id)\n" " {\n" " if((vertex_id[0] % counter_id) == 0)\n" " {\n"; for (glw::GLint n_ac = 0; n_ac < (m_gl_max_geometry_atomic_counter_buffers_ext_value); ++n_ac) { code_sstream << " atomicCounterIncrement(ac" << n_ac << ");\n"; } code_sstream << " }\n" " }\n"; code_sstream << "\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" " EmitVertex();\n" "}\n"; /* Form a specialized version of the GS source code */ std::string gs_code = code_sstream.str(); const char* gs_code_raw = gs_code.c_str(); std::string gs_code_specialized = specializeShader(1, /* parts */ &gs_code_raw); return gs_code_specialized; } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderMaxAtomicCounterBuffersTest::iterate() { /* Define Vertex Shader's code for the purpose of this test. */ const char* vs_code = "${VERSION}\n" "\n" "flat out int vertex_id;\n" "\n" "void main()\n" "{\n" " vertex_id = gl_VertexID;\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; unsigned int expected_value = 0; const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bool has_shader_compilation_failed = true; const glw::GLuint initial_ac_data = 0; const glw::GLuint number_of_indices = 128 * m_gl_max_geometry_atomic_counter_buffers_ext_value; bool result = true; std::string fs_code_specialized = ""; const char* fs_code_specialized_raw = DE_NULL; std::string gs_code_specialized = ""; const char* gs_code_specialized_raw = DE_NULL; std::string vs_code_specialized = ""; const char* vs_code_specialized_raw = DE_NULL; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } /* Retrieve GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT pname value */ gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, &m_gl_max_geometry_atomic_counter_buffers_ext_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT pname"); /* Retrieve GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS pname value */ gl.getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_gl_max_atomic_counter_buffer_bindings_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS pname"); /* Check if m_gl_max_geometry_atomic_counter_buffers_ext_value is less than or equal zero. */ if (m_gl_max_geometry_atomic_counter_buffers_ext_value <= 0) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT query value " << "[" << m_gl_max_geometry_atomic_counter_buffers_ext_value << "]" " is less than or equal to zero. Atomic Counter Buffers" " are not supported." << tcu::TestLog::EndMessage; if (m_gl_max_geometry_atomic_counter_buffers_ext_value == 0) { throw tcu::NotSupportedError("GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT is 0"); } else { result = false; goto end; } } /* Check if m_gl_max_atomic_counter_buffer_bindings_value is less than m_gl_max_shader_storage_blocks_value. */ if (m_gl_max_atomic_counter_buffer_bindings_value < m_gl_max_geometry_atomic_counter_buffers_ext_value) { m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT query value " << "[" << m_gl_max_geometry_atomic_counter_buffers_ext_value << "]" " is greater than GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS query value " "[" << m_gl_max_atomic_counter_buffer_bindings_value << "]." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create a program object. */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ fs_code_specialized = specializeShader(1, &dummy_fs_code); fs_code_specialized_raw = fs_code_specialized.c_str(); gs_code_specialized = getGSCode(); gs_code_specialized_raw = gs_code_specialized.c_str(); vs_code_specialized = specializeShader(1, &vs_code); vs_code_specialized_raw = vs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */ &vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */ &fs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create Atomic Counter Buffer Objects. */ m_acbo_ids = new glw::GLuint[m_gl_max_geometry_atomic_counter_buffers_ext_value]; gl.genBuffers(m_gl_max_geometry_atomic_counter_buffers_ext_value, m_acbo_ids); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); for (glw::GLint n_acb = 0; n_acb < m_gl_max_geometry_atomic_counter_buffers_ext_value; ++n_acb) { gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_ids[n_acb]); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname."); gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(glw::GLuint), &initial_ac_data /*initialize with zeroes*/, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, n_acb /*binding index*/, m_acbo_ids[n_acb] /*buffer*/); GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed."); } /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Use program. */ gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); gl.drawArrays(GL_POINTS, 0 /*starting index*/, number_of_indices); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname."); /* Calculate expected value. */ /* For each point being processed by Geometry Shader. */ for (glw::GLuint vertex_id = 0; vertex_id < number_of_indices; ++vertex_id) { /* And for each atomic counter ID. */ for (int atomic_counter_id = 1; atomic_counter_id <= m_gl_max_geometry_atomic_counter_buffers_ext_value; ++atomic_counter_id) { /* Check if (vertex_id % atomic_counter_id) == 0. If it is true, increment expected_value. */ if (vertex_id % atomic_counter_id == 0) { ++expected_value; } } } /* Retrieve values from Atomic Counter Buffer Objects and check if these values are valid. */ for (glw::GLint n_acb = 0; n_acb < m_gl_max_geometry_atomic_counter_buffers_ext_value; ++n_acb) { gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_ids[n_acb]); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); glw::GLuint* ptrABO_data = (glw::GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/, sizeof(glw::GLuint) /*length*/, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); if (ptrABO_data[0] != expected_value) { result = false; break; } gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrABO_data = NULL; } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest:: GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_id(0) , m_fs_po_id(0) , m_gs_id(0) , m_gs_po_id(0) , m_ppo_id(0) , m_vao_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_id != 0) { gl.deleteShader(m_fs_id); m_fs_id = 0; } if (m_fs_po_id != 0) { gl.deleteProgram(m_fs_po_id); m_fs_po_id = 0; } if (m_gs_id != 0) { gl.deleteShader(m_gs_id); m_gs_id = 0; } if (m_gs_po_id != 0) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } if (m_ppo_id != 0) { gl.deleteProgramPipelines(1, &m_ppo_id); m_ppo_id = 0; } if (m_vao_id != 0) { gl.deleteVertexArrays(1, &m_vao_id); m_vao_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest::iterate() { bool has_shader_compilation_failed = true; bool result = true; glw::GLenum error = GL_NO_ERROR; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create separable program objects. */ m_fs_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); gl.programParameteri(m_fs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed."); m_gs_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); gl.programParameteri(m_gs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string fs_code_specialized = specializeShader(1, &dummy_fs_code); const char* fs_code_specialized_raw = fs_code_specialized.c_str(); std::string gs_code_specialized = specializeShader(1, &dummy_gs_code); const char* gs_code_specialized_raw = gs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_fs_po_id, m_fs_id, 1, /* n_sh1_body_parts */ &fs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */ NULL, 0, 0, /* n_sh3_body_parts */ NULL, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Fragment Shader Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } if (!TestCaseBase::buildProgram(m_gs_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */ NULL, 0, 0, /* n_sh3_body_parts */ NULL, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Configure Pipeline Object. */ gl.genProgramPipelines(1, &m_ppo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed."); gl.useProgramStages(m_ppo_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed."); gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed."); /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); /* Use Program Pipeline Object. */ gl.bindProgramPipeline(m_ppo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed."); gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/); error = gl.getError(); /* Check if correct error was generated. */ if (GL_INVALID_OPERATION != error) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; } end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderIncompatibleDrawCallModeTest::GeometryShaderIncompatibleDrawCallModeTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fs_id(0) , m_gs_ids(NULL) , m_number_of_gs(5 /*taken from test spec*/) , m_po_ids(NULL) { m_vao_id = 0; m_vs_id = 0; } /** Deinitializes GLES objects created during the test. */ void GeometryShaderIncompatibleDrawCallModeTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_fs_id != 0) { gl.deleteShader(m_fs_id); m_fs_id = 0; } if (m_gs_ids != 0) { for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { gl.deleteShader(m_gs_ids[i]); m_gs_ids[i] = 0; } delete[] m_gs_ids; m_gs_ids = NULL; } if (m_po_ids != 0) { for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { gl.deleteProgram(m_po_ids[i]); m_po_ids[i] = 0; } delete[] m_po_ids; m_po_ids = NULL; } 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; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderIncompatibleDrawCallModeTest::iterate() { /* Define 5 Geometry Shaders for purpose of this test. */ const char* gs_code_points = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " EmitVertex();\n" "}\n"; const char* gs_code_lines = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (lines) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " EmitVertex();\n" "}\n"; const char* gs_code_lines_adjacency = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (lines_adjacency) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " EmitVertex();\n" "}\n"; const char* gs_code_triangles = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (triangles) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " EmitVertex();\n" "}\n"; const char* gs_code_triangles_adjacency = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (triangles_adjacency) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " EmitVertex();\n" "}\n"; bool has_shader_compilation_failed = true; bool result = true; m_gs_ids = new glw::GLuint[m_number_of_gs]; m_po_ids = new glw::GLuint[m_number_of_gs]; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create program objects & geometry shader objects. */ for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { m_gs_ids[i] = gl.createShader(GL_GEOMETRY_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); m_po_ids[i] = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); } /* Create shader object. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string fs_code_specialized = specializeShader(1, &dummy_fs_code); const char* fs_code_specialized_raw = fs_code_specialized.c_str(); std::string gs_codes_specialized[] = { specializeShader(1, &gs_code_points), specializeShader(1, &gs_code_lines), specializeShader(1, &gs_code_lines_adjacency), specializeShader(1, &gs_code_triangles), specializeShader(1, &gs_code_triangles_adjacency) }; const char* gs_codes_specialized_raw[] = { gs_codes_specialized[0].c_str(), gs_codes_specialized[1].c_str(), gs_codes_specialized[2].c_str(), gs_codes_specialized[3].c_str(), gs_codes_specialized[4].c_str() }; std::string vs_code_specialized = specializeShader(1, &dummy_vs_code); const char* vs_code_specialized_raw = vs_code_specialized.c_str(); for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1, /* n_sh1_body_parts */ &fs_code_specialized_raw, m_gs_ids[i], 1, /* n_sh2_body_parts */ &gs_codes_specialized_raw[i], m_vs_id, 1, /* n_sh3_body_parts */ &vs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed for i = " << "[" << i << "]." << tcu::TestLog::EndMessage; result = false; break; } } if (result) { /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); for (glw::GLuint po = 0; po < m_number_of_gs; ++po) { /* Use Program Object. */ gl.useProgram(m_po_ids[po]); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); if (po != 0) { gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } } if (po != 1) { gl.drawArrays(GL_LINES, 0 /*starting index*/, 2 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_LINE_LOOP, 0 /*starting index*/, 2 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_LINE_STRIP, 0 /*starting index*/, 2 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } } if (po != 2) { gl.drawArrays(GL_LINES_ADJACENCY_EXT, 0 /*starting index*/, 4 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_LINE_STRIP_ADJACENCY_EXT, 0 /*starting index*/, 4 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } } if (po != 3) { gl.drawArrays(GL_TRIANGLES, 0 /*starting index*/, 3 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_TRIANGLE_FAN, 0 /*starting index*/, 3 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_TRIANGLE_STRIP, 0 /*starting index*/, 3 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } } if (po != 4) { gl.drawArrays(GL_TRIANGLES_ADJACENCY_EXT, 0 /*starting index*/, 6 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } gl.drawArrays(GL_TRIANGLE_STRIP_ADJACENCY_EXT, 0 /*starting index*/, 6 /*number of indices*/); if (GL_INVALID_OPERATION != gl.getError()) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; break; } } } } if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderInsufficientEmittedVerticesTest::GeometryShaderInsufficientEmittedVerticesTest( Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_fbo_id(0) , m_fs_id(0) , m_gs_ids(NULL) , m_number_of_color_components(4) , m_number_of_gs(2 /*taken from test spec*/) , m_po_ids(NULL) , m_texture_height(16) , m_texture_id(0) , m_texture_width(16) { m_vao_id = 0; m_vs_id = 0; /* Allocate enough memory for glReadPixels() data which is respectively: width, height, RGBA components number. */ m_pixels = new glw::GLubyte[m_texture_height * m_texture_width * m_number_of_color_components]; } /** Deinitializes GLES objects created during the test. */ void GeometryShaderInsufficientEmittedVerticesTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f); if (m_pixels != NULL) { delete[] m_pixels; m_pixels = NULL; } 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_ids != 0) { for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { gl.deleteShader(m_gs_ids[i]); m_gs_ids[i] = 0; } delete[] m_gs_ids; m_gs_ids = NULL; } if (m_po_ids != 0) { for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { gl.deleteProgram(m_po_ids[i]); m_po_ids[i] = 0; } delete[] m_po_ids; m_po_ids = NULL; } if (m_texture_id != 0) { gl.deleteTextures(1, &m_texture_id); m_texture_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; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderInsufficientEmittedVerticesTest::iterate() { /* Define Fragment Shader for purpose of this test. */ const char* fs_code = "${VERSION}\n" "\n" "precision highp float;\n" "\n" "out vec4 result;\n" "\n" "void main()\n" "{\n" " result = vec4(1.0, 0.0, 0.0, 0.0);\n" "}\n"; /* Define 2 Geometry Shaders for purpose of this test. */ const char* gs_line_strip = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (line_strip, max_vertices = 2) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " gl_Position.zw = vec2(0.0, 1.0);\n" " EmitVertex();\n" "}\n"; const char* gs_triangle_strip = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (points) in;\n" "layout (triangle_strip, max_vertices = 3) out;\n" "\n" "${IN_PER_VERTEX_DECL_ARRAY}" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " gl_Position.zw = vec2(0.0, 1.0);\n" " EmitVertex();\n" " gl_Position = gl_in[0].gl_Position;\n" " gl_Position.zw = vec2(0.0, 1.0);\n" " EmitVertex();\n" "}\n"; bool has_shader_compilation_failed = true; bool result = true; m_gs_ids = new glw::GLuint[m_number_of_gs]; m_po_ids = new glw::GLuint[m_number_of_gs]; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create program objects & geometry shader objects. */ for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { m_gs_ids[i] = gl.createShader(GL_GEOMETRY_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); m_po_ids[i] = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); } /* Create shader object. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string fs_code_specialized = specializeShader(1, &fs_code); const char* fs_code_specialized_raw = fs_code_specialized.c_str(); std::string gs_codes_specialized[] = { specializeShader(1, &gs_line_strip), specializeShader(1, &gs_triangle_strip) }; const char* gs_codes_specialized_raw[] = { gs_codes_specialized[0].c_str(), gs_codes_specialized[1].c_str() }; std::string vs_code_specialized = specializeShader(1, &dummy_vs_code); const char* vs_code_specialized_raw = vs_code_specialized.c_str(); for (glw::GLuint i = 0; i < m_number_of_gs; ++i) { if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1, /* n_sh1_body_parts */ &fs_code_specialized_raw, m_gs_ids[i], 1, /* n_sh2_body_parts */ &gs_codes_specialized_raw[i], m_vs_id, 1, /* n_sh3_body_parts */ &vs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed for i = " << "[" << i << "]." << tcu::TestLog::EndMessage; result = false; break; } } if (result) { /* Create a 2D texture. */ gl.genTextures(1, &m_texture_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); gl.bindTexture(GL_TEXTURE_2D, m_texture_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.texStorage2D(GL_TEXTURE_2D, 1 /*levels*/, GL_RGBA8, 16 /*width taken from spec*/, 16 /*height taken from spec*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); /* Configure FBO. */ gl.genFramebuffers(1, &m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed."); gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0 /*level*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); /* Configure VAO. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); gl.clearColor(0.0f, 1.0f, 0.0f, 0.0f); GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed."); for (glw::GLuint po = 0; po < m_number_of_gs; ++po) { /* Use Program Object. */ gl.useProgram(m_po_ids[po]); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); gl.clear(GL_COLOR_BUFFER_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed."); gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname."); gl.readPixels(0 /*x*/, 0 /*y*/, m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); for (glw::GLuint pixel = 0; pixel < (m_texture_width * m_texture_height * m_number_of_color_components - m_number_of_color_components); pixel += m_number_of_color_components) { if (m_pixels[pixel] != 0 && m_pixels[pixel + 1] != 255 && m_pixels[pixel + 2] != 0 && m_pixels[pixel + 3] != 0) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Pixel [" << pixel << "] has color = [" << m_pixels[pixel] << ", " << m_pixels[pixel + 1] << ", " << m_pixels[pixel + 2] << ", " << m_pixels[pixel + 3] << "] " << "instead of [0, 255, 0, 0]." << tcu::TestLog::EndMessage; break; } } } } if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest:: GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_gs_id(0) , m_gs_po_id(0) , m_ppo_id(0) , m_tfbo_id(0) , m_vao_id(0) , m_vs_id(0) , m_vs_po_id(0) { } /** Deinitializes GLES objects created during the test. */ void GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_gs_id != 0) { gl.deleteShader(m_gs_id); m_gs_id = 0; } if (m_gs_po_id != 0) { gl.deleteProgram(m_gs_po_id); m_gs_po_id = 0; } if (m_ppo_id != 0) { gl.deleteProgramPipelines(1, &m_ppo_id); m_ppo_id = 0; } if (m_tfbo_id != 0) { gl.deleteBuffers(1, &m_tfbo_id); m_tfbo_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; } if (m_vs_po_id != 0) { gl.deleteProgram(m_vs_po_id); m_vs_po_id = 0; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest::iterate() { /* Define Geometry Shader for purpose of this test. */ const char* gs_code = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "${IN_PER_VERTEX_DECL_ARRAY}\n" "${OUT_PER_VERTEX_DECL}\n" "\n" "layout (points) in;\n" "layout (points, max_vertices = 1) out;\n" "\n" "flat in int vertexID[];\n" "flat in ivec4 out_vs_1[];\n" "\n" "out vec4 out_gs_1;\n" "\n" "void main()\n" "{\n" " out_gs_1 = vec4(vertexID[0] * 2, vertexID[0] * 2 + 1, vertexID[0] * 2 + 2, vertexID[0] * 2 + 3);\n" " gl_Position = vec4(0, 0, 0, 1);\n" " EmitVertex();\n" "}\n"; /* Define Vertex Shader for purpose of this test. */ const char* vs_code = "${VERSION}\n" "${OUT_PER_VERTEX_DECL}\n" "\n" "flat out ivec4 out_vs_1;\n" "flat out int vertexID;\n" "\n" "void main()\n" "{\n" " vertexID = gl_VertexID;\n" " out_vs_1 = ivec4(gl_VertexID, gl_VertexID + 1, gl_VertexID + 2, gl_VertexID + 3);\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; bool has_shader_compilation_failed = true; bool result = true; glw::GLfloat* ptrTF_data_f = NULL; glw::GLuint* ptrTF_data_ui = NULL; glw::GLfloat expected_geom_results[] = { 0.0f, 1.0f, 2.0f, 3.0f }; glw::GLuint expected_vertex_results[] = { 0, 1, 2, 3 }; glw::GLfloat epsilon = 1e-5f; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create separable program objects. */ m_gs_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); gl.programParameteri(m_gs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed."); m_vs_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); gl.programParameteri(m_vs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed."); /* Create shader objects. */ m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string gs_code_specialized = specializeShader(1, &gs_code); const char* gs_code_specialized_raw = gs_code_specialized.c_str(); std::string vs_code_specialized = specializeShader(1, &vs_code); const char* vs_code_specialized_raw = vs_code_specialized.c_str(); /* Specify output variables to be captured. */ const char* tf_varyings[2] = { "out_gs_1", "out_vs_1" }; gl.transformFeedbackVaryings(m_gs_po_id, 1 /*count*/, &tf_varyings[0], GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed."); gl.transformFeedbackVaryings(m_vs_po_id, 1 /*count*/, &tf_varyings[1], GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed."); if (!TestCaseBase::buildProgram(m_gs_po_id, m_gs_id, 1, /* n_sh1_body_parts */ &gs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */ NULL, 0, 0, /* n_sh3_body_parts */ NULL, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } if (!TestCaseBase::buildProgram(m_vs_po_id, m_vs_id, 1, /* n_sh1_body_parts */ &vs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */ NULL, 0, 0, /* n_sh3_body_parts */ NULL, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create and configure Program Pipeline Object. */ gl.genProgramPipelines(1, &m_ppo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call(s) failed."); gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed."); gl.useProgramStages(m_ppo_id, GL_VERTEX_SHADER_BIT, m_vs_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed."); /* Create Vertex Array Object. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed."); /* Create Buffer Object for Transform Feedback data. */ gl.genBuffers(1, &m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed."); gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed."); gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4, NULL, GL_STREAM_READ); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed."); gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed."); /* Ensure that there is no program object already bound and bind program pipeline. */ gl.useProgram(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed."); gl.bindProgramPipeline(m_ppo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed."); gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed."); /* First pass - Vertex and Geometry Shaders On. */ gl.beginTransformFeedback(GL_POINTS); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed."); gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call(s) failed."); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed."); /* Retrieve data and check if it is correct. */ ptrTF_data_f = (glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*offset*/, sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); for (size_t i = 0; i < 4; ++i) { if (fabs(ptrTF_data_f[i] - expected_geom_results[i]) >= epsilon) { result = false; break; } } gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrTF_data_f = NULL; if (!result) { goto end; } /* Deactivate Geometry Shader Program Object from Program Pipeline Object. */ gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, 0 /* program */); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed."); /* Second pass - only Vertex Shader Program On. */ gl.beginTransformFeedback(GL_POINTS); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed."); gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call(s) failed."); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed."); gl.disable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed."); /* Retrieve data and check if it is correct. */ ptrTF_data_ui = (glw::GLuint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*offset*/, sizeof(glw::GLuint) * 4 /* four float vector components */, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); for (size_t i = 0; i < 4; ++i) { if (ptrTF_data_ui[i] != expected_vertex_results[i]) { result = false; break; } } gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); ptrTF_data_ui = NULL; end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives( Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description), m_fs_id(0), m_gs_id(0), m_po_id(0), m_tfbo_id(0) { m_vao_id = 0; m_vs_id = 0; } /** Deinitializes GLES objects created during the test. */ void GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 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_po_id != 0) { gl.deleteProgram(m_po_id); m_po_id = 0; } if (m_tfbo_id != 0) { gl.deleteBuffers(1, &m_tfbo_id); m_tfbo_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; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::iterate() { /* Define Geometry Shader for purpose of this test. */ const char* gs_code = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (lines) in;\n" "layout (triangle_strip, max_vertices = 3) out;\n" "\n" "out vec4 out_gs_1;\n" "\n" "void main()\n" "{\n" " out_gs_1 = vec4(4.0, 3.0, 2.0, 1.0);\n" "\n" " gl_Position = vec4(0, 0, 0, 1);\n" " EmitVertex();\n" "\n" " gl_Position = vec4(1, 0, 0, 1);\n" " EmitVertex();\n" "\n" " gl_Position = vec4(1, 1, 0, 1);\n" " EmitVertex();\n" "\n" " EndPrimitive();" "}\n"; bool has_shader_compilation_failed = true; bool result = true; glw::GLenum error = GL_NO_ERROR; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create program object. */ m_po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); /* Specify output variables to be captured. */ const char* tf_varyings[] = { "out_gs_1" }; gl.transformFeedbackVaryings(m_po_id, 1 /*count*/, tf_varyings, GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string fs_code_specialized = specializeShader(1, &dummy_fs_code); const char* fs_code_specialized_raw = fs_code_specialized.c_str(); std::string gs_code_specialized = specializeShader(1, &gs_code); const char* gs_code_specialized_raw = gs_code_specialized.c_str(); std::string vs_code_specialized = specializeShader(1, &dummy_vs_code); const char* vs_code_specialized_raw = vs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_id, m_fs_id, 1, /* n_sh1_body_parts */ &fs_code_specialized_raw, m_gs_id, 1, /* n_sh2_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh3_body_parts */ &vs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed whereas a success was expected." << tcu::TestLog::EndMessage; result = false; goto end; } /* Create Vertex Array Object. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed."); /* Create Buffer Object for Transform Feedback data. */ gl.genBuffers(1, &m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed."); gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed."); gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4 * 3 /* capture 4 float vector components times 3 triangle vertices */, NULL, GL_STREAM_READ); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed."); gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed."); /* Turn on program object. */ gl.useProgram(m_po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed."); gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed."); gl.beginTransformFeedback(GL_LINES); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed."); gl.drawArrays(GL_TRIANGLES, 0 /*first*/, 3 /*count*/); error = gl.getError(); if (error != GL_INVALID_OPERATION) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated." << tcu::TestLog::EndMessage; } gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed."); gl.disable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed."); end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } /** Constructor * * @param context Test context * @param extParams Not used. * @param name Test case's name * @param description Test case's description **/ GeometryShaderDrawCallsWhileTFPaused::GeometryShaderDrawCallsWhileTFPaused(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description), m_fs_id(0), m_gs_id(0), m_tfbo_id(0) { m_vao_id = 0; m_vs_id = 0; } /** Deinitializes GLES objects created during the test. */ void GeometryShaderDrawCallsWhileTFPaused::deinit() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 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; } for (int i = 0; i < 15 /* All combinations of possible inputs and outputs in GS */; ++i) { if (m_po_ids[i] != 0) { gl.deleteProgram(m_po_ids[i]); m_po_ids[i] = 0; } } if (m_tfbo_id != 0) { gl.deleteBuffers(1, &m_tfbo_id); m_tfbo_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; } /* Release base class */ TestCaseBase::deinit(); } /** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult GeometryShaderDrawCallsWhileTFPaused::iterate() { /* Define 15 (all combinations of possible inputs and outputs in geometry shader) Geometry Shaders for purpose of this test. */ const std::string gs_inputs[] = { "points", "lines", "lines_adjacency", "triangles", "triangles_adjacency" }; const std::string gs_outputs[] = { "points", "line_strip", "triangle_strip" }; const std::string gs_max_output_vertices[] = { "1", "2", "3" }; const unsigned short number_of_combinations = (sizeof(gs_inputs) / sizeof(gs_inputs[0]) * (sizeof(gs_outputs) / sizeof(gs_outputs[0]))); std::string gs_codes[number_of_combinations]; glw::GLenum errorCode; for (size_t i = 0; i < (sizeof(gs_inputs) / sizeof(gs_inputs[0])) /*5 possible GS inputs*/; ++i) { for (size_t j = 0; j < (sizeof(gs_outputs) / sizeof(gs_outputs[0])) /*3 possible GS outputs*/; ++j) { /* This shader will not emit primitives for anything but points. * We do so, because we just need to make sure that, while transform feedback * is paused, all draw calls executed with an active program object which * includes a geometry shader, are valid. */ gs_codes[j + 3 * i] = "${VERSION}\n" "${GEOMETRY_SHADER_REQUIRE}\n" "\n" "layout (" + gs_inputs[i] + ") in;\n" "layout (" + gs_outputs[j] + ", max_vertices = " + gs_max_output_vertices[j] + ") out;\n" "\n" "out vec2 out_gs_1;\n" "\n" "void main()\n" "{\n" " out_gs_1 = vec2(1.0, 2.0);\n" " gl_Position = vec4(0, 0, 0, 1);\n" " EmitVertex();\n" "}\n"; } } bool has_shader_compilation_failed = true; bool result = true; const glw::GLuint tf_modes[3] = { GL_POINTS, GL_LINES, GL_TRIANGLES }; const glw::GLuint draw_call_modes[5] = { GL_POINTS, GL_LINES, GL_LINES_ADJACENCY, GL_TRIANGLES, GL_TRIANGLES_ADJACENCY }; /* This test should only run if EXT_geometry_shader is supported. */ if (!m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Create program objects. */ for (int i = 0; i < number_of_combinations; ++i) { m_po_ids[i] = gl.createProgram(); } GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed."); /* Specify output variables to be captured. */ const char* tf_varyings[] = { "out_gs_1" }; for (int i = 0; i < number_of_combinations; ++i) { gl.transformFeedbackVaryings(m_po_ids[i], 1 /*count*/, tf_varyings, GL_INTERLEAVED_ATTRIBS); } GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed."); /* Create shader objects. */ m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Try to link the test program object */ std::string fs_code_specialized = specializeShader(1, &dummy_fs_code); const char* fs_code_specialized_raw = fs_code_specialized.c_str(); std::string vs_code_specialized = specializeShader(1, &dummy_vs_code); const char* vs_code_specialized_raw = vs_code_specialized.c_str(); for (int i = 0; i < number_of_combinations; ++i) { const char* gs_code = gs_codes[i].c_str(); std::string gs_code_specialized = specializeShader(1, &gs_code); const char* gs_code_specialized_raw = gs_code_specialized.c_str(); if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1, /* n_sh1_body_parts */ &fs_code_specialized_raw, m_gs_id, 1, /* n_sh2_body_parts */ &gs_code_specialized_raw, m_vs_id, 1, /* n_sh3_body_parts */ &vs_code_specialized_raw, &has_shader_compilation_failed)) { m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed whereas a success was expected." << tcu::TestLog::EndMessage; result = false; } } if (!result) { goto end; } /* Create Vertex Array Object. */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed."); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed."); /* Create Buffer Object for Transform Feedback data. */ gl.genBuffers(1, &m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed."); gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed."); gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 2 * 3 /* capture 2 float vector components times 3 triangle vertices */, NULL, GL_STREAM_READ); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed."); gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed."); gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed."); for (int i = 0; i < 3 /* number of TF modes */ && result; ++i) { for (int j = 0; j < 5 /*number of draw call modes*/ && result; ++j) { for (int k = 0; k < 3 /* number of output GS primitive types */; ++k) { /* Turn on program object. */ gl.useProgram(m_po_ids[k + 3 * j]); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed."); gl.beginTransformFeedback(tf_modes[i]); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed."); gl.pauseTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback() call(s) failed."); gl.drawArrays(draw_call_modes[j], 0 /*first*/, 3 /*count*/); errorCode = gl.getError(); gl.resumeTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glResumeTransformFeedback() call(s) failed."); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed."); /* If draw call fails stop test execution. */ if (GL_NO_ERROR != errorCode) { m_testCtx.getLog() << tcu::TestLog::Message << "glDrawArrays() call generated an error while transform feedback was paused." << tcu::TestLog::EndMessage; result = false; break; } } } } gl.disable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed."); end: if (result) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } return STOP; } } // namespace glcts