-# VK-GL-CTS issue: 624
-KHR-GL40.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL41.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL42.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL43.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL44.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL45.shader_subroutine.multiple_contexts
-# VK-GL-CTS issue: 624
-KHR-GL46.shader_subroutine.multiple_contexts
--- /dev/null
+KHR-NoContext.gl40.multiple_contexts.uniform_preservation
--- /dev/null
+KHR-NoContext.gl40.*
--- /dev/null
+KHR-NoContext.gl40.multiple_contexts.uniform_preservation
*/-->
<TestPackage name="Khronos Mustpass GL NoContext">
<Configuration caseListFile="gl30-khr-master.txt" commandLine="--deqp-screen-rotation=unspecified --deqp-surface-width=64 --deqp-surface-height=64 --deqp-base-seed=1 --deqp-watchdog=disable" name="khr-master" os="any" useForFirstEGLConfig="True"/>
+ <Configuration caseListFile="gl40-khr-master.txt" commandLine="--deqp-screen-rotation=unspecified --deqp-surface-width=64 --deqp-surface-height=64 --deqp-base-seed=1 --deqp-watchdog=disable" name="khr-master" os="any" useForFirstEGLConfig="True"/>
<Configuration caseListFile="gl45-khr-master.txt" commandLine="--deqp-screen-rotation=unspecified --deqp-surface-width=64 --deqp-surface-height=64 --deqp-base-seed=1 --deqp-watchdog=disable" name="khr-master" os="any" useForFirstEGLConfig="True"/>
</TestPackage>
</Mustpass>
--- /dev/null
+KHR-NoContext.gl40.*
glcFragDepthTests.hpp
glcInfoTests.cpp
glcInfoTests.hpp
+ glcMultipleContextsTests.cpp
+ glcMultipleContextsTests.hpp
glcNoErrorTests.cpp
glcNoErrorTests.hpp
glcRobustnessTests.cpp
m_renderCtx = DE_NULL;
}
-glu::RenderContext* Context::createSharedContext(glu::ContextFlags, glu::ResetNotificationStrategy)
-{
- TCU_THROW(InternalError, "Not implemented");
-}
-
const tcu::RenderTarget& Context::getRenderTarget(void) const
{
return m_renderCtx->getRenderTarget();
const tcu::RenderTarget& getRenderTarget(void) const;
- glu::RenderContext* createSharedContext(
- glu::ContextFlags ctxFlags = (glu::ContextFlags)0,
- glu::ResetNotificationStrategy ctxReset = glu::RESET_NOTIFICATION_STRATEGY_NOT_SPECIFIED);
-
private:
Context(const Context& other);
Context& operator=(const Context& other);
--- /dev/null
+/*-------------------------------------------------------------------------
+ * OpenGL Conformance Test Suite
+ * -----------------------------
+ *
+ * Copyright (c) 2017 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 glcMultipleContextsTests.cpp
+ * \brief
+ */ /*-------------------------------------------------------------------*/
+
+#include "glcMultipleContextsTests.hpp"
+#include "deSharedPtr.hpp"
+#include "gl4cShaderSubroutineTests.hpp"
+#include "gluContextInfo.hpp"
+#include "glwEnums.hpp"
+#include "glwFunctions.hpp"
+#include "tcuMatrix.hpp"
+#include <cmath>
+#include <cstring>
+#include <deMath.h>
+
+using namespace glw;
+using namespace gl4cts::ShaderSubroutine;
+
+namespace glcts
+{
+
+/**
+ * * Create multiple contexts and verify that subroutine uniforms values
+ * are preserved for each program stage when switching rendering context.
+ *
+ * OpenGL 4.1 or ARB_separate_shader_objects support required
+ * * Same as above, but use pipelines instead of monolithic program.
+ **/
+class UniformPreservationTest : public tcu::TestCase
+{
+public:
+ /* Public methods */
+ UniformPreservationTest(tcu::TestContext& testCtx, glu::ApiType apiType);
+
+ virtual void deinit();
+ virtual tcu::TestNode::IterateResult iterate();
+
+private:
+ /* Private types */
+ struct subroutineUniformSet
+ {
+ bool operator!=(const subroutineUniformSet& arg) const;
+ void set(glw::GLuint bit_field, const subroutineUniformSet subroutine_indices[2]);
+
+ glw::GLuint m_vertex_shader_stage;
+ glw::GLuint m_tesselation_control_shader_stage;
+ glw::GLuint m_tesselation_evaluation_shader_stage;
+ glw::GLuint m_geometry_shader_stage;
+ glw::GLuint m_fragment_shader_stage;
+ };
+
+ /* Private methods */
+ void captureCurrentSubroutineSet(subroutineUniformSet& set);
+
+ void getShaders(const glw::GLchar*& out_vertex_shader_code, const glw::GLchar*& out_tesselation_control_shader_code,
+ const glw::GLchar*& out_tesselation_evaluation_shader_code,
+ const glw::GLchar*& out_geometry_shader_code, const glw::GLchar*& out_fragment_shader_code);
+
+ void initSharedContexts();
+
+ void prepareProgram(Utils::program** programs, bool is_separable);
+
+ void prepareProgramPipeline(glw::GLuint& pipeline_id, Utils::program** programs);
+
+ bool testCase(const glw::GLuint bit_field[5]);
+
+ bool testProgram(Utils::program** programs, bool is_separable, const glw::GLuint test_cases[][5],
+ glw::GLuint n_test_cases);
+
+ void updateCurrentSubroutineSet(const subroutineUniformSet& set);
+
+ /* Private fields */
+ static const glw::GLuint m_n_shared_contexts;
+ static const glw::GLuint m_fragment_stage_index;
+ static const glw::GLuint m_geometry_stage_index;
+ static const glw::GLuint m_tesselation_control_stage_index;
+ static const glw::GLuint m_tesselation_evaluation_stage_index;
+ static const glw::GLuint m_vertex_stage_index;
+
+ glu::ApiType m_api_type;
+ de::SharedPtr<deqp::Context> m_base_context;
+ glu::RenderContext* m_shared_contexts[4];
+ glw::GLuint m_program_pipelines[5];
+ subroutineUniformSet m_subroutine_indices[2];
+ subroutineUniformSet m_subroutine_uniform_locations;
+};
+
+/* Constants used by FunctionalTest20_21 */
+const GLuint UniformPreservationTest::m_n_shared_contexts = 4;
+const GLuint UniformPreservationTest::m_fragment_stage_index = 0;
+const GLuint UniformPreservationTest::m_geometry_stage_index = 1;
+const GLuint UniformPreservationTest::m_tesselation_control_stage_index = 2;
+const GLuint UniformPreservationTest::m_tesselation_evaluation_stage_index = 3;
+const GLuint UniformPreservationTest::m_vertex_stage_index = 4;
+
+/** Set subroutine indices, indices are taken from one of two sets according to provided <bit_field>
+ *
+ * @param bit_field Selects source of of index for each stage
+ * @param subroutine_indices Array of two indices sets
+ **/
+void UniformPreservationTest::subroutineUniformSet::set(GLuint bit_field,
+ const subroutineUniformSet subroutine_indices[2])
+{
+ GLuint vertex_stage = ((bit_field & (0x01 << 0)) >> 0);
+ GLuint tesselation_control_stage = ((bit_field & (0x01 << 1)) >> 1);
+ GLuint tesselation_evaluation_stage = ((bit_field & (0x01 << 2)) >> 2);
+ GLuint geometry_stage = ((bit_field & (0x01 << 3)) >> 3);
+ GLuint fragment_stage = ((bit_field & (0x01 << 4)) >> 4);
+
+ m_vertex_shader_stage = subroutine_indices[vertex_stage].m_vertex_shader_stage;
+ m_tesselation_control_shader_stage =
+ subroutine_indices[tesselation_control_stage].m_tesselation_control_shader_stage;
+ m_tesselation_evaluation_shader_stage =
+ subroutine_indices[tesselation_evaluation_stage].m_tesselation_evaluation_shader_stage;
+ m_geometry_shader_stage = subroutine_indices[geometry_stage].m_geometry_shader_stage;
+ m_fragment_shader_stage = subroutine_indices[fragment_stage].m_fragment_shader_stage;
+}
+
+/** Negated comparison of two sets
+ *
+ * @param arg Instance that will be compared to this
+ *
+ * @return false when both objects are equal, true otherwise
+ **/
+bool UniformPreservationTest::subroutineUniformSet::operator!=(const subroutineUniformSet& arg) const
+{
+ if ((arg.m_vertex_shader_stage != m_vertex_shader_stage) ||
+ (arg.m_tesselation_control_shader_stage != m_tesselation_control_shader_stage) ||
+ (arg.m_tesselation_evaluation_shader_stage != m_tesselation_evaluation_shader_stage) ||
+ (arg.m_geometry_shader_stage != m_geometry_shader_stage) ||
+ (arg.m_fragment_shader_stage != m_fragment_shader_stage))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/** Constructor.
+ *
+ * @param context Rendering context.
+ *
+ **/
+UniformPreservationTest::UniformPreservationTest(tcu::TestContext& testCtx, glu::ApiType apiType)
+ : tcu::TestCase(testCtx, "uniform_preservation",
+ "Verifies that shader uniforms are preserved when rendering context is switched.")
+ , m_api_type(apiType)
+{
+ for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
+ {
+ m_program_pipelines[i] = 0;
+ }
+
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i] = 0;
+ }
+}
+
+/** Deinitializes all GL objects that may have been created during
+ * test execution.
+ **/
+void UniformPreservationTest::deinit()
+{
+ /* GL entry points */
+ const glw::Functions& gl = m_base_context->getRenderContext().getFunctions();
+
+ for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
+ {
+ if (0 != m_program_pipelines[i])
+ {
+ gl.deleteProgramPipelines(1, &m_program_pipelines[i]);
+ m_program_pipelines[i] = 0;
+ }
+ }
+
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ if (0 != m_shared_contexts[i])
+ {
+ delete m_shared_contexts[i];
+ m_shared_contexts[i] = 0;
+ }
+ }
+}
+
+/** Executes test iteration.
+ *
+ * @return Returns STOP
+ */
+tcu::TestNode::IterateResult UniformPreservationTest::iterate()
+{
+ /* Test cases, values stored here are used as bit fields */
+ static const GLuint test_cases[][m_n_shared_contexts + 1] = {
+ { 0, 1, 2, 3, 4 }, { 1, 2, 3, 4, 0 }, { 2, 3, 4, 0, 1 }, { 3, 4, 0, 1, 2 },
+ { 4, 0, 1, 2, 3 }, { 27, 28, 29, 30, 31 }, { 28, 29, 30, 31, 27 }, { 29, 30, 31, 27, 28 },
+ { 30, 31, 27, 28, 29 }, { 31, 27, 28, 29, 30 },
+ };
+ static const GLuint n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
+
+ glu::ContextType context_type(m_api_type);
+ m_base_context = de::SharedPtr<deqp::Context>(new deqp::Context(m_testCtx, context_type));
+
+ /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
+ if (!m_base_context->getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
+ {
+ throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
+ }
+
+ /* Prepare contexts */
+ initSharedContexts();
+
+ /* Test result */
+ bool result = true;
+
+ /* Program pointers */
+ Utils::program* program_pointers[5];
+
+ /* Test monolithic program */
+ {
+ /* Prepare program */
+ Utils::program program(*m_base_context.get());
+
+ program_pointers[m_fragment_stage_index] = &program;
+
+ prepareProgram(program_pointers, false);
+
+ /* Execute test */
+ if (false == testProgram(program_pointers, false, test_cases, n_test_cases))
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by monolithic program."
+ << tcu::TestLog::EndMessage;
+
+ result = false;
+ }
+ }
+
+ /* Test separable programs */
+ if (true == m_base_context->getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
+ {
+ /* Prepare programs */
+ Utils::program vertex_program(*m_base_context.get());
+ Utils::program tesselation_control_program(*m_base_context.get());
+ Utils::program tesselation_evaluation_program(*m_base_context.get());
+ Utils::program geometry_program(*m_base_context.get());
+ Utils::program fragment_program(*m_base_context.get());
+
+ program_pointers[m_fragment_stage_index] = &fragment_program;
+ program_pointers[m_geometry_stage_index] = &geometry_program;
+ program_pointers[m_tesselation_control_stage_index] = &tesselation_control_program;
+ program_pointers[m_tesselation_evaluation_stage_index] = &tesselation_evaluation_program;
+ program_pointers[m_vertex_stage_index] = &vertex_program;
+
+ prepareProgram(program_pointers, true);
+
+ /* Execute test */
+ if (false == testProgram(program_pointers, true, test_cases, n_test_cases))
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by separable program."
+ << tcu::TestLog::EndMessage;
+ result = false;
+ }
+ }
+
+ /* All done */
+ if (true == result)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ }
+ else
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+ }
+
+ return tcu::TestNode::STOP;
+}
+
+/** Query state of subroutine uniforms of current program/pipeline
+ *
+ * @param set Storage for results
+ **/
+void UniformPreservationTest::captureCurrentSubroutineSet(subroutineUniformSet& set)
+{
+ /* GL entry points */
+ const glw::Functions& gl = m_base_context->getRenderContext().getFunctions();
+
+ /* Fragment */
+ gl.getUniformSubroutineuiv(GL_FRAGMENT_SHADER, m_subroutine_uniform_locations.m_fragment_shader_stage,
+ &set.m_fragment_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
+
+ /* Geometry */
+ gl.getUniformSubroutineuiv(GL_GEOMETRY_SHADER, m_subroutine_uniform_locations.m_geometry_shader_stage,
+ &set.m_geometry_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
+
+ /* Tess ctrl */
+ gl.getUniformSubroutineuiv(GL_TESS_CONTROL_SHADER,
+ m_subroutine_uniform_locations.m_tesselation_control_shader_stage,
+ &set.m_tesselation_control_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
+
+ /* Tess eval */
+ gl.getUniformSubroutineuiv(GL_TESS_EVALUATION_SHADER,
+ m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage,
+ &set.m_tesselation_evaluation_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
+
+ /* Vertex */
+ gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_subroutine_uniform_locations.m_vertex_shader_stage,
+ &set.m_vertex_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
+}
+
+/** Get shaders' source code
+ *
+ * @param out_vertex_shader_code Vertex source code
+ * @param out_tesselation_control_shader_code Tess ctrl source code
+ * @param out_tesselation_evaluation_shader_code Tess eval source code
+ * @param out_geometry_shader_code Geometry source code
+ * @param out_fragment_shader_code Fragment source code
+ **/
+void UniformPreservationTest::getShaders(const glw::GLchar*& out_vertex_shader_code,
+ const glw::GLchar*& out_tesselation_control_shader_code,
+ const glw::GLchar*& out_tesselation_evaluation_shader_code,
+ const glw::GLchar*& out_geometry_shader_code,
+ const glw::GLchar*& out_fragment_shader_code)
+{
+ static const GLchar* vertex_shader_code = "#version 400 core\n"
+ "#extension GL_ARB_shader_subroutine : require\n"
+ "\n"
+ "precision highp float;\n"
+ "\n"
+ "// Subroutine type\n"
+ "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
+ "\n"
+ "// Subroutine definition\n"
+ "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left + right;\n"
+ "}\n"
+ "\n"
+ "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left * right;\n"
+ "}\n"
+ "\n"
+ "// Sub routine uniform\n"
+ "subroutine uniform routine_type routine;\n"
+ "\n"
+ "// Input data\n"
+ "uniform vec4 uni_vs_left;\n"
+ "uniform vec4 uni_vs_right;\n"
+ "\n"
+ "// Output\n"
+ "out vec4 vs_tcs_result;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vs_tcs_result = routine(uni_vs_left, uni_vs_right);\n"
+ "}\n"
+ "\n";
+
+ static const GLchar* tesselation_control_shader_code =
+ "#version 400 core\n"
+ "#extension GL_ARB_shader_subroutine : require\n"
+ "\n"
+ "precision highp float;\n"
+ "\n"
+ "layout(vertices = 1) out;\n"
+ "\n"
+ "// Subroutine type\n"
+ "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
+ "\n"
+ "// Subroutine definition\n"
+ "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left + right;\n"
+ "}\n"
+ "\n"
+ "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left * right;\n"
+ "}\n"
+ "\n"
+ "// Sub routine uniform\n"
+ "subroutine uniform routine_type routine;\n"
+ "\n"
+ "// Input data\n"
+ "uniform vec4 uni_tcs_left;\n"
+ "uniform vec4 uni_tcs_right;\n"
+ "\n"
+ "in vec4 vs_tcs_result[];\n"
+ "\n"
+ "// Output\n"
+ "out vec4 tcs_tes_result[];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_TessLevelOuter[0] = 1.0;\n"
+ " gl_TessLevelOuter[1] = 1.0;\n"
+ " gl_TessLevelOuter[2] = 1.0;\n"
+ " gl_TessLevelOuter[3] = 1.0;\n"
+ " gl_TessLevelInner[0] = 1.0;\n"
+ " gl_TessLevelInner[1] = 1.0;\n"
+ "\n"
+ " tcs_tes_result[gl_InvocationID] = routine(uni_tcs_left, uni_tcs_right) + vs_tcs_result[gl_InvocationID];\n"
+ "}\n"
+ "\n";
+
+ static const GLchar* tesselation_evaluation_shader_code =
+ "#version 400 core\n"
+ "#extension GL_ARB_shader_subroutine : require\n"
+ "\n"
+ "precision highp float;\n"
+ "\n"
+ "layout(isolines, point_mode) in;\n"
+ "\n"
+ "// Subroutine type\n"
+ "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
+ "\n"
+ "// Subroutine definition\n"
+ "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left + right;\n"
+ "}\n"
+ "\n"
+ "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left * right;\n"
+ "}\n"
+ "\n"
+ "// Sub routine uniform\n"
+ "subroutine uniform routine_type routine;\n"
+ "\n"
+ "// Input data\n"
+ "uniform vec4 uni_tes_left;\n"
+ "uniform vec4 uni_tes_right;\n"
+ "\n"
+ "in vec4 tcs_tes_result[];\n"
+ "\n"
+ "// Output\n"
+ "out vec4 tes_gs_result;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " tes_gs_result = routine(uni_tes_left, uni_tes_right) + tcs_tes_result[0];\n"
+ "}\n"
+ "\n";
+
+ static const GLchar* geometry_shader_code =
+ "#version 400 core\n"
+ "#extension GL_ARB_shader_subroutine : require\n"
+ "\n"
+ "precision highp float;\n"
+ "\n"
+ "layout(points) in;\n"
+ "layout(points, max_vertices = 1) out;\n"
+ "\n"
+ "// Subroutine type\n"
+ "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
+ "\n"
+ "// Subroutine definition\n"
+ "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left + right;\n"
+ "}\n"
+ "\n"
+ "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left * right;\n"
+ "}\n"
+ "\n"
+ "// Sub routine uniform\n"
+ "subroutine uniform routine_type routine;\n"
+ "\n"
+ "// Input data\n"
+ "uniform vec4 uni_gs_left;\n"
+ "uniform vec4 uni_gs_right;\n"
+ "\n"
+ "in vec4 tes_gs_result[];\n"
+ "\n"
+ "// Output\n"
+ "out vec4 gs_fs_result;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gs_fs_result = routine(uni_gs_left, uni_gs_right) + tes_gs_result[0];\n"
+ "}\n"
+ "\n";
+
+ static const GLchar* fragmenty_shader_code =
+ "#version 400 core\n"
+ "#extension GL_ARB_shader_subroutine : require\n"
+ "\n"
+ "precision highp float;\n"
+ "\n"
+ "// Subroutine type\n"
+ "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
+ "\n"
+ "// Subroutine definition\n"
+ "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left + right;\n"
+ "}\n"
+ "\n"
+ "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
+ "{\n"
+ " return left * right;\n"
+ "}\n"
+ "\n"
+ "// Sub routine uniform\n"
+ "subroutine uniform routine_type routine;\n"
+ "\n"
+ "// Input data\n"
+ "uniform vec4 uni_fs_left;\n"
+ "uniform vec4 uni_fs_right;\n"
+ "\n"
+ "in vec4 gs_fs_result;\n"
+ "\n"
+ "// Output\n"
+ "out vec4 fs_out_result;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " fs_out_result = routine(uni_fs_left, uni_fs_right) + gs_fs_result;\n"
+ "}\n"
+ "\n";
+
+ out_vertex_shader_code = vertex_shader_code;
+ out_tesselation_control_shader_code = tesselation_control_shader_code;
+ out_tesselation_evaluation_shader_code = tesselation_evaluation_shader_code;
+ out_geometry_shader_code = geometry_shader_code;
+ out_fragment_shader_code = fragmenty_shader_code;
+}
+
+/** Create <m_n_shared_contexts> shared contexts
+ *
+ **/
+void UniformPreservationTest::initSharedContexts()
+{
+ glu::ContextType context_type(m_api_type);
+ glu::RenderConfig render_config(context_type);
+ const tcu::CommandLine& command_line(m_testCtx.getCommandLine());
+ glu::RenderContext* shared_context = &(m_base_context->getRenderContext());
+ glu::parseRenderConfig(&render_config, command_line);
+
+#if (DE_OS == DE_OS_ANDROID)
+ // Android can only have one Window created at a time
+ // Note that this surface type is not supported on all platforms
+ render_config.surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
+#endif
+
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i] =
+ glu::createRenderContext(m_testCtx.getPlatform(), command_line, render_config, shared_context);
+ }
+ m_base_context->getRenderContext().makeCurrent();
+}
+
+/** Prepare program(s)
+ *
+ * @param programs An array of 5 programs' pointers. If monolithic program is prepared that only index m_fragment_stage_index should be initialized, otherwise all 5
+ * @param is_separable Select if monolithic or separable programs should be prepared
+ **/
+void UniformPreservationTest::prepareProgram(Utils::program** programs, bool is_separable)
+{
+ /* Get shader sources */
+ const GLchar* vertex_shader_code;
+ const GLchar* tesselation_control_shader_code;
+ const GLchar* tesselation_evaluation_shader_code;
+ const GLchar* geometry_shader_code;
+ const GLchar* fragmenty_shader_code;
+
+ getShaders(vertex_shader_code, tesselation_control_shader_code, tesselation_evaluation_shader_code,
+ geometry_shader_code, fragmenty_shader_code);
+
+ /* Subroutines and uniform names */
+ static const GLchar* subroutine_names[] = { "add", "multiply" };
+ static const GLuint n_subroutines = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
+
+ static const GLchar* subroutine_uniform_name = "routine";
+
+ /* Build program */
+ if (false == is_separable)
+ {
+ programs[0]->build(0 /* compute shader source */, fragmenty_shader_code, geometry_shader_code,
+ tesselation_control_shader_code, tesselation_evaluation_shader_code, vertex_shader_code,
+ 0 /* varying_names */, 0 /* n_varying_names */);
+
+ programs[m_geometry_stage_index] = programs[m_fragment_stage_index];
+ programs[m_tesselation_control_stage_index] = programs[m_fragment_stage_index];
+ programs[m_tesselation_evaluation_stage_index] = programs[m_fragment_stage_index];
+ programs[m_vertex_stage_index] = programs[m_fragment_stage_index];
+ }
+ else
+ {
+ programs[m_fragment_stage_index]->build(0, fragmenty_shader_code, 0, 0, 0, 0, 0, 0, true);
+ programs[m_geometry_stage_index]->build(0, 0, geometry_shader_code, 0, 0, 0, 0, 0, true);
+ programs[m_tesselation_control_stage_index]->build(0, 0, 0, tesselation_control_shader_code, 0, 0, 0, 0, true);
+ programs[m_tesselation_evaluation_stage_index]->build(0, 0, 0, 0, tesselation_evaluation_shader_code, 0, 0, 0,
+ true);
+ programs[m_vertex_stage_index]->build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0, true);
+ }
+
+ /* Get subroutine indices */
+ for (GLuint i = 0; i < n_subroutines; ++i)
+ {
+ m_subroutine_indices[i].m_fragment_shader_stage =
+ programs[m_fragment_stage_index]->getSubroutineIndex(subroutine_names[i], GL_FRAGMENT_SHADER);
+
+ m_subroutine_indices[i].m_geometry_shader_stage =
+ programs[m_geometry_stage_index]->getSubroutineIndex(subroutine_names[i], GL_GEOMETRY_SHADER);
+
+ m_subroutine_indices[i].m_tesselation_control_shader_stage =
+ programs[m_tesselation_control_stage_index]->getSubroutineIndex(subroutine_names[i],
+ GL_TESS_CONTROL_SHADER);
+
+ m_subroutine_indices[i].m_tesselation_evaluation_shader_stage =
+ programs[m_tesselation_evaluation_stage_index]->getSubroutineIndex(subroutine_names[i],
+ GL_TESS_EVALUATION_SHADER);
+
+ m_subroutine_indices[i].m_vertex_shader_stage =
+ programs[m_vertex_stage_index]->getSubroutineIndex(subroutine_names[i], GL_VERTEX_SHADER);
+ }
+
+ /* Get subroutine uniform locations */
+ m_subroutine_uniform_locations.m_fragment_shader_stage =
+ programs[m_fragment_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_FRAGMENT_SHADER);
+
+ m_subroutine_uniform_locations.m_geometry_shader_stage =
+ programs[m_geometry_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_GEOMETRY_SHADER);
+
+ m_subroutine_uniform_locations.m_tesselation_control_shader_stage =
+ programs[m_tesselation_control_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
+ GL_TESS_CONTROL_SHADER);
+
+ m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage =
+ programs[m_tesselation_evaluation_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
+ GL_TESS_EVALUATION_SHADER);
+
+ m_subroutine_uniform_locations.m_vertex_shader_stage =
+ programs[m_vertex_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_VERTEX_SHADER);
+}
+
+/** Generate program pipeline for current context and attach separable programs
+ *
+ * @param out_pipeline_id Id of generated pipeline
+ * @param programs Collection of separable programs
+ **/
+void UniformPreservationTest::prepareProgramPipeline(glw::GLuint& out_pipeline_id, Utils::program** programs)
+{
+ /* GL entry points */
+ const glw::Functions& gl = m_base_context->getRenderContext().getFunctions();
+
+ /* Generate */
+ gl.genProgramPipelines(1, &out_pipeline_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GenProgramPipelines");
+
+ /* Bind */
+ gl.bindProgramPipeline(out_pipeline_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "BindProgramPipeline");
+
+ /* Set up programs */
+ gl.useProgramStages(out_pipeline_id, GL_FRAGMENT_SHADER_BIT, programs[m_fragment_stage_index]->m_program_object_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
+
+ gl.useProgramStages(out_pipeline_id, GL_GEOMETRY_SHADER_BIT, programs[m_geometry_stage_index]->m_program_object_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
+
+ gl.useProgramStages(out_pipeline_id, GL_TESS_CONTROL_SHADER_BIT,
+ programs[m_tesselation_control_stage_index]->m_program_object_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
+
+ gl.useProgramStages(out_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT,
+ programs[m_tesselation_evaluation_stage_index]->m_program_object_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
+
+ gl.useProgramStages(out_pipeline_id, GL_VERTEX_SHADER_BIT, programs[m_vertex_stage_index]->m_program_object_id);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
+}
+
+/** Test specific case
+ *
+ * @param bit_field An array of 5 bit fields used to set up subroutine uniforms, one element per context
+ *
+ * @return True if test pass, false otherwise
+ **/
+bool UniformPreservationTest::testCase(const glw::GLuint bit_field[5])
+{
+ /* Storage for subroutine indices */
+ subroutineUniformSet captured_subroutine_indices[m_n_shared_contexts + 1];
+ subroutineUniformSet subroutine_indices[m_n_shared_contexts + 1];
+
+ /* Prepare subroutine_indices with bit fields */
+ for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
+ {
+ subroutine_indices[i].set(bit_field[i], m_subroutine_indices);
+ };
+
+ /* Update subroutine uniforms, each context gets different set */
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i]->makeCurrent();
+ updateCurrentSubroutineSet(subroutine_indices[i]);
+ }
+
+ m_base_context->getRenderContext().makeCurrent();
+ updateCurrentSubroutineSet(subroutine_indices[m_n_shared_contexts]);
+
+ /* Capture subroutine uniforms */
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i]->makeCurrent();
+ captureCurrentSubroutineSet(captured_subroutine_indices[i]);
+ }
+
+ m_base_context->getRenderContext().makeCurrent();
+ captureCurrentSubroutineSet(captured_subroutine_indices[m_n_shared_contexts]);
+
+ /* Verify that captured uniforms match expected values */
+ for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
+ {
+ if (subroutine_indices[i] != captured_subroutine_indices[i])
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message << "Error."
+ << " Context: " << i << " VS, expected: " << subroutine_indices[i].m_vertex_shader_stage
+ << " captured: " << captured_subroutine_indices[i].m_vertex_shader_stage
+ << " TCS, expected: " << subroutine_indices[i].m_tesselation_control_shader_stage
+ << " captured: " << captured_subroutine_indices[i].m_tesselation_control_shader_stage
+ << " TES, expected: " << subroutine_indices[i].m_tesselation_evaluation_shader_stage
+ << " captured: " << captured_subroutine_indices[i].m_tesselation_evaluation_shader_stage
+ << " GS, expected: " << subroutine_indices[i].m_geometry_shader_stage
+ << " captured: " << captured_subroutine_indices[i].m_geometry_shader_stage
+ << " FS, expected: " << subroutine_indices[i].m_fragment_shader_stage
+ << " captured: " << captured_subroutine_indices[i].m_fragment_shader_stage
+ << tcu::TestLog::EndMessage;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/** Test a program or pipeline
+ *
+ * @param programs An array of 5 programs\ pointers, as in preparePrograms
+ * @param is_separable Selects if monolithic or separable programs should be used
+ * @param test_cases Collection of test cases
+ * @param n_test_cases Number of test cases
+ *
+ * @return True if all cases pass, false otherwise
+ **/
+bool UniformPreservationTest::testProgram(Utils::program** programs, bool is_separable,
+ const glw::GLuint test_cases[][5], glw::GLuint n_test_cases)
+{
+ /* Set program/pipeline as current for all contexts */
+ if (false == is_separable)
+ {
+ programs[0]->use();
+
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i]->makeCurrent();
+ programs[0]->use();
+ }
+ }
+ else
+ {
+ /* GL entry points */
+ const glw::Functions& gl = m_base_context->getRenderContext().getFunctions();
+
+ /* Make sure that program pipeline will be used */
+ gl.useProgram(0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
+
+ prepareProgramPipeline(m_program_pipelines[m_n_shared_contexts], programs);
+
+ for (GLuint i = 0; i < m_n_shared_contexts; ++i)
+ {
+ m_shared_contexts[i]->makeCurrent();
+
+ /* Make sure that program pipeline will be used */
+ gl.useProgram(0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
+
+ prepareProgramPipeline(m_program_pipelines[i], programs);
+ }
+ }
+
+ /* Execute test */
+ bool result = true;
+ for (GLuint i = 0; i < n_test_cases; ++i)
+ {
+ if (false == testCase(test_cases[i]))
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/** Set up subroutine uniforms for current program or pipeline
+ *
+ * @param set Set of subroutine indices
+ **/
+void UniformPreservationTest::updateCurrentSubroutineSet(const subroutineUniformSet& set)
+{
+ /* GL entry points */
+ const glw::Functions& gl = m_base_context->getRenderContext().getFunctions();
+
+ /* Fragment */
+ gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1 /* count */, &set.m_fragment_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
+
+ /* Geometry */
+ gl.uniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1 /* count */, &set.m_geometry_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
+
+ /* Tess ctrl */
+ gl.uniformSubroutinesuiv(GL_TESS_CONTROL_SHADER, 1 /* count */, &set.m_tesselation_control_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
+
+ /* Tess eval */
+ gl.uniformSubroutinesuiv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &set.m_tesselation_evaluation_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
+
+ /* Vertex */
+ gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &set.m_vertex_shader_stage);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
+}
+
+/** Constructor.
+ *
+ * @param context Rendering context.
+ **/
+MultipleContextsTests::MultipleContextsTests(tcu::TestContext& testCtx, glu::ApiType apiType)
+ : tcu::TestCaseGroup(testCtx, "multiple_contexts", "Verifies \"shader_subroutine\" functionality")
+ , m_apiType(apiType)
+{
+ /* Left blank on purpose */
+}
+
+/** Initializes a texture_storage_multisample test group.
+ *
+ **/
+void MultipleContextsTests::init(void)
+{
+ addChild(new UniformPreservationTest(m_testCtx, m_apiType));
+}
+
+} /* glcts namespace */
--- /dev/null
+#ifndef _GLCMULTIPLECONTEXTSTESTS_HPP
+#define _GLCMULTIPLECONTEXTSTESTS_HPP
+/*-------------------------------------------------------------------------
+ * OpenGL Conformance Test Suite
+ * -----------------------------
+ *
+ * Copyright (c) 2017 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 glcMultipleContextsTests.hpp
+ * \brief
+ */ /*-------------------------------------------------------------------*/
+
+#include "glcTestCase.hpp"
+#include "glwDefs.hpp"
+#include <queue>
+
+#include "tcuTestLog.hpp"
+
+namespace glcts
+{
+
+/** Group class for Shader Subroutine conformance tests */
+class MultipleContextsTests : public tcu::TestCaseGroup
+{
+public:
+ /* Public methods */
+ MultipleContextsTests(tcu::TestContext& testCtx, glu::ApiType apiType);
+ virtual ~MultipleContextsTests()
+ {
+ }
+
+ virtual void init(void);
+
+private:
+ /* Private methods */
+ MultipleContextsTests(const MultipleContextsTests&);
+ MultipleContextsTests& operator=(const MultipleContextsTests&);
+
+ /* Private members */
+ glu::ApiType m_apiType;
+};
+
+} /* gl4cts namespace */
+
+#endif // _GLCMULTIPLECONTEXTSTESTS_HPP
#include "glcNoDefaultContextPackage.hpp"
#include "glcContextFlagsTests.hpp"
+#include "glcMultipleContextsTests.hpp"
#include "glcNoErrorTests.hpp"
#include "glcRobustnessTests.hpp"
#include "gluRenderContext.hpp"
gl30Group->addChild(new glcts::NoErrorTests(getTestContext(), glu::ApiType::core(3, 0)));
addChild(gl30Group);
+ tcu::TestCaseGroup* gl40Group = new tcu::TestCaseGroup(getTestContext(), "gl40", "");
+ gl40Group->addChild(new glcts::MultipleContextsTests(getTestContext(), glu::ApiType::core(4, 0)));
+ addChild(gl40Group);
+
tcu::TestCaseGroup* gl45Group = new tcu::TestCaseGroup(getTestContext(), "gl45", "");
gl45Group->addChild(new glcts::RobustnessTests(getTestContext(), glu::ApiType::core(4, 5)));
gl45Group->addChild(new glcts::ContextFlagsTests(getTestContext(), glu::ApiType::core(4, 5)));
} /* for (all drawn points) */
}
-/* Constants used by FunctionalTest20_21 */
-const GLuint FunctionalTest20_21::m_n_shared_contexts = 4;
-const GLuint FunctionalTest20_21::m_fragment_stage_index = 0;
-const GLuint FunctionalTest20_21::m_geometry_stage_index = 1;
-const GLuint FunctionalTest20_21::m_tesselation_control_stage_index = 2;
-const GLuint FunctionalTest20_21::m_tesselation_evaluation_stage_index = 3;
-const GLuint FunctionalTest20_21::m_vertex_stage_index = 4;
-
-/** Set subroutine indices, indices are taken from one of two sets according to provided <bit_field>
- *
- * @param bit_field Selects source of of index for each stage
- * @param subroutine_indices Array of two indices sets
- **/
-void FunctionalTest20_21::subroutineUniformSet::set(GLuint bit_field, const subroutineUniformSet subroutine_indices[2])
-{
- GLuint vertex_stage = ((bit_field & (0x01 << 0)) >> 0);
- GLuint tesselation_control_stage = ((bit_field & (0x01 << 1)) >> 1);
- GLuint tesselation_evaluation_stage = ((bit_field & (0x01 << 2)) >> 2);
- GLuint geometry_stage = ((bit_field & (0x01 << 3)) >> 3);
- GLuint fragment_stage = ((bit_field & (0x01 << 4)) >> 4);
-
- m_vertex_shader_stage = subroutine_indices[vertex_stage].m_vertex_shader_stage;
- m_tesselation_control_shader_stage =
- subroutine_indices[tesselation_control_stage].m_tesselation_control_shader_stage;
- m_tesselation_evaluation_shader_stage =
- subroutine_indices[tesselation_evaluation_stage].m_tesselation_evaluation_shader_stage;
- m_geometry_shader_stage = subroutine_indices[geometry_stage].m_geometry_shader_stage;
- m_fragment_shader_stage = subroutine_indices[fragment_stage].m_fragment_shader_stage;
-}
-
-/** Negated comparison of two sets
- *
- * @param arg Instance that will be compared to this
- *
- * @return false when both objects are equal, true otherwise
- **/
-bool FunctionalTest20_21::subroutineUniformSet::operator!=(const subroutineUniformSet& arg) const
-{
- if ((arg.m_vertex_shader_stage != m_vertex_shader_stage) ||
- (arg.m_tesselation_control_shader_stage != m_tesselation_control_shader_stage) ||
- (arg.m_tesselation_evaluation_shader_stage != m_tesselation_evaluation_shader_stage) ||
- (arg.m_geometry_shader_stage != m_geometry_shader_stage) ||
- (arg.m_fragment_shader_stage != m_fragment_shader_stage))
- {
- return true;
- }
-
- return false;
-}
-
-/** Constructor.
- *
- * @param context Rendering context.
- *
- **/
-FunctionalTest20_21::FunctionalTest20_21(deqp::Context& context)
- : TestCase(context, "multiple_contexts",
- "Verifies that shader uniforms are preserved when rendering context is switched.")
-{
- for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
- {
- m_program_pipelines[i] = 0;
- }
-
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i] = 0;
- }
-}
-
-/** Deinitializes all GL objects that may have been created during
- * test execution.
- **/
-void FunctionalTest20_21::deinit()
-{
- /* GL entry points */
- const glw::Functions& gl = m_context.getRenderContext().getFunctions();
-
- for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
- {
- if (0 != m_program_pipelines[i])
- {
- gl.deleteProgramPipelines(1, &m_program_pipelines[i]);
- m_program_pipelines[i] = 0;
- }
- }
-
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- if (0 != m_shared_contexts[i])
- {
- delete m_shared_contexts[i];
- m_shared_contexts[i] = 0;
- }
- }
-
- m_context.getRenderContext().makeCurrent();
-}
-
-/** Executes test iteration.
- *
- * @return Returns STOP
- */
-tcu::TestNode::IterateResult FunctionalTest20_21::iterate()
-{
- /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
- if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
- {
- throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
- }
-
- /* Test cases, values stored here are used as bit fields */
- static const GLuint test_cases[][m_n_shared_contexts + 1] = {
- { 0, 1, 2, 3, 4 }, { 1, 2, 3, 4, 0 }, { 2, 3, 4, 0, 1 }, { 3, 4, 0, 1, 2 },
- { 4, 0, 1, 2, 3 }, { 27, 28, 29, 30, 31 }, { 28, 29, 30, 31, 27 }, { 29, 30, 31, 27, 28 },
- { 30, 31, 27, 28, 29 }, { 31, 27, 28, 29, 30 },
- };
- static const GLuint n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
-
- /* Prepare contexts */
- initSharedContexts();
-
- /* Test result */
- bool result = true;
-
- /* Program pointers */
- Utils::program* program_pointers[5];
-
- /* Test monolithic program */
- {
- /* Prepare program */
- Utils::program program(m_context);
-
- program_pointers[m_fragment_stage_index] = &program;
-
- prepareProgram(program_pointers, false);
-
- /* Execute test */
- if (false == testProgram(program_pointers, false, test_cases, n_test_cases))
- {
- m_context.getTestContext().getLog() << tcu::TestLog::Message
- << "Last error message was caused by monolithic program."
- << tcu::TestLog::EndMessage;
-
- result = false;
- }
- }
-
- /* Test separable programs */
- if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
- {
- /* Prepare programs */
- Utils::program vertex_program(m_context);
- Utils::program tesselation_control_program(m_context);
- Utils::program tesselation_evaluation_program(m_context);
- Utils::program geometry_program(m_context);
- Utils::program fragment_program(m_context);
-
- program_pointers[m_fragment_stage_index] = &fragment_program;
- program_pointers[m_geometry_stage_index] = &geometry_program;
- program_pointers[m_tesselation_control_stage_index] = &tesselation_control_program;
- program_pointers[m_tesselation_evaluation_stage_index] = &tesselation_evaluation_program;
- program_pointers[m_vertex_stage_index] = &vertex_program;
-
- prepareProgram(program_pointers, true);
-
- /* Execute test */
- if (false == testProgram(program_pointers, true, test_cases, n_test_cases))
- {
- m_context.getTestContext().getLog() << tcu::TestLog::Message
- << "Last error message was caused by separable program."
- << tcu::TestLog::EndMessage;
- result = false;
- }
- }
-
- /* All done */
- if (true == result)
- {
- m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
- }
- else
- {
- m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
- }
-
- return tcu::TestNode::STOP;
-}
-
-/** Query state of subroutine uniforms of current program/pipeline
- *
- * @param set Storage for results
- **/
-void FunctionalTest20_21::captureCurrentSubroutineSet(subroutineUniformSet& set)
-{
- /* GL entry points */
- const glw::Functions& gl = m_context.getRenderContext().getFunctions();
-
- /* Fragment */
- gl.getUniformSubroutineuiv(GL_FRAGMENT_SHADER, m_subroutine_uniform_locations.m_fragment_shader_stage,
- &set.m_fragment_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
-
- /* Geometry */
- gl.getUniformSubroutineuiv(GL_GEOMETRY_SHADER, m_subroutine_uniform_locations.m_geometry_shader_stage,
- &set.m_geometry_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
-
- /* Tess ctrl */
- gl.getUniformSubroutineuiv(GL_TESS_CONTROL_SHADER,
- m_subroutine_uniform_locations.m_tesselation_control_shader_stage,
- &set.m_tesselation_control_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
-
- /* Tess eval */
- gl.getUniformSubroutineuiv(GL_TESS_EVALUATION_SHADER,
- m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage,
- &set.m_tesselation_evaluation_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
-
- /* Vertex */
- gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_subroutine_uniform_locations.m_vertex_shader_stage,
- &set.m_vertex_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
-}
-
-/** Get shaders' source code
- *
- * @param out_vertex_shader_code Vertex source code
- * @param out_tesselation_control_shader_code Tess ctrl source code
- * @param out_tesselation_evaluation_shader_code Tess eval source code
- * @param out_geometry_shader_code Geometry source code
- * @param out_fragment_shader_code Fragment source code
- **/
-void FunctionalTest20_21::getShaders(const glw::GLchar*& out_vertex_shader_code,
- const glw::GLchar*& out_tesselation_control_shader_code,
- const glw::GLchar*& out_tesselation_evaluation_shader_code,
- const glw::GLchar*& out_geometry_shader_code,
- const glw::GLchar*& out_fragment_shader_code)
-{
- static const GLchar* vertex_shader_code = "#version 400 core\n"
- "#extension GL_ARB_shader_subroutine : require\n"
- "\n"
- "precision highp float;\n"
- "\n"
- "// Subroutine type\n"
- "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
- "\n"
- "// Subroutine definition\n"
- "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left + right;\n"
- "}\n"
- "\n"
- "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left * right;\n"
- "}\n"
- "\n"
- "// Sub routine uniform\n"
- "subroutine uniform routine_type routine;\n"
- "\n"
- "// Input data\n"
- "uniform vec4 uni_vs_left;\n"
- "uniform vec4 uni_vs_right;\n"
- "\n"
- "// Output\n"
- "out vec4 vs_tcs_result;\n"
- "\n"
- "void main()\n"
- "{\n"
- " vs_tcs_result = routine(uni_vs_left, uni_vs_right);\n"
- "}\n"
- "\n";
-
- static const GLchar* tesselation_control_shader_code =
- "#version 400 core\n"
- "#extension GL_ARB_shader_subroutine : require\n"
- "\n"
- "precision highp float;\n"
- "\n"
- "layout(vertices = 1) out;\n"
- "\n"
- "// Subroutine type\n"
- "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
- "\n"
- "// Subroutine definition\n"
- "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left + right;\n"
- "}\n"
- "\n"
- "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left * right;\n"
- "}\n"
- "\n"
- "// Sub routine uniform\n"
- "subroutine uniform routine_type routine;\n"
- "\n"
- "// Input data\n"
- "uniform vec4 uni_tcs_left;\n"
- "uniform vec4 uni_tcs_right;\n"
- "\n"
- "in vec4 vs_tcs_result[];\n"
- "\n"
- "// Output\n"
- "out vec4 tcs_tes_result[];\n"
- "\n"
- "void main()\n"
- "{\n"
- " gl_TessLevelOuter[0] = 1.0;\n"
- " gl_TessLevelOuter[1] = 1.0;\n"
- " gl_TessLevelOuter[2] = 1.0;\n"
- " gl_TessLevelOuter[3] = 1.0;\n"
- " gl_TessLevelInner[0] = 1.0;\n"
- " gl_TessLevelInner[1] = 1.0;\n"
- "\n"
- " tcs_tes_result[gl_InvocationID] = routine(uni_tcs_left, uni_tcs_right) + vs_tcs_result[gl_InvocationID];\n"
- "}\n"
- "\n";
-
- static const GLchar* tesselation_evaluation_shader_code =
- "#version 400 core\n"
- "#extension GL_ARB_shader_subroutine : require\n"
- "\n"
- "precision highp float;\n"
- "\n"
- "layout(isolines, point_mode) in;\n"
- "\n"
- "// Subroutine type\n"
- "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
- "\n"
- "// Subroutine definition\n"
- "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left + right;\n"
- "}\n"
- "\n"
- "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left * right;\n"
- "}\n"
- "\n"
- "// Sub routine uniform\n"
- "subroutine uniform routine_type routine;\n"
- "\n"
- "// Input data\n"
- "uniform vec4 uni_tes_left;\n"
- "uniform vec4 uni_tes_right;\n"
- "\n"
- "in vec4 tcs_tes_result[];\n"
- "\n"
- "// Output\n"
- "out vec4 tes_gs_result;\n"
- "\n"
- "void main()\n"
- "{\n"
- " tes_gs_result = routine(uni_tes_left, uni_tes_right) + tcs_tes_result[0];\n"
- "}\n"
- "\n";
-
- static const GLchar* geometry_shader_code =
- "#version 400 core\n"
- "#extension GL_ARB_shader_subroutine : require\n"
- "\n"
- "precision highp float;\n"
- "\n"
- "layout(points) in;\n"
- "layout(points, max_vertices = 1) out;\n"
- "\n"
- "// Subroutine type\n"
- "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
- "\n"
- "// Subroutine definition\n"
- "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left + right;\n"
- "}\n"
- "\n"
- "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left * right;\n"
- "}\n"
- "\n"
- "// Sub routine uniform\n"
- "subroutine uniform routine_type routine;\n"
- "\n"
- "// Input data\n"
- "uniform vec4 uni_gs_left;\n"
- "uniform vec4 uni_gs_right;\n"
- "\n"
- "in vec4 tes_gs_result[];\n"
- "\n"
- "// Output\n"
- "out vec4 gs_fs_result;\n"
- "\n"
- "void main()\n"
- "{\n"
- " gs_fs_result = routine(uni_gs_left, uni_gs_right) + tes_gs_result[0];\n"
- "}\n"
- "\n";
-
- static const GLchar* fragmenty_shader_code =
- "#version 400 core\n"
- "#extension GL_ARB_shader_subroutine : require\n"
- "\n"
- "precision highp float;\n"
- "\n"
- "// Subroutine type\n"
- "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
- "\n"
- "// Subroutine definition\n"
- "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left + right;\n"
- "}\n"
- "\n"
- "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
- "{\n"
- " return left * right;\n"
- "}\n"
- "\n"
- "// Sub routine uniform\n"
- "subroutine uniform routine_type routine;\n"
- "\n"
- "// Input data\n"
- "uniform vec4 uni_fs_left;\n"
- "uniform vec4 uni_fs_right;\n"
- "\n"
- "in vec4 gs_fs_result;\n"
- "\n"
- "// Output\n"
- "out vec4 fs_out_result;\n"
- "\n"
- "void main()\n"
- "{\n"
- " fs_out_result = routine(uni_fs_left, uni_fs_right) + gs_fs_result;\n"
- "}\n"
- "\n";
-
- out_vertex_shader_code = vertex_shader_code;
- out_tesselation_control_shader_code = tesselation_control_shader_code;
- out_tesselation_evaluation_shader_code = tesselation_evaluation_shader_code;
- out_geometry_shader_code = geometry_shader_code;
- out_fragment_shader_code = fragmenty_shader_code;
-}
-
-/** Create <m_n_shared_contexts> shared contexts
- *
- **/
-void FunctionalTest20_21::initSharedContexts()
-{
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i] = m_context.createSharedContext();
- }
-}
-
-/** Prepare program(s)
- *
- * @param programs An array of 5 programs' pointers. If monolithic program is prepared that only index m_fragment_stage_index should be initialized, otherwise all 5
- * @param is_separable Select if monolithic or separable programs should be prepared
- **/
-void FunctionalTest20_21::prepareProgram(Utils::program** programs, bool is_separable)
-{
- /* Get shader sources */
- const GLchar* vertex_shader_code;
- const GLchar* tesselation_control_shader_code;
- const GLchar* tesselation_evaluation_shader_code;
- const GLchar* geometry_shader_code;
- const GLchar* fragmenty_shader_code;
-
- getShaders(vertex_shader_code, tesselation_control_shader_code, tesselation_evaluation_shader_code,
- geometry_shader_code, fragmenty_shader_code);
-
- /* Subroutines and uniform names */
- static const GLchar* subroutine_names[] = { "add", "multiply" };
- static const GLuint n_subroutines = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
-
- static const GLchar* subroutine_uniform_name = "routine";
-
- /* Build program */
- if (false == is_separable)
- {
- programs[0]->build(0 /* compute shader source */, fragmenty_shader_code, geometry_shader_code,
- tesselation_control_shader_code, tesselation_evaluation_shader_code, vertex_shader_code,
- 0 /* varying_names */, 0 /* n_varying_names */);
-
- programs[m_geometry_stage_index] = programs[m_fragment_stage_index];
- programs[m_tesselation_control_stage_index] = programs[m_fragment_stage_index];
- programs[m_tesselation_evaluation_stage_index] = programs[m_fragment_stage_index];
- programs[m_vertex_stage_index] = programs[m_fragment_stage_index];
- }
- else
- {
- programs[m_fragment_stage_index]->build(0, fragmenty_shader_code, 0, 0, 0, 0, 0, 0, true);
- programs[m_geometry_stage_index]->build(0, 0, geometry_shader_code, 0, 0, 0, 0, 0, true);
- programs[m_tesselation_control_stage_index]->build(0, 0, 0, tesselation_control_shader_code, 0, 0, 0, 0, true);
- programs[m_tesselation_evaluation_stage_index]->build(0, 0, 0, 0, tesselation_evaluation_shader_code, 0, 0, 0,
- true);
- programs[m_vertex_stage_index]->build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0, true);
- }
-
- /* Get subroutine indices */
- for (GLuint i = 0; i < n_subroutines; ++i)
- {
- m_subroutine_indices[i].m_fragment_shader_stage =
- programs[m_fragment_stage_index]->getSubroutineIndex(subroutine_names[i], GL_FRAGMENT_SHADER);
-
- m_subroutine_indices[i].m_geometry_shader_stage =
- programs[m_geometry_stage_index]->getSubroutineIndex(subroutine_names[i], GL_GEOMETRY_SHADER);
-
- m_subroutine_indices[i].m_tesselation_control_shader_stage =
- programs[m_tesselation_control_stage_index]->getSubroutineIndex(subroutine_names[i],
- GL_TESS_CONTROL_SHADER);
-
- m_subroutine_indices[i].m_tesselation_evaluation_shader_stage =
- programs[m_tesselation_evaluation_stage_index]->getSubroutineIndex(subroutine_names[i],
- GL_TESS_EVALUATION_SHADER);
-
- m_subroutine_indices[i].m_vertex_shader_stage =
- programs[m_vertex_stage_index]->getSubroutineIndex(subroutine_names[i], GL_VERTEX_SHADER);
- }
-
- /* Get subroutine uniform locations */
- m_subroutine_uniform_locations.m_fragment_shader_stage =
- programs[m_fragment_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_FRAGMENT_SHADER);
-
- m_subroutine_uniform_locations.m_geometry_shader_stage =
- programs[m_geometry_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_GEOMETRY_SHADER);
-
- m_subroutine_uniform_locations.m_tesselation_control_shader_stage =
- programs[m_tesselation_control_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
- GL_TESS_CONTROL_SHADER);
-
- m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage =
- programs[m_tesselation_evaluation_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
- GL_TESS_EVALUATION_SHADER);
-
- m_subroutine_uniform_locations.m_vertex_shader_stage =
- programs[m_vertex_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_VERTEX_SHADER);
-}
-
-/** Generate program pipeline for current context and attach separable programs
- *
- * @param out_pipeline_id Id of generated pipeline
- * @param programs Collection of separable programs
- **/
-void FunctionalTest20_21::prepareProgramPipeline(glw::GLuint& out_pipeline_id, Utils::program** programs)
-{
- /* GL entry points */
- const glw::Functions& gl = m_context.getRenderContext().getFunctions();
-
- /* Generate */
- gl.genProgramPipelines(1, &out_pipeline_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "GenProgramPipelines");
-
- /* Bind */
- gl.bindProgramPipeline(out_pipeline_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "BindProgramPipeline");
-
- /* Set up programs */
- gl.useProgramStages(out_pipeline_id, GL_FRAGMENT_SHADER_BIT, programs[m_fragment_stage_index]->m_program_object_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
-
- gl.useProgramStages(out_pipeline_id, GL_GEOMETRY_SHADER_BIT, programs[m_geometry_stage_index]->m_program_object_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
-
- gl.useProgramStages(out_pipeline_id, GL_TESS_CONTROL_SHADER_BIT,
- programs[m_tesselation_control_stage_index]->m_program_object_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
-
- gl.useProgramStages(out_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT,
- programs[m_tesselation_evaluation_stage_index]->m_program_object_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
-
- gl.useProgramStages(out_pipeline_id, GL_VERTEX_SHADER_BIT, programs[m_vertex_stage_index]->m_program_object_id);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
-}
-
-/** Test specific case
- *
- * @param bit_field An array of 5 bit fields used to set up subroutine uniforms, one element per context
- *
- * @return True if test pass, false otherwise
- **/
-bool FunctionalTest20_21::testCase(const glw::GLuint bit_field[5])
-{
- /* Storage for subroutine indices */
- subroutineUniformSet captured_subroutine_indices[m_n_shared_contexts + 1];
- subroutineUniformSet subroutine_indices[m_n_shared_contexts + 1];
-
- /* Prepare subroutine_indices with bit fields */
- for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
- {
- subroutine_indices[i].set(bit_field[i], m_subroutine_indices);
- };
-
- /* Update subroutine uniforms, each context gets different set */
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i]->makeCurrent();
- updateCurrentSubroutineSet(subroutine_indices[i]);
- }
-
- m_context.getRenderContext().makeCurrent();
- updateCurrentSubroutineSet(subroutine_indices[m_n_shared_contexts]);
-
- /* Capture subroutine uniforms */
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i]->makeCurrent();
- captureCurrentSubroutineSet(captured_subroutine_indices[i]);
- }
-
- m_context.getRenderContext().makeCurrent();
- captureCurrentSubroutineSet(captured_subroutine_indices[m_n_shared_contexts]);
-
- /* Verify that captured uniforms match expected values */
- for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
- {
- if (subroutine_indices[i] != captured_subroutine_indices[i])
- {
- m_context.getTestContext().getLog()
- << tcu::TestLog::Message << "Error."
- << " Context: " << i << " VS, expected: " << subroutine_indices[i].m_vertex_shader_stage
- << " captured: " << captured_subroutine_indices[i].m_vertex_shader_stage
- << " TCS, expected: " << subroutine_indices[i].m_tesselation_control_shader_stage
- << " captured: " << captured_subroutine_indices[i].m_tesselation_control_shader_stage
- << " TES, expected: " << subroutine_indices[i].m_tesselation_evaluation_shader_stage
- << " captured: " << captured_subroutine_indices[i].m_tesselation_evaluation_shader_stage
- << " GS, expected: " << subroutine_indices[i].m_geometry_shader_stage
- << " captured: " << captured_subroutine_indices[i].m_geometry_shader_stage
- << " FS, expected: " << subroutine_indices[i].m_fragment_shader_stage
- << " captured: " << captured_subroutine_indices[i].m_fragment_shader_stage << tcu::TestLog::EndMessage;
-
- return false;
- }
- }
-
- return true;
-}
-
-/** Test a program or pipeline
- *
- * @param programs An array of 5 programs\ pointers, as in preparePrograms
- * @param is_separable Selects if monolithic or separable programs should be used
- * @param test_cases Collection of test cases
- * @param n_test_cases Number of test cases
- *
- * @return True if all cases pass, false otherwise
- **/
-bool FunctionalTest20_21::testProgram(Utils::program** programs, bool is_separable, const glw::GLuint test_cases[][5],
- glw::GLuint n_test_cases)
-{
- /* Set program/pipeline as current for all contexts */
- if (false == is_separable)
- {
- programs[0]->use();
-
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i]->makeCurrent();
- programs[0]->use();
- }
- }
- else
- {
- /* GL entry points */
- const glw::Functions& gl = m_context.getRenderContext().getFunctions();
-
- /* Make sure that program pipeline will be used */
- gl.useProgram(0);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
-
- prepareProgramPipeline(m_program_pipelines[m_n_shared_contexts], programs);
-
- for (GLuint i = 0; i < m_n_shared_contexts; ++i)
- {
- m_shared_contexts[i]->makeCurrent();
-
- /* Make sure that program pipeline will be used */
- gl.useProgram(0);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
-
- prepareProgramPipeline(m_program_pipelines[i], programs);
- }
- }
-
- /* Execute test */
- bool result = true;
- for (GLuint i = 0; i < n_test_cases; ++i)
- {
- if (false == testCase(test_cases[i]))
- {
- result = false;
- break;
- }
- }
-
- return result;
-}
-
-/** Set up subroutine uniforms for current program or pipeline
- *
- * @param set Set of subroutine indices
- **/
-void FunctionalTest20_21::updateCurrentSubroutineSet(const subroutineUniformSet& set)
-{
- /* GL entry points */
- const glw::Functions& gl = m_context.getRenderContext().getFunctions();
-
- /* Fragment */
- gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1 /* count */, &set.m_fragment_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
-
- /* Geometry */
- gl.uniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1 /* count */, &set.m_geometry_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
-
- /* Tess ctrl */
- gl.uniformSubroutinesuiv(GL_TESS_CONTROL_SHADER, 1 /* count */, &set.m_tesselation_control_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
-
- /* Tess eval */
- gl.uniformSubroutinesuiv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &set.m_tesselation_evaluation_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
-
- /* Vertex */
- gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &set.m_vertex_shader_stage);
- GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
-}
-
/** Constructor.
*
* @param context Rendering context.
addChild(new ShaderSubroutine::FunctionalTest16(m_context));
addChild(new ShaderSubroutine::FunctionalTest17(m_context));
addChild(new ShaderSubroutine::FunctionalTest18_19(m_context));
- addChild(new ShaderSubroutine::FunctionalTest20_21(m_context));
addChild(new ShaderSubroutine::NegativeTest1(m_context));
addChild(new ShaderSubroutine::NegativeTest2(m_context));
addChild(new ShaderSubroutine::NegativeTest3(m_context));
};
/**
- * * Create multiple contexts and verify that subroutine uniforms values
- * are preserved for each program stage when switching rendering context.
- *
- * OpenGL 4.1 or ARB_separate_shader_objects support required
- * * Same as above, but use pipelines instead of monolithic program.
- **/
-class FunctionalTest20_21 : public deqp::TestCase
-{
-public:
- /* Public methods */
- FunctionalTest20_21(deqp::Context& context);
-
- virtual void deinit();
- virtual tcu::TestNode::IterateResult iterate();
-
-private:
- /* Private types */
- struct subroutineUniformSet
- {
- bool operator!=(const subroutineUniformSet& arg) const;
- void set(glw::GLuint bit_field, const subroutineUniformSet subroutine_indices[2]);
-
- glw::GLuint m_vertex_shader_stage;
- glw::GLuint m_tesselation_control_shader_stage;
- glw::GLuint m_tesselation_evaluation_shader_stage;
- glw::GLuint m_geometry_shader_stage;
- glw::GLuint m_fragment_shader_stage;
- };
-
- /* Private methods */
- void captureCurrentSubroutineSet(subroutineUniformSet& set);
-
- void getShaders(const glw::GLchar*& out_vertex_shader_code, const glw::GLchar*& out_tesselation_control_shader_code,
- const glw::GLchar*& out_tesselation_evaluation_shader_code,
- const glw::GLchar*& out_geometry_shader_code, const glw::GLchar*& out_fragment_shader_code);
-
- void initSharedContexts();
-
- void prepareProgram(Utils::program** programs, bool is_separable);
-
- void prepareProgramPipeline(glw::GLuint& pipeline_id, Utils::program** programs);
-
- bool testCase(const glw::GLuint bit_field[5]);
-
- bool testProgram(Utils::program** programs, bool is_separable, const glw::GLuint test_cases[][5],
- glw::GLuint n_test_cases);
-
- void updateCurrentSubroutineSet(const subroutineUniformSet& set);
-
- /* Private fields */
- static const glw::GLuint m_n_shared_contexts;
- static const glw::GLuint m_fragment_stage_index;
- static const glw::GLuint m_geometry_stage_index;
- static const glw::GLuint m_tesselation_control_stage_index;
- static const glw::GLuint m_tesselation_evaluation_stage_index;
- static const glw::GLuint m_vertex_stage_index;
-
- glw::GLuint m_program_pipelines[5];
- glu::RenderContext* m_shared_contexts[4];
- subroutineUniformSet m_subroutine_indices[2];
- subroutineUniformSet m_subroutine_uniform_locations;
-};
-
-/**
* Test whether all INVALID_OPERATION, INVALID_VALUE and INVALID_ENUM
* errors related to subroutines usage are properly generated.
**/
static const RunParams khronos_mustpass_gl_nocontext_first_cfg[] = {
{ glu::ApiType::core(3, 0), "khr-master", DE_NULL, "unspecified", 1, DE_NULL, 64, 64 },
+ { glu::ApiType::core(4, 0), "khr-master", DE_NULL, "unspecified", 1, DE_NULL, 64, 64 },
{ glu::ApiType::core(4, 5), "khr-master", DE_NULL, "unspecified", 1, DE_NULL, 64, 64 },
};
Module("GTF-GL31", "GL31"),
Module("GTF-GL30", "GL30"),
Module("KHR-NOCTX-GL30","GL30"),
+ Module("KHR-NOCTX-GL40","GL40"),
Module("KHR-NOCTX-GL45","GL45"),
]
GLCTS_BIN_NAME = "glcts"
def getCaseListFileName (module, caseListType):
mname = module.name
- if mname == "KHR-NOCTX-ES2" or mname == "KHR-NOCTX-ES32" or mname == "KHR-NOCTX-GL30" or mname == "KHR-NOCTX-GL45":
+ if mname == "KHR-NOCTX-ES2" or mname == "KHR-NOCTX-ES32" or mname == "KHR-NOCTX-GL30" or mname == "KHR-NOCTX-GL40" or mname == "KHR-NOCTX-GL45":
mname = "KHR-NoContext"
return "%s-cases.%s" % (mname, caseListType)
])
NOCTX_GL30_KHR_MODULE = getModuleByName("KHR-NOCTX-GL30")
+NOCTX_GL40_KHR_MODULE = getModuleByName("KHR-NOCTX-GL40")
NOCTX_GL45_KHR_MODULE = getModuleByName("KHR-NOCTX-GL45")
GLCTS_NOCTX_GL30_KHR_PKG = Package(module = NOCTX_GL30_KHR_MODULE, configurations = [
filters = [include("gl30-khr-master.txt")]),
])
+GLCTS_NOCTX_GL40_KHR_PKG = Package(module = NOCTX_GL40_KHR_MODULE, configurations = [
+ # Master
+ Configuration(name = "khr-master",
+ surfacewidth = "64",
+ surfaceheight = "64",
+ baseseed = "1",
+ filters = [include("gl40-khr-master.txt")]),
+ ])
+
GLCTS_NOCTX_GL45_KHR_PKG = Package(module = NOCTX_GL45_KHR_MODULE, configurations = [
# Master
Configuration(name = "khr-master",
gl_packages.append(pkg1)
mustpass = [Mustpass(project = GL_CTS_KHR_MP_PROJECT, version = "4.6.0.x", isCurrent=True, packages = gl_packages),
- Mustpass(project = GL_CTS_NOCTX_PROJECT, version = "4.6.0.x", isCurrent=True, packages = [GLCTS_NOCTX_GL30_KHR_PKG, GLCTS_NOCTX_GL45_KHR_PKG]),
+ Mustpass(project = GL_CTS_NOCTX_PROJECT, version = "4.6.0.x", isCurrent=True, packages = [GLCTS_NOCTX_GL30_KHR_PKG, GLCTS_NOCTX_GL40_KHR_PKG, GLCTS_NOCTX_GL45_KHR_PKG]),
]
return mustpass
#include "deDynamicLibrary.hpp"
#include "deSTLUtil.hpp"
+#include "deSharedPtr.hpp"
#include <string>
#include <string>
class RenderContext : public GLRenderContext
{
public:
- RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
+ RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config, const glu::RenderContext* sharedContext = DE_NULL);
virtual ~RenderContext (void);
virtual glu::ContextType getType (void) const { return m_renderConfig.type; }
virtual void makeCurrent (void);
private:
- void create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
+ void create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config, const glu::RenderContext* sharedContext);
void destroy (void);
const glu::RenderConfig m_renderConfig;
const NativeWindowFactory* const m_nativeWindowFactory; // Stored in case window must be re-created
- NativeDisplay* m_display;
+ de::SharedPtr<NativeDisplay> m_display;
NativeWindow* m_window;
NativePixmap* m_pixmap;
EGLConfig m_eglConfig;
EGLSurface m_eglSurface;
EGLContext m_eglContext;
+ EGLContext m_eglSharedContext;
tcu::RenderTarget m_glRenderTarget;
de::DynamicLibrary* m_dynamicGLLibrary;
glw::Functions m_glFunctions;
};
-RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
+RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config, const glu::RenderContext* sharedContext)
: m_renderConfig (config)
, m_nativeWindowFactory (windowFactory)
, m_display (DE_NULL)
, m_eglDisplay (EGL_NO_DISPLAY)
, m_eglSurface (EGL_NO_SURFACE)
, m_eglContext (EGL_NO_CONTEXT)
+ , m_eglSharedContext (EGL_NO_CONTEXT)
, m_dynamicGLLibrary (DE_NULL)
{
try
{
- create(displayFactory, windowFactory, pixmapFactory, config);
+ create(displayFactory, windowFactory, pixmapFactory, config, sharedContext);
}
catch (...)
{
delete m_window;
delete m_pixmap;
- delete m_display;
delete m_dynamicGLLibrary;
}
return (glw::GenericFuncType)m_display->getLibrary().getProcAddress(name);
}
-void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
+void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config, const glu::RenderContext *sharedContext)
{
glu::RenderConfig::SurfaceType surfaceType = config.surfaceType;
DE_ASSERT(displayFactory);
- m_display = displayFactory->createDisplay();
- m_eglDisplay = eglu::getDisplay(*m_display);
+ if (DE_NULL == sharedContext)
+ m_display = de::SharedPtr<NativeDisplay>(displayFactory->createDisplay());
+ else
+ {
+ const RenderContext* context = dynamic_cast<const RenderContext*>(sharedContext);
+ m_eglSharedContext = context->m_eglContext;
+ m_display = context->m_display;
+ }
+ m_eglDisplay = eglu::getDisplay(*m_display);
const Library& egl = m_display->getLibrary();
{
{
if (windowFactory)
{
- const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config);
+ const WindowSurfacePair windowSurface = createWindow(m_display.get(), windowFactory, m_eglDisplay, m_eglConfig, config);
m_window = windowSurface.first;
m_eglSurface = windowSurface.second;
}
{
if (pixmapFactory)
{
- const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config);
+ const PixmapSurfacePair pixmapSurface = createPixmap(m_display.get(), pixmapFactory, m_eglDisplay, m_eglConfig, config);
m_pixmap = pixmapSurface.first;
m_eglSurface = pixmapSurface.second;
}
throw tcu::InternalError("Invalid surface type");
}
- m_eglContext = createGLContext(egl, m_eglDisplay, m_eglConfig, config.type, config.resetNotificationStrategy);
+ m_eglContext = createGLContext(egl, m_eglDisplay, m_eglConfig, config.type, m_eglSharedContext, config.resetNotificationStrategy);
EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
if (m_eglContext != EGL_NO_CONTEXT)
EGLU_CHECK_CALL(egl, destroyContext(m_eglDisplay, m_eglContext));
- EGLU_CHECK_CALL(egl, terminate(m_eglDisplay));
+ if (m_eglSharedContext == EGL_NO_CONTEXT)
+ EGLU_CHECK_CALL(egl, terminate(m_eglDisplay));
m_eglDisplay = EGL_NO_DISPLAY;
m_eglSurface = EGL_NO_SURFACE;
delete m_window;
delete m_pixmap;
- delete m_display;
delete m_dynamicGLLibrary;
m_window = DE_NULL;
m_pixmap = DE_NULL;
- m_display = DE_NULL;
m_dynamicGLLibrary = DE_NULL;
}
try
{
- WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig);
+ WindowSurfacePair windowSurface = createWindow(m_display.get(), m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig);
m_window = windowSurface.first;
m_eglSurface = windowSurface.second;
{
}
-glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
+glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine, const glu::RenderContext *sharedContext) const
{
const NativeDisplayFactory& displayFactory = selectNativeDisplayFactory(m_displayFactoryRegistry, cmdLine);
pixmapFactory = DE_NULL;
}
- return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config);
+ return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config, sharedContext);
}
} // eglu
{
public:
GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry);
- virtual glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const;
+ virtual glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine, const glu::RenderContext *sharedContext) const;
private:
const NativeDisplayFactoryRegistry& m_displayFactoryRegistry;
EGLDisplay display,
EGLContext eglConfig,
const glu::ContextType& contextType,
+ eglw::EGLContext sharedContext,
glu::ResetNotificationStrategy resetNotificationStrategy)
{
const bool khrCreateContextSupported = hasExtension(egl, display, "EGL_KHR_create_context");
attribList.push_back(EGL_NONE);
EGLU_CHECK_CALL(egl, bindAPI(api));
- context = egl.createContext(display, eglConfig, EGL_NO_CONTEXT, &(attribList[0]));
+ context = egl.createContext(display, eglConfig, sharedContext, &(attribList[0]));
EGLU_CHECK_MSG(egl, "eglCreateContext()");
return context;
eglw::EGLDisplay display,
eglw::EGLConfig config,
const glu::ContextType& contextType,
+ eglw::EGLContext sharedContext = EGL_NO_CONTEXT,
glu::ResetNotificationStrategy resetNotificationStrategy = glu::RESET_NOTIFICATION_STRATEGY_NOT_SPECIFIED);
eglw::EGLConfig chooseConfig (const eglw::Library& egl,
* Only single context will be active concurrently and it will be accessed
* only from the calling thread.
*
- * \param config Rendering context configuration
- * \param cmdLine Command line for extra arguments
+ * \param config Rendering context configuration
+ * \param cmdLine Command line for extra arguments
+ * \param sharedContext Context with which objects should be shared
* \return Rendering context wrapper object.
*//*--------------------------------------------------------------------*/
- virtual RenderContext* createContext (const RenderConfig& config, const tcu::CommandLine& cmdLine) const = 0;
+ virtual RenderContext* createContext (const RenderConfig& config, const tcu::CommandLine& cmdLine, const glu::RenderContext* sharedContext) const = 0;
private:
ContextFactory (const ContextFactory&);
nativeRenderConfig.type = config.type;
nativeRenderConfig.windowVisibility = config.windowVisibility;
// \note All other properties are defaults, mostly DONT_CARE
- m_context = factory.createContext(nativeRenderConfig, cmdLine);
+ m_context = factory.createContext(nativeRenderConfig, cmdLine, DE_NULL);
createFramebuffer(config);
}
catch (...)
return flags;
}
-RenderContext* createRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, const RenderConfig& config)
+RenderContext* createRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, const RenderConfig& config, const RenderContext* sharedContext)
{
const ContextFactoryRegistry& registry = platform.getGLPlatform().getContextFactoryRegistry();
const char* factoryName = cmdLine.getGLContextType();
factory = registry.getDefaultFactory();
if (cmdLine.getSurfaceType() == tcu::SURFACETYPE_FBO)
+ {
+ if (sharedContext)
+ TCU_FAIL("Shared context not implemented for FBO surface type");
return new FboRenderContext(*factory, config, cmdLine);
+ }
else
- return factory->createContext(config, cmdLine);
+ return factory->createContext(config, cmdLine, sharedContext);
}
RenderContext* createDefaultRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, ApiType apiType)
// Utilities
-RenderContext* createRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, const RenderConfig& config);
+RenderContext* createRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, const RenderConfig& config, const RenderContext* sharedContext = DE_NULL);
RenderContext* createDefaultRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, ApiType apiType);
void initCoreFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType);
public:
GlxContextFactory (EventState& eventState);
~GlxContextFactory (void);
- RenderContext* createContext (const RenderConfig& config,
- const CommandLine& cmdLine) const;
+ RenderContext* createContext (const RenderConfig& config,
+ const CommandLine& cmdLine,
+ const glu::RenderContext* sharedContext) const;
EventState& getEventState (void) const { return m_eventState;}
Visual* getXVisual (void) { return m_visual; }
GLXContext createContext (const GlxContextFactory& factory,
const ContextType& contextType,
+ const glu::RenderContext* sharedContext,
glu::ResetNotificationStrategy resetNotificationStrategy);
GLXWindow createWindow (::Window xWindow);
GlxDisplay& getGlxDisplay (void) { return m_display; }
{
public:
GlxRenderContext (const GlxContextFactory& factory,
- const RenderConfig& config);
+ const RenderConfig& config,
+ const glu::RenderContext* sharedContext
+ );
~GlxRenderContext (void);
virtual ContextType getType (void) const;
virtual void postIterate (void);
void clearCurrent (void);
virtual const glw::Functions& getFunctions (void) const;
virtual const tcu::RenderTarget& getRenderTarget (void) const;
+ const GLXContext& getGLXContext (void) const;
private:
GlxDisplay m_glxDisplay;
XSetErrorHandler(tcuLnxX11GlxErrorHandler);
}
-RenderContext* GlxContextFactory::createContext (const RenderConfig& config,
- const CommandLine& cmdLine) const
+RenderContext* GlxContextFactory::createContext (const RenderConfig& config,
+ const CommandLine& cmdLine,
+ const glu::RenderContext* sharedContext) const
{
DE_UNREF(cmdLine);
- GlxRenderContext* const renderContext = new GlxRenderContext(*this, config);
+ GlxRenderContext* const renderContext = new GlxRenderContext(*this, config, sharedContext);
return renderContext;
}
GLXContext GlxVisual::createContext (const GlxContextFactory& factory,
const ContextType& contextType,
+ const glu::RenderContext* sharedContext,
glu::ResetNotificationStrategy resetNotificationStrategy)
{
std::vector<int> attribs;
// Terminate attrib list
attribs.push_back(None);
+ const GlxRenderContext* sharedGlxRenderContext = dynamic_cast<const GlxRenderContext*>(sharedContext);
+ const GLXContext& sharedGLXContext = sharedGlxRenderContext ? sharedGlxRenderContext->getGLXContext() : DE_NULL;
+
return TCU_CHECK_GLX(factory.m_glXCreateContextAttribsARB(
- getXDisplay(), m_fbConfig, DE_NULL, True, &attribs[0]));
+ getXDisplay(), m_fbConfig, sharedGLXContext, True, &attribs[0]));
}
GLXWindow GlxVisual::createWindow (::Window xWindow)
};
GlxRenderContext::GlxRenderContext (const GlxContextFactory& factory,
- const RenderConfig& config)
+ const RenderConfig& config,
+ const glu::RenderContext* sharedContext)
: m_glxDisplay (factory.getEventState(), DE_NULL)
, m_glxVisual (chooseVisual(m_glxDisplay, config))
, m_type (config.type)
- , m_GLXContext (m_glxVisual.createContext(factory, config.type, config.resetNotificationStrategy))
+ , m_GLXContext (m_glxVisual.createContext(factory, config.type, sharedContext, config.resetNotificationStrategy))
, m_glxDrawable (createDrawable(m_glxVisual, config))
, m_renderTarget (m_glxDrawable->getWidth(), m_glxDrawable->getHeight(),
PixelFormat(m_glxVisual.getAttrib(GLX_RED_SIZE),
return m_functions;
}
+const GLXContext& GlxRenderContext::getGLXContext (void) const
+{
+ return m_GLXContext;
+}
+
MovePtr<ContextFactory> createContextFactory (EventState& eventState)
{
return MovePtr<ContextFactory>(new GlxContextFactory(eventState));
{
}
-glu::RenderContext* NullGLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const
+glu::RenderContext* NullGLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine&, const glu::RenderContext*) const
{
return new RenderContext(config);
}
{
public:
NullGLContextFactory (void);
- glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const;
+ glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine&, const glu::RenderContext*) const;
};
} // null
Context::Context (const Core* core,
HDC deviceCtx,
+ const Context* sharedContext,
glu::ContextType ctxType,
int pixelFormat,
glu::ResetNotificationStrategy resetNotificationStrategy)
// Context version and profile
{
int profileBit = 0;
+ HGLRC sharedCtx = DE_NULL;
int minor = ctxType.getMinorVersion();
int major = ctxType.getMajorVersion();
throw ResourceError("Failed to set pixel format");
}
+ HGLRC sharedCtx = DE_NULL;
+ if (DE_NULL != sharedContext)
+ sharedCtx = sharedContext->m_context;
+
// Terminate attribList
attribList.push_back(0);
// Create context
- m_context = wgl.createContextAttribsARB(deviceCtx, (HGLRC)0, &attribList[0]);
+ m_context = wgl.createContextAttribsARB(deviceCtx, sharedCtx, &attribList[0]);
if (!m_context)
TCU_THROW(ResourceError, "Failed to create WGL context");
public:
Context (const Core* core,
HDC deviceCtx,
+ const Context* sharedContext,
glu::ContextType ctxType,
int pixelFormat,
glu::ResetNotificationStrategy resetNotificationStrategy);
class WGLContext : public glu::RenderContext
{
public:
- WGLContext (HINSTANCE instance, const wgl::Core& wglCore, const glu::RenderConfig& config);
+ WGLContext (HINSTANCE instance, const wgl::Core& wglCore, const WGLContext* sharedContext, const glu::RenderConfig& config);
~WGLContext (void);
glu::ContextType getType (void) const { return m_contextType; }
glw::Functions m_functions;
};
-WGLContext::WGLContext (HINSTANCE instance, const wgl::Core& wglCore, const glu::RenderConfig& config)
+WGLContext::WGLContext (HINSTANCE instance, const wgl::Core& wglCore, const WGLContext* sharedContext, const glu::RenderConfig& config)
: m_contextType (config.type)
, m_window (instance,
config.width != glu::RenderConfig::DONT_CARE ? config.width : DEFAULT_WINDOW_WIDTH,
if (pixelFormat < 0)
throw NotSupportedError("Compatible WGL pixel format not found");
- m_context = new wgl::Context(&wglCore, deviceCtx, config.type, pixelFormat, config.resetNotificationStrategy);
+ const wgl::Context* sharedCtx = DE_NULL;
+ if (DE_NULL != sharedContext)
+ sharedCtx = sharedContext->m_context;
+
+ m_context = new wgl::Context(&wglCore, deviceCtx, sharedCtx, config.type, pixelFormat, config.resetNotificationStrategy);
try
{
{
}
-glu::RenderContext* ContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const
+glu::RenderContext* ContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine&,
+ const glu::RenderContext* sharedContext) const
{
- return new WGLContext(m_instance, m_wglCore, config);
+ const WGLContext* sharedWGLContext = static_cast<const WGLContext*>(sharedContext);
+ return new WGLContext(m_instance, m_wglCore, sharedWGLContext, config);
}
} // wgl
{
public:
ContextFactory (HINSTANCE instance);
- virtual glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const;
+ virtual glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine,
+ const glu::RenderContext* sharedContext) const;
private:
const HINSTANCE m_instance;