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 m_egl.releaseThread(); 125 } 126 127 private: 128 const Library& m_egl; 129 const EGLDisplay m_display; 130 const EGLSurface m_surface; 131 const EGLContext m_context; 132 const EGLConfig m_config; 133 tcu::Maybe<eglu::Error>& m_error; 134 }; 135 136 class ThreadCleanUpTest : public TestCase 137 { 138 public: 139 enum ContextType 140 { 141 CONTEXTTYPE_SINGLE = 0, 142 CONTEXTTYPE_MULTI 143 }; 144 145 enum SurfaceType 146 { 147 SURFACETYPE_SINGLE = 0, 148 SURFACETYPE_MULTI 149 }; 150 151 static std::string testCaseName (ContextType contextType, SurfaceType surfaceType) 152 { 153 std::string name; 154 155 if (contextType == CONTEXTTYPE_SINGLE) 156 name += "single_context_"; 157 else 158 name += "multi_context_"; 159 160 if (surfaceType ==SURFACETYPE_SINGLE) 161 name += "single_surface"; 162 else 163 name += "multi_surface"; 164 165 return name; 166 } 167 168 169 ThreadCleanUpTest (EglTestContext& eglTestCtx, ContextType contextType, SurfaceType surfaceType) 170 : TestCase (eglTestCtx, testCaseName(contextType, surfaceType).c_str(), "Simple thread context clean up test") 171 , m_contextType (contextType) 172 , m_surfaceType (surfaceType) 173 , m_iterCount (250) 174 , m_iterNdx (0) 175 , m_display (EGL_NO_DISPLAY) 176 , m_config (0) 177 , m_surface (EGL_NO_SURFACE) 178 , m_context (EGL_NO_CONTEXT) 179 { 180 } 181 182 ~ThreadCleanUpTest (void) 183 { 184 deinit(); 185 } 186 187 void init (void) 188 { 189 const Library& egl = m_eglTestCtx.getLibrary(); 190 191 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 192 193 { 194 eglu::FilterList filters; 195 filters << isES2Renderable << isPBuffer; 196 m_config = eglu::chooseSingleConfig(egl, m_display, filters); 197 } 198 199 if (m_contextType == CONTEXTTYPE_SINGLE) 200 { 201 const EGLint attribList[] = 202 { 203 EGL_CONTEXT_CLIENT_VERSION, 2, 204 EGL_NONE 205 }; 206 207 egl.bindAPI(EGL_OPENGL_ES_API); 208 209 m_context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList); 210 EGLU_CHECK_MSG(egl, "Failed to create context"); 211 } 212 213 if (m_surfaceType == SURFACETYPE_SINGLE) 214 { 215 const EGLint attribs[] = 216 { 217 EGL_WIDTH, 32, 218 EGL_HEIGHT, 32, 219 EGL_NONE 220 }; 221 222 m_surface = egl.createPbufferSurface(m_display, m_config, attribs); 223 EGLU_CHECK_MSG(egl, "Failed to create surface"); 224 } 225 } 226 227 void deinit (void) 228 { 229 const Library& egl = m_eglTestCtx.getLibrary(); 230 231 if (m_surface != EGL_NO_SURFACE) 232 { 233 egl.destroySurface(m_display, m_surface); 234 m_surface = EGL_NO_SURFACE; 235 } 236 237 if (m_context != EGL_NO_CONTEXT) 238 { 239 egl.destroyContext(m_display, m_context); 240 m_context = EGL_NO_CONTEXT; 241 } 242 243 if (m_display != EGL_NO_DISPLAY) 244 { 245 egl.terminate(m_display); 246 m_display = EGL_NO_DISPLAY; 247 } 248 } 249 250 IterateResult iterate (void) 251 { 252 if (m_iterNdx < m_iterCount) 253 { 254 tcu::Maybe<eglu::Error> error; 255 256 Thread thread (m_eglTestCtx.getLibrary(), m_display, m_surface, m_context, m_config, error); 257 258 thread.start(); 259 thread.join(); 260 261 if (error) 262 { 263 m_testCtx.getLog() << TestLog::Message << "Failed. Got error: " << error->getMessage() << TestLog::EndMessage; 264 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error->getMessage()); 265 return STOP; 266 } 267 268 m_iterNdx++; 269 return CONTINUE; 270 } 271 else 272 { 273 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 274 return STOP; 275 } 276 } 277 278 private: 279 const ContextType m_contextType; 280 const SurfaceType m_surfaceType; 281 const size_t m_iterCount; 282 size_t m_iterNdx; 283 EGLDisplay m_display; 284 EGLConfig m_config; 285 EGLSurface m_surface; 286 EGLContext m_context; 287 }; 288 289 } // anonymous 290 291 TestCaseGroup* createThreadCleanUpTest (EglTestContext& eglTestCtx) 292 { 293 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(eglTestCtx, "thread_cleanup", "Thread cleanup tests")); 294 295 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_SINGLE)); 296 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_SINGLE)); 297 298 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_MULTI)); 299 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_MULTI)); 300 301 return group.release(); 302 } 303 304 } // egl 305 } // deqp 306