From 1b91247d4ad206cbdbef731a2bac9151d6ddda70 Mon Sep 17 00:00:00 2001 From: Piotr Byszewski Date: Fri, 25 Aug 2017 13:39:58 +0200 Subject: [PATCH] Add multiple contexts tests multiple_contexts test (one of shader_subroutine tests) was modified and moved to contextless module. Shared contexts functionality was restored in framework. Components: Framework, OpenGL VK-GL-CTS issue: 612 Affects: KHR-NoContext.gl40.multiple_contexts.uniform_preservation KHR-GL40.shader_subroutine.multiple_contexts Change-Id: Id170ef37c2e3c488095663c91788978223d356ec --- .../4.6.0.x/src/gl40-test-issues.txt | 2 - .../4.6.0.x/src/gl41-test-issues.txt | 2 - .../4.6.0.x/src/gl42-test-issues.txt | 2 - .../4.6.0.x/src/gl43-test-issues.txt | 2 - .../4.6.0.x/src/gl44-test-issues.txt | 2 - .../4.6.0.x/src/gl45-test-issues.txt | 2 - .../4.6.0.x/src/gl46-test-issues.txt | 2 - .../4.5.5.x/gl40-khr-master.txt | 1 + .../4.5.5.x/src/gl40-khr-master.txt | 1 + .../4.6.0.x/gl40-khr-master.txt | 1 + .../gl/khronos_mustpass_noctx/4.6.0.x/mustpass.xml | 1 + .../4.6.0.x/src/gl40-khr-master.txt | 1 + external/openglcts/modules/common/CMakeLists.txt | 2 + external/openglcts/modules/common/glcContext.cpp | 5 - external/openglcts/modules/common/glcContext.hpp | 4 - .../modules/common/glcMultipleContextsTests.cpp | 875 +++++++++++++++++++++ .../modules/common/glcMultipleContextsTests.hpp | 58 ++ .../modules/common/glcNoDefaultContextPackage.cpp | 5 + .../modules/gl/gl4cShaderSubroutineTests.cpp | 735 ----------------- .../modules/gl/gl4cShaderSubroutineTests.hpp | 64 -- .../runner/glcKhronosMustpassGlNocontext.hpp | 1 + external/openglcts/scripts/build_caselists.py | 3 +- external/openglcts/scripts/build_mustpass.py | 12 +- framework/egl/egluGLContextFactory.cpp | 44 +- framework/egl/egluGLContextFactory.hpp | 2 +- framework/egl/egluGLUtil.cpp | 3 +- framework/egl/egluGLUtil.hpp | 1 + framework/opengl/gluContextFactory.hpp | 7 +- framework/opengl/gluFboRenderContext.cpp | 2 +- framework/opengl/gluRenderContext.cpp | 8 +- framework/opengl/gluRenderContext.hpp | 2 +- .../platform/lnx/X11/tcuLnxX11GlxPlatform.cpp | 34 +- framework/platform/null/tcuNullContextFactory.cpp | 2 +- framework/platform/null/tcuNullContextFactory.hpp | 2 +- framework/platform/win32/tcuWGL.cpp | 8 +- framework/platform/win32/tcuWGL.hpp | 1 + framework/platform/win32/tcuWGLContextFactory.cpp | 16 +- framework/platform/win32/tcuWGLContextFactory.hpp | 3 +- 38 files changed, 1049 insertions(+), 869 deletions(-) create mode 100644 external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/gl40-khr-master.txt create mode 100644 external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/src/gl40-khr-master.txt create mode 100644 external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/gl40-khr-master.txt create mode 100644 external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/src/gl40-khr-master.txt create mode 100644 external/openglcts/modules/common/glcMultipleContextsTests.cpp create mode 100644 external/openglcts/modules/common/glcMultipleContextsTests.hpp diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl40-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl40-test-issues.txt index c2fd524..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl40-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl40-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL40.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl41-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl41-test-issues.txt index bcf2806..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl41-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl41-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL41.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl42-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl42-test-issues.txt index c56274e..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl42-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl42-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL42.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl43-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl43-test-issues.txt index a0e70c3..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl43-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl43-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL43.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl44-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl44-test-issues.txt index 19dc4ae..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl44-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl44-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL44.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl45-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl45-test-issues.txt index 479437e..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl45-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl45-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL45.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl46-test-issues.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl46-test-issues.txt index 8650140..e69de29 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl46-test-issues.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/src/gl46-test-issues.txt @@ -1,2 +0,0 @@ -# VK-GL-CTS issue: 624 -KHR-GL46.shader_subroutine.multiple_contexts diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/gl40-khr-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/gl40-khr-master.txt new file mode 100644 index 0000000..a34c4d6 --- /dev/null +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/gl40-khr-master.txt @@ -0,0 +1 @@ +KHR-NoContext.gl40.multiple_contexts.uniform_preservation diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/src/gl40-khr-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/src/gl40-khr-master.txt new file mode 100644 index 0000000..c1c12c3 --- /dev/null +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.5.5.x/src/gl40-khr-master.txt @@ -0,0 +1 @@ +KHR-NoContext.gl40.* diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/gl40-khr-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/gl40-khr-master.txt new file mode 100644 index 0000000..a34c4d6 --- /dev/null +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/gl40-khr-master.txt @@ -0,0 +1 @@ +KHR-NoContext.gl40.multiple_contexts.uniform_preservation diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/mustpass.xml b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/mustpass.xml index 45dae0a..584e263 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/mustpass.xml +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/mustpass.xml @@ -19,6 +19,7 @@ */--> + diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/src/gl40-khr-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/src/gl40-khr-master.txt new file mode 100644 index 0000000..c1c12c3 --- /dev/null +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0.x/src/gl40-khr-master.txt @@ -0,0 +1 @@ +KHR-NoContext.gl40.* diff --git a/external/openglcts/modules/common/CMakeLists.txt b/external/openglcts/modules/common/CMakeLists.txt index 62117c8..6267960 100644 --- a/external/openglcts/modules/common/CMakeLists.txt +++ b/external/openglcts/modules/common/CMakeLists.txt @@ -32,6 +32,8 @@ set(GLCTS_COMMON_SRCS glcFragDepthTests.hpp glcInfoTests.cpp glcInfoTests.hpp + glcMultipleContextsTests.cpp + glcMultipleContextsTests.hpp glcNoErrorTests.cpp glcNoErrorTests.hpp glcRobustnessTests.cpp diff --git a/external/openglcts/modules/common/glcContext.cpp b/external/openglcts/modules/common/glcContext.cpp index fb2e3b1..c1551c9 100644 --- a/external/openglcts/modules/common/glcContext.cpp +++ b/external/openglcts/modules/common/glcContext.cpp @@ -83,11 +83,6 @@ void Context::destroyRenderContext(void) 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(); diff --git a/external/openglcts/modules/common/glcContext.hpp b/external/openglcts/modules/common/glcContext.hpp index b91a365..d42e62c 100644 --- a/external/openglcts/modules/common/glcContext.hpp +++ b/external/openglcts/modules/common/glcContext.hpp @@ -71,10 +71,6 @@ public: 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); diff --git a/external/openglcts/modules/common/glcMultipleContextsTests.cpp b/external/openglcts/modules/common/glcMultipleContextsTests.cpp new file mode 100644 index 0000000..df78d0d --- /dev/null +++ b/external/openglcts/modules/common/glcMultipleContextsTests.cpp @@ -0,0 +1,875 @@ +/*------------------------------------------------------------------------- + * 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 +#include +#include + +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 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 + * + * @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(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 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 */ diff --git a/external/openglcts/modules/common/glcMultipleContextsTests.hpp b/external/openglcts/modules/common/glcMultipleContextsTests.hpp new file mode 100644 index 0000000..867e153 --- /dev/null +++ b/external/openglcts/modules/common/glcMultipleContextsTests.hpp @@ -0,0 +1,58 @@ +#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 + +#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 diff --git a/external/openglcts/modules/common/glcNoDefaultContextPackage.cpp b/external/openglcts/modules/common/glcNoDefaultContextPackage.cpp index 0fc4d53..e918e67 100644 --- a/external/openglcts/modules/common/glcNoDefaultContextPackage.cpp +++ b/external/openglcts/modules/common/glcNoDefaultContextPackage.cpp @@ -23,6 +23,7 @@ #include "glcNoDefaultContextPackage.hpp" #include "glcContextFlagsTests.hpp" +#include "glcMultipleContextsTests.hpp" #include "glcNoErrorTests.hpp" #include "glcRobustnessTests.hpp" #include "gluRenderContext.hpp" @@ -88,6 +89,10 @@ void NoDefaultContextPackage::init(void) 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))); diff --git a/external/openglcts/modules/gl/gl4cShaderSubroutineTests.cpp b/external/openglcts/modules/gl/gl4cShaderSubroutineTests.cpp index 0ef75b3..67806b8 100644 --- a/external/openglcts/modules/gl/gl4cShaderSubroutineTests.cpp +++ b/external/openglcts/modules/gl/gl4cShaderSubroutineTests.cpp @@ -9838,740 +9838,6 @@ void FunctionalTest18_19::verifyXFBData(const glw::GLvoid* data, glw::GLuint boo } /* 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 - * - * @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 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. @@ -14518,7 +13784,6 @@ void ShaderSubroutineTests::init(void) 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)); diff --git a/external/openglcts/modules/gl/gl4cShaderSubroutineTests.hpp b/external/openglcts/modules/gl/gl4cShaderSubroutineTests.hpp index 60c605a..99ca816 100644 --- a/external/openglcts/modules/gl/gl4cShaderSubroutineTests.hpp +++ b/external/openglcts/modules/gl/gl4cShaderSubroutineTests.hpp @@ -1038,70 +1038,6 @@ private: }; /** - * * 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. **/ diff --git a/external/openglcts/modules/runner/glcKhronosMustpassGlNocontext.hpp b/external/openglcts/modules/runner/glcKhronosMustpassGlNocontext.hpp index 71b6723..c1281dc 100644 --- a/external/openglcts/modules/runner/glcKhronosMustpassGlNocontext.hpp +++ b/external/openglcts/modules/runner/glcKhronosMustpassGlNocontext.hpp @@ -23,6 +23,7 @@ const char* mustpassDir = "gl_cts/data/mustpass/gl/khronos_mustpass_noctx/4.6.0. 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 }, }; diff --git a/external/openglcts/scripts/build_caselists.py b/external/openglcts/scripts/build_caselists.py index a1c1ba4..828b2cc 100644 --- a/external/openglcts/scripts/build_caselists.py +++ b/external/openglcts/scripts/build_caselists.py @@ -76,6 +76,7 @@ MODULES = [ 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" @@ -102,7 +103,7 @@ def getModulesPath (buildCfg): 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) diff --git a/external/openglcts/scripts/build_mustpass.py b/external/openglcts/scripts/build_mustpass.py index 7d2c1a2..5ccd336 100644 --- a/external/openglcts/scripts/build_mustpass.py +++ b/external/openglcts/scripts/build_mustpass.py @@ -1013,6 +1013,7 @@ GL_MODULES = OrderedDict([ ]) 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 = [ @@ -1024,6 +1025,15 @@ GLCTS_NOCTX_GL30_KHR_PKG = Package(module = NOCTX_GL30_KHR_MODULE, configurati 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", @@ -1060,7 +1070,7 @@ def generateGLMustpass(): 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 diff --git a/framework/egl/egluGLContextFactory.cpp b/framework/egl/egluGLContextFactory.cpp index e96d2f8..21d103f 100644 --- a/framework/egl/egluGLContextFactory.cpp +++ b/framework/egl/egluGLContextFactory.cpp @@ -47,6 +47,7 @@ #include "deDynamicLibrary.hpp" #include "deSTLUtil.hpp" +#include "deSharedPtr.hpp" #include #include @@ -129,7 +130,7 @@ private: 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; } @@ -147,13 +148,13 @@ public: 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 m_display; NativeWindow* m_window; NativePixmap* m_pixmap; @@ -161,13 +162,14 @@ private: 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) @@ -177,6 +179,7 @@ RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const , m_eglDisplay (EGL_NO_DISPLAY) , m_eglSurface (EGL_NO_SURFACE) , m_eglContext (EGL_NO_CONTEXT) + , m_eglSharedContext (EGL_NO_CONTEXT) , m_dynamicGLLibrary (DE_NULL) { @@ -184,7 +187,7 @@ RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const try { - create(displayFactory, windowFactory, pixmapFactory, config); + create(displayFactory, windowFactory, pixmapFactory, config, sharedContext); } catch (...) { @@ -206,7 +209,6 @@ RenderContext::~RenderContext(void) delete m_window; delete m_pixmap; - delete m_display; delete m_dynamicGLLibrary; } @@ -305,15 +307,22 @@ glw::GenericFuncType RenderContext::getProcAddress (const char* name) const 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(displayFactory->createDisplay()); + else + { + const RenderContext* context = dynamic_cast(sharedContext); + m_eglSharedContext = context->m_eglContext; + m_display = context->m_display; + } + m_eglDisplay = eglu::getDisplay(*m_display); const Library& egl = m_display->getLibrary(); { @@ -345,7 +354,7 @@ void RenderContext::create (const NativeDisplayFactory* displayFactory, const Na { 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; } @@ -358,7 +367,7 @@ void RenderContext::create (const NativeDisplayFactory* displayFactory, const Na { 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; } @@ -375,7 +384,7 @@ void RenderContext::create (const NativeDisplayFactory* displayFactory, const Na 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)); @@ -473,7 +482,8 @@ void RenderContext::destroy (void) 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; @@ -482,12 +492,10 @@ void RenderContext::destroy (void) 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; } @@ -521,7 +529,7 @@ void RenderContext::postIterate (void) 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; @@ -587,7 +595,7 @@ GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayF { } -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); @@ -612,7 +620,7 @@ glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& co pixmapFactory = DE_NULL; } - return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config); + return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config, sharedContext); } } // eglu diff --git a/framework/egl/egluGLContextFactory.hpp b/framework/egl/egluGLContextFactory.hpp index 53617bf..2452306 100644 --- a/framework/egl/egluGLContextFactory.hpp +++ b/framework/egl/egluGLContextFactory.hpp @@ -49,7 +49,7 @@ class GLContextFactory : public glu::ContextFactory { 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; diff --git a/framework/egl/egluGLUtil.cpp b/framework/egl/egluGLUtil.cpp index cca5681..9c0a308 100644 --- a/framework/egl/egluGLUtil.cpp +++ b/framework/egl/egluGLUtil.cpp @@ -80,6 +80,7 @@ EGLContext createGLContext (const Library& egl, EGLDisplay display, EGLContext eglConfig, const glu::ContextType& contextType, + eglw::EGLContext sharedContext, glu::ResetNotificationStrategy resetNotificationStrategy) { const bool khrCreateContextSupported = hasExtension(egl, display, "EGL_KHR_create_context"); @@ -193,7 +194,7 @@ EGLContext createGLContext (const Library& egl, 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; diff --git a/framework/egl/egluGLUtil.hpp b/framework/egl/egluGLUtil.hpp index be55740..fb26fb1 100644 --- a/framework/egl/egluGLUtil.hpp +++ b/framework/egl/egluGLUtil.hpp @@ -45,6 +45,7 @@ eglw::EGLContext createGLContext (const eglw::Library& egl, 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, diff --git a/framework/opengl/gluContextFactory.hpp b/framework/opengl/gluContextFactory.hpp index 4c75ae5..54b42f5 100644 --- a/framework/opengl/gluContextFactory.hpp +++ b/framework/opengl/gluContextFactory.hpp @@ -57,11 +57,12 @@ public: * 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&); diff --git a/framework/opengl/gluFboRenderContext.cpp b/framework/opengl/gluFboRenderContext.cpp index f1469ac..e71848a 100644 --- a/framework/opengl/gluFboRenderContext.cpp +++ b/framework/opengl/gluFboRenderContext.cpp @@ -180,7 +180,7 @@ FboRenderContext::FboRenderContext (const ContextFactory& factory, const RenderC 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 (...) diff --git a/framework/opengl/gluRenderContext.cpp b/framework/opengl/gluRenderContext.cpp index 3b3b6fc..6bb3e4a 100644 --- a/framework/opengl/gluRenderContext.cpp +++ b/framework/opengl/gluRenderContext.cpp @@ -130,7 +130,7 @@ static ContextFlags parseContextFlags (const std::string& flagsStr) 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(); @@ -161,9 +161,13 @@ RenderContext* createRenderContext (tcu::Platform& platform, const tcu::CommandL 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) diff --git a/framework/opengl/gluRenderContext.hpp b/framework/opengl/gluRenderContext.hpp index 0c6871c..e17cb59 100644 --- a/framework/opengl/gluRenderContext.hpp +++ b/framework/opengl/gluRenderContext.hpp @@ -232,7 +232,7 @@ private: // 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); diff --git a/framework/platform/lnx/X11/tcuLnxX11GlxPlatform.cpp b/framework/platform/lnx/X11/tcuLnxX11GlxPlatform.cpp index 0194772..29a45e3 100644 --- a/framework/platform/lnx/X11/tcuLnxX11GlxPlatform.cpp +++ b/framework/platform/lnx/X11/tcuLnxX11GlxPlatform.cpp @@ -82,8 +82,9 @@ class GlxContextFactory : public glu::ContextFactory 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;} @@ -119,6 +120,7 @@ public: 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; } @@ -171,7 +173,9 @@ class GlxRenderContext : public RenderContext { 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); @@ -179,6 +183,7 @@ public: 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; @@ -214,11 +219,12 @@ GlxContextFactory::GlxContextFactory (EventState& eventState) 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; } @@ -304,6 +310,7 @@ int GlxVisual::getAttrib (int attribute) GLXContext GlxVisual::createContext (const GlxContextFactory& factory, const ContextType& contextType, + const glu::RenderContext* sharedContext, glu::ResetNotificationStrategy resetNotificationStrategy) { std::vector attribs; @@ -391,8 +398,11 @@ GLXContext GlxVisual::createContext (const GlxContextFactory& factory, // Terminate attrib list attribs.push_back(None); + const GlxRenderContext* sharedGlxRenderContext = dynamic_cast(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) @@ -683,11 +693,12 @@ struct GlxFunctionLoader : public glw::FunctionLoader }; 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), @@ -745,6 +756,11 @@ const glw::Functions& GlxRenderContext::getFunctions (void) const return m_functions; } +const GLXContext& GlxRenderContext::getGLXContext (void) const +{ + return m_GLXContext; +} + MovePtr createContextFactory (EventState& eventState) { return MovePtr(new GlxContextFactory(eventState)); diff --git a/framework/platform/null/tcuNullContextFactory.cpp b/framework/platform/null/tcuNullContextFactory.cpp index d466185..2db64f9 100644 --- a/framework/platform/null/tcuNullContextFactory.cpp +++ b/framework/platform/null/tcuNullContextFactory.cpp @@ -34,7 +34,7 @@ NullGLContextFactory::NullGLContextFactory (void) { } -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); } diff --git a/framework/platform/null/tcuNullContextFactory.hpp b/framework/platform/null/tcuNullContextFactory.hpp index 3f0e975..ee05c5c 100644 --- a/framework/platform/null/tcuNullContextFactory.hpp +++ b/framework/platform/null/tcuNullContextFactory.hpp @@ -35,7 +35,7 @@ class NullGLContextFactory : public glu::ContextFactory { 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 diff --git a/framework/platform/win32/tcuWGL.cpp b/framework/platform/win32/tcuWGL.cpp index 6e8ec31..0bbca82 100644 --- a/framework/platform/win32/tcuWGL.cpp +++ b/framework/platform/win32/tcuWGL.cpp @@ -401,6 +401,7 @@ PixelFormatInfo Core::getPixelFormatInfo (HDC deviceCtx, int pixelFormat) const Context::Context (const Core* core, HDC deviceCtx, + const Context* sharedContext, glu::ContextType ctxType, int pixelFormat, glu::ResetNotificationStrategy resetNotificationStrategy) @@ -414,6 +415,7 @@ Context::Context (const Core* core, // Context version and profile { int profileBit = 0; + HGLRC sharedCtx = DE_NULL; int minor = ctxType.getMinorVersion(); int major = ctxType.getMajorVersion(); @@ -505,11 +507,15 @@ Context::Context (const Core* core, 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"); diff --git a/framework/platform/win32/tcuWGL.hpp b/framework/platform/win32/tcuWGL.hpp index cafae1c..6f50632 100644 --- a/framework/platform/win32/tcuWGL.hpp +++ b/framework/platform/win32/tcuWGL.hpp @@ -197,6 +197,7 @@ class Context public: Context (const Core* core, HDC deviceCtx, + const Context* sharedContext, glu::ContextType ctxType, int pixelFormat, glu::ResetNotificationStrategy resetNotificationStrategy); diff --git a/framework/platform/win32/tcuWGLContextFactory.cpp b/framework/platform/win32/tcuWGLContextFactory.cpp index 17c6bc8..2521129 100644 --- a/framework/platform/win32/tcuWGLContextFactory.cpp +++ b/framework/platform/win32/tcuWGLContextFactory.cpp @@ -65,7 +65,7 @@ private: 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; } @@ -90,7 +90,7 @@ private: 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, @@ -112,7 +112,11 @@ WGLContext::WGLContext (HINSTANCE instance, const wgl::Core& wglCore, const glu: 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 { @@ -174,9 +178,11 @@ ContextFactory::ContextFactory (HINSTANCE instance) { } -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(sharedContext); + return new WGLContext(m_instance, m_wglCore, sharedWGLContext, config); } } // wgl diff --git a/framework/platform/win32/tcuWGLContextFactory.hpp b/framework/platform/win32/tcuWGLContextFactory.hpp index b3301e1..2994cba 100644 --- a/framework/platform/win32/tcuWGLContextFactory.hpp +++ b/framework/platform/win32/tcuWGLContextFactory.hpp @@ -36,7 +36,8 @@ class ContextFactory : public glu::ContextFactory { 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; -- 2.7.4