1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL Module 3 * --------------------------------------- 4 * 5 * Copyright 2014 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 Config query tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "teglQueryContextTests.hpp" 25 #include "teglSimpleConfigCase.hpp" 26 #include "teglRenderCase.hpp" 27 #include "egluCallLogWrapper.hpp" 28 #include "egluStrUtil.hpp" 29 #include "tcuCommandLine.hpp" 30 #include "tcuTestLog.hpp" 31 #include "tcuTestContext.hpp" 32 33 #include "egluUtil.hpp" 34 #include "egluNativeDisplay.hpp" 35 #include "egluNativeWindow.hpp" 36 #include "egluNativePixmap.hpp" 37 38 #include "deUniquePtr.hpp" 39 40 #include <vector> 41 42 #include <EGL/eglext.h> 43 44 #if !defined(EGL_OPENGL_ES3_BIT_KHR) 45 # define EGL_OPENGL_ES3_BIT_KHR 0x0040 46 #endif 47 #if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR) 48 # define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION 49 #endif 50 51 namespace deqp 52 { 53 namespace egl 54 { 55 56 using eglu::ConfigInfo; 57 using tcu::TestLog; 58 59 struct ContextCaseInfo 60 { 61 EGLint surfaceType; 62 EGLint clientType; 63 EGLint clientVersion; 64 }; 65 66 class ContextCase : public SimpleConfigCase, protected eglu::CallLogWrapper 67 { 68 public: 69 ContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask); 70 virtual ~ContextCase (void); 71 72 void executeForConfig (tcu::egl::Display& display, EGLConfig config); 73 void executeForSurface (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, ContextCaseInfo& info); 74 75 virtual void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) = 0; 76 77 private: 78 EGLint m_surfaceTypeMask; 79 }; 80 81 ContextCase::ContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask) 82 : SimpleConfigCase (eglTestCtx, name, description, configIds) 83 , CallLogWrapper (eglTestCtx.getTestContext().getLog()) 84 , m_surfaceTypeMask (surfaceTypeMask) 85 { 86 } 87 88 ContextCase::~ContextCase (void) 89 { 90 } 91 92 void ContextCase::executeForConfig (tcu::egl::Display& display, EGLConfig config) 93 { 94 tcu::TestLog& log = m_testCtx.getLog(); 95 const int width = 64; 96 const int height = 64; 97 const EGLint configId = display.getConfigAttrib(config, EGL_CONFIG_ID); 98 eglu::NativeDisplay& nativeDisplay = m_eglTestCtx.getNativeDisplay(); 99 bool isOk = true; 100 std::string failReason = ""; 101 102 if (m_surfaceTypeMask & EGL_WINDOW_BIT) 103 { 104 log << TestLog::Message << "Creating window surface with config ID " << configId << TestLog::EndMessage; 105 106 try 107 { 108 de::UniquePtr<eglu::NativeWindow> window (m_eglTestCtx.createNativeWindow(display.getEGLDisplay(), config, DE_NULL, width, height, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); 109 tcu::egl::WindowSurface surface (display, eglu::createWindowSurface(nativeDisplay, *window, display.getEGLDisplay(), config, DE_NULL)); 110 111 ContextCaseInfo info; 112 info.surfaceType = EGL_WINDOW_BIT; 113 114 executeForSurface(m_eglTestCtx.getDisplay(), config, surface.getEGLSurface(), info); 115 } 116 catch (const tcu::TestError& e) 117 { 118 log << e; 119 isOk = false; 120 failReason = e.what(); 121 } 122 123 log << TestLog::Message << TestLog::EndMessage; 124 } 125 126 if (m_surfaceTypeMask & EGL_PIXMAP_BIT) 127 { 128 log << TestLog::Message << "Creating pixmap surface with config ID " << configId << TestLog::EndMessage; 129 130 try 131 { 132 de::UniquePtr<eglu::NativePixmap> pixmap (m_eglTestCtx.createNativePixmap(display.getEGLDisplay(), config, DE_NULL, width, height)); 133 tcu::egl::PixmapSurface surface (display, eglu::createPixmapSurface(nativeDisplay, *pixmap, display.getEGLDisplay(), config, DE_NULL)); 134 135 ContextCaseInfo info; 136 info.surfaceType = EGL_PIXMAP_BIT; 137 138 executeForSurface(display, config, surface.getEGLSurface(), info); 139 } 140 catch (const tcu::TestError& e) 141 { 142 log << e; 143 isOk = false; 144 failReason = e.what(); 145 } 146 147 log << TestLog::Message << TestLog::EndMessage; 148 } 149 150 if (m_surfaceTypeMask & EGL_PBUFFER_BIT) 151 { 152 log << TestLog::Message << "Creating pbuffer surface with config ID " << configId << TestLog::EndMessage; 153 154 try 155 { 156 const EGLint surfaceAttribs[] = 157 { 158 EGL_WIDTH, width, 159 EGL_HEIGHT, height, 160 EGL_NONE 161 }; 162 163 tcu::egl::PbufferSurface surface(display, config, surfaceAttribs); 164 165 ContextCaseInfo info; 166 info.surfaceType = EGL_PBUFFER_BIT; 167 168 executeForSurface(display, config, surface.getEGLSurface(), info); 169 } 170 catch (const tcu::TestError& e) 171 { 172 log << e; 173 isOk = false; 174 failReason = e.what(); 175 } 176 177 log << TestLog::Message << TestLog::EndMessage; 178 } 179 180 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 181 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason.c_str()); 182 } 183 184 void ContextCase::executeForSurface (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, ContextCaseInfo& info) 185 { 186 TestLog& log = m_testCtx.getLog(); 187 EGLint apiBits = display.getConfigAttrib(config, EGL_RENDERABLE_TYPE); 188 189 static const EGLint es1Attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; 190 static const EGLint es2Attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 191 static const EGLint es3Attrs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_NONE }; 192 193 static const struct 194 { 195 const char* name; 196 EGLenum api; 197 EGLint apiBit; 198 const EGLint* ctxAttrs; 199 EGLint apiVersion; 200 } apis[] = 201 { 202 { "OpenGL", EGL_OPENGL_API, EGL_OPENGL_BIT, DE_NULL, 0 }, 203 { "OpenGL ES 1", EGL_OPENGL_ES_API, EGL_OPENGL_ES_BIT, es1Attrs, 1 }, 204 { "OpenGL ES 2", EGL_OPENGL_ES_API, EGL_OPENGL_ES2_BIT, es2Attrs, 2 }, 205 { "OpenGL ES 3", EGL_OPENGL_ES_API, EGL_OPENGL_ES3_BIT_KHR, es3Attrs, 3 }, 206 { "OpenVG", EGL_OPENVG_API, EGL_OPENVG_BIT, DE_NULL, 0 } 207 }; 208 209 for (int apiNdx = 0; apiNdx < (int)DE_LENGTH_OF_ARRAY(apis); apiNdx++) 210 { 211 if ((apiBits & apis[apiNdx].apiBit) == 0) 212 continue; // Not supported API 213 214 TCU_CHECK_EGL_CALL(eglBindAPI(apis[apiNdx].api)); 215 216 log << TestLog::Message << "Creating " << apis[apiNdx].name << " context" << TestLog::EndMessage; 217 218 const EGLContext context = eglCreateContext(display.getEGLDisplay(), config, EGL_NO_CONTEXT, apis[apiNdx].ctxAttrs); 219 TCU_CHECK_EGL(); 220 TCU_CHECK(context != EGL_NO_CONTEXT); 221 222 TCU_CHECK_EGL_CALL(eglMakeCurrent(display.getEGLDisplay(), surface, surface, context)); 223 224 info.clientType = apis[apiNdx].api; 225 info.clientVersion = apis[apiNdx].apiVersion; 226 227 executeForContext(display, config, surface, context, info); 228 229 // Destroy 230 TCU_CHECK_EGL_CALL(eglMakeCurrent(display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 231 TCU_CHECK_EGL_CALL(eglDestroyContext(display.getEGLDisplay(), context)); 232 } 233 } 234 235 class GetCurrentContextCase : public ContextCase 236 { 237 public: 238 GetCurrentContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask) 239 : ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask) 240 { 241 } 242 243 void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) 244 { 245 TestLog& log = m_testCtx.getLog(); 246 247 DE_UNREF(display); 248 DE_UNREF(config && surface); 249 DE_UNREF(info); 250 251 enableLogging(true); 252 253 const EGLContext gotContext = eglGetCurrentContext(); 254 TCU_CHECK_EGL(); 255 256 if (gotContext == context) 257 { 258 log << TestLog::Message << " Pass" << TestLog::EndMessage; 259 } 260 else if (gotContext == EGL_NO_CONTEXT) 261 { 262 log << TestLog::Message << " Fail, got EGL_NO_CONTEXT" << TestLog::EndMessage; 263 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_CONTEXT"); 264 } 265 else if (gotContext != context) 266 { 267 log << TestLog::Message << " Fail, call returned the wrong context. Expected: " << tcu::toHex(context) << ", got: " << tcu::toHex(gotContext) << TestLog::EndMessage; 268 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid context"); 269 } 270 271 enableLogging(false); 272 } 273 }; 274 275 class GetCurrentSurfaceCase : public ContextCase 276 { 277 public: 278 GetCurrentSurfaceCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask) 279 : ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask) 280 { 281 } 282 283 void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) 284 { 285 TestLog& log = m_testCtx.getLog(); 286 287 DE_UNREF(display); 288 DE_UNREF(config && context); 289 DE_UNREF(info); 290 291 enableLogging(true); 292 293 const EGLContext gotReadSurface = eglGetCurrentSurface(EGL_READ); 294 TCU_CHECK_EGL(); 295 296 const EGLContext gotDrawSurface = eglGetCurrentSurface(EGL_DRAW); 297 TCU_CHECK_EGL(); 298 299 if (gotReadSurface == surface && gotDrawSurface == surface) 300 { 301 log << TestLog::Message << " Pass" << TestLog::EndMessage; 302 } 303 else 304 { 305 log << TestLog::Message << " Fail, read surface: " << tcu::toHex(gotReadSurface) 306 << ", draw surface: " << tcu::toHex(gotDrawSurface) 307 << ", expected: " << tcu::toHex(surface) << TestLog::EndMessage; 308 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid surface"); 309 } 310 311 enableLogging(false); 312 } 313 }; 314 315 class GetCurrentDisplayCase : public ContextCase 316 { 317 public: 318 GetCurrentDisplayCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask) 319 : ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask) 320 { 321 } 322 323 void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) 324 { 325 TestLog& log = m_testCtx.getLog(); 326 327 DE_UNREF(config && surface && context); 328 DE_UNREF(info); 329 330 enableLogging(true); 331 332 const EGLDisplay gotDisplay = eglGetCurrentDisplay(); 333 TCU_CHECK_EGL(); 334 335 if (gotDisplay == display.getEGLDisplay()) 336 { 337 log << TestLog::Message << " Pass" << TestLog::EndMessage; 338 } 339 else if (gotDisplay == EGL_NO_DISPLAY) 340 { 341 log << TestLog::Message << " Fail, got EGL_NO_DISPLAY" << TestLog::EndMessage; 342 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_DISPLAY"); 343 } 344 else if (gotDisplay != display.getEGLDisplay()) 345 { 346 log << TestLog::Message << " Fail, call returned the wrong display. Expected: " << tcu::toHex(display.getEGLDisplay()) << ", got: " << tcu::toHex(gotDisplay) << TestLog::EndMessage; 347 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid display"); 348 } 349 350 enableLogging(false); 351 } 352 }; 353 354 class QueryContextCase : public ContextCase 355 { 356 public: 357 QueryContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask) 358 : ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask) 359 { 360 } 361 362 EGLint getContextAttrib (tcu::egl::Display& display, EGLContext context, EGLint attrib) 363 { 364 EGLint value; 365 TCU_CHECK_EGL_CALL(eglQueryContext(display.getEGLDisplay(), context, attrib, &value)); 366 367 return value; 368 } 369 370 void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) 371 { 372 TestLog& log = m_testCtx.getLog(); 373 const eglu::Version version (display.getEGLMajorVersion(), display.getEGLMinorVersion()); 374 375 DE_UNREF(surface); 376 enableLogging(true); 377 378 // Config ID 379 { 380 const EGLint configID = getContextAttrib(display, context, EGL_CONFIG_ID); 381 const EGLint surfaceConfigID = display.getConfigAttrib(config, EGL_CONFIG_ID); 382 383 if (configID != surfaceConfigID) 384 { 385 log << TestLog::Message << " Fail, config ID doesn't match the one used to create the context." << TestLog::EndMessage; 386 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid config ID"); 387 } 388 } 389 390 // Client API type 391 if (version >= eglu::Version(1, 2)) 392 { 393 const EGLint clientType = getContextAttrib(display, context, EGL_CONTEXT_CLIENT_TYPE); 394 395 if (clientType != info.clientType) 396 { 397 log << TestLog::Message << " Fail, client API type doesn't match." << TestLog::EndMessage; 398 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API type"); 399 } 400 } 401 402 // Client API version 403 if (version >= eglu::Version(1, 3)) 404 { 405 const EGLint clientVersion = getContextAttrib(display, context, EGL_CONTEXT_CLIENT_VERSION); 406 407 // \todo [2014-10-21 mika] Query actual supported api version from client api to make this check stricter. 408 if (info.clientType == EGL_OPENGL_ES_API && ((info.clientVersion == 1 && clientVersion != 1) || clientVersion < info.clientVersion)) 409 { 410 log << TestLog::Message << " Fail, client API version doesn't match." << TestLog::EndMessage; 411 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API version"); 412 } 413 } 414 415 // Render buffer 416 if (version >= eglu::Version(1, 2)) 417 { 418 const EGLint renderBuffer = getContextAttrib(display, context, EGL_RENDER_BUFFER); 419 420 if (info.surfaceType == EGL_PIXMAP_BIT && renderBuffer != EGL_SINGLE_BUFFER) 421 { 422 log << TestLog::Message << " Fail, render buffer should be EGL_SINGLE_BUFFER for a pixmap surface." << TestLog::EndMessage; 423 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer"); 424 } 425 else if (info.surfaceType == EGL_PBUFFER_BIT && renderBuffer != EGL_BACK_BUFFER) 426 { 427 log << TestLog::Message << " Fail, render buffer should be EGL_BACK_BUFFER for a pbuffer surface." << TestLog::EndMessage; 428 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer"); 429 } 430 else if (info.surfaceType == EGL_WINDOW_BIT && renderBuffer != EGL_SINGLE_BUFFER && renderBuffer != EGL_BACK_BUFFER) 431 { 432 log << TestLog::Message << " Fail, render buffer should be either EGL_SINGLE_BUFFER or EGL_BACK_BUFFER for a window surface." << TestLog::EndMessage; 433 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer"); 434 } 435 } 436 437 enableLogging(false); 438 439 log << TestLog::Message << " Pass" << TestLog::EndMessage; 440 } 441 }; 442 443 class QueryAPICase : public TestCase, protected eglu::CallLogWrapper 444 { 445 public: 446 QueryAPICase (EglTestContext& eglTestCtx, const char* name, const char* description) 447 : TestCase(eglTestCtx, name, description) 448 , CallLogWrapper(eglTestCtx.getTestContext().getLog()) 449 { 450 } 451 452 void init (void) 453 { 454 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 455 } 456 457 IterateResult iterate (void) 458 { 459 tcu::TestLog& log = m_testCtx.getLog(); 460 const EGLenum apis[] = { EGL_OPENGL_API, EGL_OPENGL_ES_API, EGL_OPENVG_API }; 461 462 enableLogging(true); 463 464 { 465 const EGLenum api = eglQueryAPI(); 466 467 if (api != EGL_OPENGL_ES_API && m_eglTestCtx.isAPISupported(EGL_OPENGL_ES_API)) 468 { 469 log << TestLog::Message << " Fail, initial value should be EGL_OPENGL_ES_API if OpenGL ES is supported." << TestLog::EndMessage; 470 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value"); 471 } 472 else if(api != EGL_NONE && !m_eglTestCtx.isAPISupported(EGL_OPENGL_ES_API)) 473 { 474 log << TestLog::Message << " Fail, initial value should be EGL_NONE if OpenGL ES is not supported." << TestLog::EndMessage; 475 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value"); 476 } 477 } 478 479 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(apis); ndx++) 480 { 481 const EGLenum api = apis[ndx]; 482 483 log << TestLog::Message << TestLog::EndMessage; 484 485 if (m_eglTestCtx.isAPISupported(api)) 486 { 487 eglBindAPI(api); 488 489 if (api != eglQueryAPI()) 490 { 491 log << TestLog::Message << " Fail, return value does not match previously bound API." << TestLog::EndMessage; 492 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid return value"); 493 } 494 } 495 else 496 { 497 log << TestLog::Message << eglu::getAPIStr(api) << " not supported." << TestLog::EndMessage; 498 } 499 } 500 501 enableLogging(false); 502 return STOP; 503 } 504 }; 505 506 QueryContextTests::QueryContextTests (EglTestContext& eglTestCtx) 507 : TestCaseGroup(eglTestCtx, "query_context", "Rendering context query tests") 508 { 509 } 510 511 QueryContextTests::~QueryContextTests (void) 512 { 513 } 514 515 template<class QueryContextClass> 516 void createQueryContextGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group) 517 { 518 std::vector<RenderConfigIdSet> configSets; 519 eglu::FilterList filters; 520 521 getDefaultRenderConfigIdSets(configSets, eglTestCtx.getConfigs(), filters); 522 523 for (std::vector<RenderConfigIdSet>::const_iterator setIter = configSets.begin(); setIter != configSets.end(); setIter++) 524 group->addChild(new QueryContextClass(eglTestCtx, setIter->getName(), "", setIter->getConfigIds(), setIter->getSurfaceTypeMask())); 525 } 526 527 void QueryContextTests::init (void) 528 { 529 { 530 tcu::TestCaseGroup* simpleGroup = new tcu::TestCaseGroup(m_testCtx, "simple", "Simple API tests"); 531 addChild(simpleGroup); 532 533 simpleGroup->addChild(new QueryAPICase(m_eglTestCtx, "query_api", "eglQueryAPI() test")); 534 } 535 536 // eglGetCurrentContext 537 { 538 tcu::TestCaseGroup* getCurrentContextGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_context", "eglGetCurrentContext() tests"); 539 addChild(getCurrentContextGroup); 540 541 createQueryContextGroups<GetCurrentContextCase>(m_eglTestCtx, getCurrentContextGroup); 542 } 543 544 // eglGetCurrentSurface 545 { 546 tcu::TestCaseGroup* getCurrentSurfaceGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_surface", "eglGetCurrentSurface() tests"); 547 addChild(getCurrentSurfaceGroup); 548 549 createQueryContextGroups<GetCurrentSurfaceCase>(m_eglTestCtx, getCurrentSurfaceGroup); 550 } 551 552 // eglGetCurrentDisplay 553 { 554 tcu::TestCaseGroup* getCurrentDisplayGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_display", "eglGetCurrentDisplay() tests"); 555 addChild(getCurrentDisplayGroup); 556 557 createQueryContextGroups<GetCurrentDisplayCase>(m_eglTestCtx, getCurrentDisplayGroup); 558 } 559 560 // eglQueryContext 561 { 562 tcu::TestCaseGroup* queryContextGroup = new tcu::TestCaseGroup(m_testCtx, "query_context", "eglQueryContext() tests"); 563 addChild(queryContextGroup); 564 565 createQueryContextGroups<QueryContextCase>(m_eglTestCtx, queryContextGroup); 566 } 567 } 568 569 } // egl 570 } // deqp 571