| /*------------------------------------------------------------------------- |
| * drawElements Quality Program EGL Module |
| * --------------------------------------- |
| * |
| * Copyright 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief EGL multi context tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "teglMultiContextTests.hpp" |
| |
| #include "egluUtil.hpp" |
| #include "egluUnique.hpp" |
| #include "egluStrUtil.hpp" |
| #include "egluConfigFilter.hpp" |
| |
| #include "eglwLibrary.hpp" |
| #include "eglwEnums.hpp" |
| |
| #include "gluDefs.hpp" |
| |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| |
| #include "tcuResultCollector.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "deRandom.hpp" |
| |
| #include <vector> |
| |
| namespace deqp |
| { |
| namespace egl |
| { |
| namespace |
| { |
| |
| using tcu::TestLog; |
| |
| class MultiContextTest : public TestCase |
| { |
| public: |
| enum Use |
| { |
| USE_NONE = 0, |
| USE_MAKECURRENT, |
| USE_CLEAR, |
| |
| USE_LAST |
| }; |
| |
| enum Sharing |
| { |
| SHARING_NONE = 0, |
| SHARING_SHARED, |
| SHARING_LAST |
| }; |
| MultiContextTest (EglTestContext& eglTestCtx, Sharing sharing, Use use, const char* name, const char* description); |
| |
| IterateResult iterate (void); |
| |
| private: |
| const Sharing m_sharing; |
| const Use m_use; |
| }; |
| |
| MultiContextTest::MultiContextTest (EglTestContext& eglTestCtx, Sharing sharing, Use use, const char* name, const char* description) |
| : TestCase (eglTestCtx, name, description) |
| , m_sharing (sharing) |
| , m_use (use) |
| { |
| } |
| |
| bool isES2Renderable (const eglu::CandidateConfig& c) |
| { |
| return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT; |
| } |
| |
| bool supportsPBuffer (const eglu::CandidateConfig& c) |
| { |
| return (c.get(EGL_SURFACE_TYPE) & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT; |
| } |
| |
| eglw::EGLConfig getConfig (const eglw::Library& egl, eglw::EGLDisplay display) |
| { |
| eglu::FilterList filters; |
| filters << isES2Renderable; |
| filters << supportsPBuffer; |
| return eglu::chooseSingleConfig(egl, display, filters); |
| } |
| |
| tcu::TestCase::IterateResult MultiContextTest::iterate (void) |
| { |
| const deUint32 seed = m_sharing == SHARING_SHARED ? 2498541716u : 8825414; |
| const size_t maxContextCount = 128; |
| const size_t minContextCount = 32; |
| const eglw::EGLint attribList[] = |
| { |
| EGL_CONTEXT_CLIENT_VERSION, 2, |
| EGL_NONE |
| }; |
| const eglw::EGLint pbufferAttribList[] = |
| { |
| EGL_WIDTH, 64, |
| EGL_HEIGHT, 64, |
| EGL_NONE |
| }; |
| |
| TestLog& log = m_testCtx.getLog(); |
| tcu::ResultCollector resultCollector (log); |
| de::Random rng (seed); |
| |
| const eglw::Library& egl = m_eglTestCtx.getLibrary(); |
| const eglu::UniqueDisplay display (egl, eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay())); |
| const eglw::EGLConfig config = getConfig(egl, *display); |
| |
| const eglu::UniqueSurface surface (egl, *display, m_use != USE_NONE ? egl.createPbufferSurface(*display, config, pbufferAttribList) : EGL_NO_SURFACE); |
| EGLU_CHECK_MSG(egl, "Failed to create pbuffer."); |
| |
| std::vector<eglw::EGLContext> contexts; |
| glw::Functions gl; |
| |
| contexts.reserve(maxContextCount); |
| |
| log << TestLog::Message << "Trying to create " << maxContextCount << (m_sharing == SHARING_SHARED ? " shared " : " ") << "contexts." << TestLog::EndMessage; |
| log << TestLog::Message << "Requiring that at least " << minContextCount << " contexts can be created." << TestLog::EndMessage; |
| |
| if (m_use == USE_CLEAR) |
| m_eglTestCtx.initGLFunctions(&gl, glu::ApiType::es(2,0)); |
| |
| EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API)); |
| |
| try |
| { |
| for (size_t contextCount = 0; contextCount < maxContextCount; contextCount++) |
| { |
| const eglw::EGLContext sharedContext = (m_sharing == SHARING_SHARED && contextCount > 0 ? contexts[rng.getUint32() % (deUint32)contextCount] : EGL_NO_CONTEXT); |
| const eglw::EGLContext context = egl.createContext(*display, config, sharedContext, attribList); |
| const eglw::EGLint error = egl.getError(); |
| |
| if (context == EGL_NO_CONTEXT || error != EGL_SUCCESS) |
| { |
| log << TestLog::Message << "Got error after creating " << contextCount << " contexts." << TestLog::EndMessage; |
| |
| if (error == EGL_BAD_ALLOC) |
| { |
| if (contextCount < minContextCount) |
| resultCollector.fail("Couldn't create the minimum number of contexts required."); |
| else |
| log << TestLog::Message << "Got EGL_BAD_ALLOC." << TestLog::EndMessage; |
| } |
| else |
| resultCollector.fail("eglCreateContext() produced error that is not EGL_BAD_ALLOC: " + eglu::getErrorStr(error).toString()); |
| |
| if (context != EGL_NO_CONTEXT) |
| resultCollector.fail("eglCreateContext() produced error, but context is not EGL_NO_CONTEXT"); |
| |
| break; |
| } |
| else |
| { |
| contexts.push_back(context); |
| |
| if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR) |
| { |
| const eglw::EGLBoolean result = egl.makeCurrent(*display, *surface, *surface, context); |
| const eglw::EGLint makeCurrentError = egl.getError(); |
| |
| if (!result || makeCurrentError != EGL_SUCCESS) |
| { |
| log << TestLog::Message << "Failed to make " << (contextCount + 1) << "th context current: " << eglu::getErrorStr(makeCurrentError) << TestLog::EndMessage; |
| resultCollector.fail("Failed to make context current"); |
| |
| break; |
| } |
| else if (m_use == USE_CLEAR) |
| { |
| gl.clearColor(0.25f, 0.75f, 0.50f, 1.00f); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| gl.finish(); |
| GLU_CHECK_GLW_MSG(gl, "Failed to clear color."); |
| } |
| } |
| } |
| } |
| |
| for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++) |
| { |
| EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx])); |
| contexts[contextNdx] = EGL_NO_CONTEXT; |
| } |
| |
| if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR) |
| EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| } |
| catch (...) |
| { |
| for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++) |
| { |
| if (contexts[contextNdx] != EGL_NO_CONTEXT) |
| EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx])); |
| } |
| |
| if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR) |
| EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| |
| throw; |
| } |
| |
| resultCollector.setTestContextResult(m_testCtx); |
| return STOP; |
| } |
| |
| } // anonymous |
| |
| TestCaseGroup* createMultiContextTests (EglTestContext& eglTestCtx) |
| { |
| de::MovePtr<TestCaseGroup> group (new TestCaseGroup(eglTestCtx, "multicontext", "EGL multi context tests.")); |
| |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_NONE, "non_shared", "Create multiple non-shared contexts.")); |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED, MultiContextTest::USE_NONE, "shared", "Create multiple shared contexts.")); |
| |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_MAKECURRENT, "non_shared_make_current", "Create multiple non-shared contexts.")); |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED, MultiContextTest::USE_MAKECURRENT, "shared_make_current", "Create multiple shared contexts.")); |
| |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_CLEAR, "non_shared_clear", "Create multiple non-shared contexts.")); |
| group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED, MultiContextTest::USE_CLEAR, "shared_clear", "Create multiple shared contexts.")); |
| |
| return group.release(); |
| } |
| |
| } // egl |
| } // deqp |