1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL Module 3 * --------------------------------------- 4 * 5 * Copyright 2016 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief EGL thread clean up tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "teglThreadCleanUpTests.hpp" 25 26 #include "egluUtil.hpp" 27 #include "egluUnique.hpp" 28 #include "egluConfigFilter.hpp" 29 30 #include "eglwLibrary.hpp" 31 #include "eglwEnums.hpp" 32 33 #include "tcuMaybe.hpp" 34 #include "tcuTestLog.hpp" 35 36 #include "deThread.hpp" 37 38 namespace deqp 39 { 40 namespace egl 41 { 42 namespace 43 { 44 45 using namespace eglw; 46 using tcu::TestLog; 47 48 bool isES2Renderable (const eglu::CandidateConfig& c) 49 { 50 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT; 51 } 52 53 bool isPBuffer (const eglu::CandidateConfig& c) 54 { 55 return (c.surfaceType() & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT; 56 } 57 58 class Thread : public de::Thread 59 { 60 public: 61 Thread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLConfig config, tcu::Maybe<eglu::Error>& error) 62 : m_egl (egl) 63 , m_display (display) 64 , m_surface (surface) 65 , m_context (context) 66 , m_config (config) 67 , m_error (error) 68 { 69 } 70 71 void testContext (EGLContext context) 72 { 73 if (m_surface != EGL_NO_SURFACE) 74 { 75 EGLU_CHECK_MSG(m_egl, "eglCreateContext"); 76 m_egl.makeCurrent(m_display, m_surface, m_surface, context); 77 EGLU_CHECK_MSG(m_egl, "eglMakeCurrent"); 78 } 79 else 80 { 81 const EGLint attribs[] = 82 { 83 EGL_WIDTH, 32, 84 EGL_HEIGHT, 32, 85 EGL_NONE 86 }; 87 const eglu::UniqueSurface surface (m_egl, m_display, m_egl.createPbufferSurface(m_display, m_config, attribs)); 88 89 EGLU_CHECK_MSG(m_egl, "eglCreateContext"); 90 m_egl.makeCurrent(m_display, *surface, *surface, context); 91 EGLU_CHECK_MSG(m_egl, "eglMakeCurrent"); 92 } 93 } 94 95 void run (void) 96 { 97 try 98 { 99 const EGLint attribList[] = 100 { 101 EGL_CONTEXT_CLIENT_VERSION, 2, 102 EGL_NONE 103 }; 104 105 m_egl.bindAPI(EGL_OPENGL_ES_API); 106 107 if (m_context == EGL_NO_CONTEXT) 108 { 109 const eglu::UniqueContext context (m_egl, m_display, m_egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList)); 110 111 testContext(*context); 112 } 113 else 114 { 115 testContext(m_context); 116 } 117 118 } 119 catch (const eglu::Error& error) 120 { 121 m_error = error; 122 } 123 } 124 125 private: 126 const Library& m_egl; 127 const EGLDisplay m_display; 128 const EGLSurface m_surface; 129 const EGLContext m_context; 130 const EGLConfig m_config; 131 tcu::Maybe<eglu::Error>& m_error; 132 }; 133 134 class ThreadCleanUpTest : public TestCase 135 { 136 public: 137 enum ContextType 138 { 139 CONTEXTTYPE_SINGLE = 0, 140 CONTEXTTYPE_MULTI 141 }; 142 143 enum SurfaceType 144 { 145 SURFACETYPE_SINGLE = 0, 146 SURFACETYPE_MULTI 147 }; 148 149 static std::string testCaseName (ContextType contextType, SurfaceType surfaceType) 150 { 151 std::string name; 152 153 if (contextType == CONTEXTTYPE_SINGLE) 154 name += "single_context_"; 155 else 156 name += "multi_context_"; 157 158 if (surfaceType ==SURFACETYPE_SINGLE) 159 name += "single_surface"; 160 else 161 name += "multi_surface"; 162 163 return name; 164 } 165 166 167 ThreadCleanUpTest (EglTestContext& eglTestCtx, ContextType contextType, SurfaceType surfaceType) 168 : TestCase (eglTestCtx, testCaseName(contextType, surfaceType).c_str(), "Simple thread context clean up test") 169 , m_contextType (contextType) 170 , m_surfaceType (surfaceType) 171 , m_iterCount (250) 172 , m_iterNdx (0) 173 , m_display (EGL_NO_DISPLAY) 174 , m_config (0) 175 , m_surface (EGL_NO_SURFACE) 176 , m_context (EGL_NO_CONTEXT) 177 { 178 } 179 180 ~ThreadCleanUpTest (void) 181 { 182 deinit(); 183 } 184 185 void init (void) 186 { 187 const Library& egl = m_eglTestCtx.getLibrary(); 188 189 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 190 191 { 192 eglu::FilterList filters; 193 filters << isES2Renderable << isPBuffer; 194 m_config = eglu::chooseSingleConfig(egl, m_display, filters); 195 } 196 197 if (m_contextType == CONTEXTTYPE_SINGLE) 198 { 199 const EGLint attribList[] = 200 { 201 EGL_CONTEXT_CLIENT_VERSION, 2, 202 EGL_NONE 203 }; 204 205 egl.bindAPI(EGL_OPENGL_ES_API); 206 207 m_context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList); 208 EGLU_CHECK_MSG(egl, "Failed to create context"); 209 } 210 211 if (m_surfaceType == SURFACETYPE_SINGLE) 212 { 213 const EGLint attribs[] = 214 { 215 EGL_WIDTH, 32, 216 EGL_HEIGHT, 32, 217 EGL_NONE 218 }; 219 220 m_surface = egl.createPbufferSurface(m_display, m_config, attribs); 221 EGLU_CHECK_MSG(egl, "Failed to create surface"); 222 } 223 } 224 225 void deinit (void) 226 { 227 const Library& egl = m_eglTestCtx.getLibrary(); 228 229 if (m_surface != EGL_NO_SURFACE) 230 { 231 egl.destroySurface(m_display, m_surface); 232 m_surface = EGL_NO_SURFACE; 233 } 234 235 if (m_context != EGL_NO_CONTEXT) 236 { 237 egl.destroyContext(m_display, m_context); 238 m_context = EGL_NO_CONTEXT; 239 } 240 241 if (m_display != EGL_NO_DISPLAY) 242 { 243 egl.terminate(m_display); 244 m_display = EGL_NO_DISPLAY; 245 } 246 } 247 248 IterateResult iterate (void) 249 { 250 if (m_iterNdx < m_iterCount) 251 { 252 tcu::Maybe<eglu::Error> error; 253 254 Thread thread (m_eglTestCtx.getLibrary(), m_display, m_surface, m_context, m_config, error); 255 256 thread.start(); 257 thread.join(); 258 259 if (error) 260 { 261 m_testCtx.getLog() << TestLog::Message << "Failed. Got error: " << error->getMessage() << TestLog::EndMessage; 262 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error->getMessage()); 263 return STOP; 264 } 265 266 m_iterNdx++; 267 return CONTINUE; 268 } 269 else 270 { 271 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 272 return STOP; 273 } 274 } 275 276 private: 277 const ContextType m_contextType; 278 const SurfaceType m_surfaceType; 279 const size_t m_iterCount; 280 size_t m_iterNdx; 281 EGLDisplay m_display; 282 EGLConfig m_config; 283 EGLSurface m_surface; 284 EGLContext m_context; 285 }; 286 287 } // anonymous 288 289 TestCaseGroup* createThreadCleanUpTest (EglTestContext& eglTestCtx) 290 { 291 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(eglTestCtx, "thread_cleanup", "Thread cleanup tests")); 292 293 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_SINGLE)); 294 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_SINGLE)); 295 296 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_MULTI)); 297 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_MULTI)); 298 299 return group.release(); 300 } 301 302 } // egl 303 } // deqp 304