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 Base class for rendering tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "teglRenderCase.hpp" 25 26 #include "teglSimpleConfigCase.hpp" 27 28 #include "egluNativeDisplay.hpp" 29 #include "egluNativeWindow.hpp" 30 #include "egluNativePixmap.hpp" 31 #include "egluUtil.hpp" 32 #include "egluUnique.hpp" 33 34 #include "eglwLibrary.hpp" 35 #include "eglwEnums.hpp" 36 37 #include "tcuRenderTarget.hpp" 38 #include "tcuTestLog.hpp" 39 #include "tcuCommandLine.hpp" 40 41 #include "deStringUtil.hpp" 42 #include "deUniquePtr.hpp" 43 44 #include <algorithm> 45 #include <iterator> 46 #include <memory> 47 #include <set> 48 49 namespace deqp 50 { 51 namespace egl 52 { 53 54 using std::string; 55 using std::vector; 56 using std::set; 57 using tcu::TestLog; 58 using namespace eglw; 59 60 static void postSurface (const Library& egl, EGLDisplay display, EGLSurface surface, EGLint typeBit) 61 { 62 if (typeBit == EGL_WINDOW_BIT) 63 EGLU_CHECK_CALL(egl, swapBuffers(display, surface)); 64 else if (typeBit == EGL_PIXMAP_BIT) 65 EGLU_CHECK_CALL(egl, waitClient()); 66 else if (typeBit == EGL_PBUFFER_BIT) 67 EGLU_CHECK_CALL(egl, waitClient()); 68 else 69 DE_ASSERT(false); 70 } 71 72 // RenderCase 73 74 RenderCase::RenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint surfaceTypeMask, const eglu::FilterList& filters) 75 : SimpleConfigCase (eglTestCtx, name, description, filters) 76 , m_surfaceTypeMask (surfaceTypeMask) 77 { 78 } 79 80 RenderCase::~RenderCase (void) 81 { 82 } 83 84 EGLint getBuildClientAPIMask (void) 85 { 86 EGLint apiMask = 0; 87 88 // Always supported regardless of flags - dynamically loaded 89 apiMask |= EGL_OPENGL_ES2_BIT; 90 apiMask |= EGL_OPENGL_ES3_BIT; 91 apiMask |= EGL_OPENGL_BIT; 92 93 #if defined(DEQP_SUPPORT_GLES1) 94 apiMask |= EGL_OPENGL_ES_BIT; 95 #endif 96 97 #if defined(DEQP_SUPPORT_VG) 98 apiMask |= EGL_OPENVG_BIT; 99 #endif 100 101 return apiMask; 102 } 103 104 static void checkBuildClientAPISupport (EGLint requiredAPIs) 105 { 106 const EGLint builtClientAPIs = getBuildClientAPIMask(); 107 108 #if !defined(DEQP_SUPPORT_GLES1) 109 if (requiredAPIs & EGL_OPENGL_ES_BIT) 110 TCU_THROW(NotSupportedError, "Test case requires ES1.1 API not supported in current build"); 111 else 112 #endif 113 if ((requiredAPIs & builtClientAPIs) != requiredAPIs) 114 TCU_THROW(InternalError, "Test case requires client API not supported in current build"); 115 } 116 117 void RenderCase::executeForConfig (EGLDisplay display, EGLConfig config) 118 { 119 const Library& egl = m_eglTestCtx.getLibrary(); 120 tcu::TestLog& log = m_testCtx.getLog(); 121 const int width = 128; 122 const int height = 128; 123 const EGLint configId = eglu::getConfigID(egl, display, config); 124 125 const eglu::NativeDisplayFactory& displayFactory = m_eglTestCtx.getNativeDisplayFactory(); 126 eglu::NativeDisplay& nativeDisplay = m_eglTestCtx.getNativeDisplay(); 127 128 bool isOk = true; 129 string failReason = ""; 130 131 if (m_surfaceTypeMask & EGL_WINDOW_BIT) 132 { 133 tcu::ScopedLogSection(log, 134 string("Config") + de::toString(configId) + "-Window", 135 string("Config ID ") + de::toString(configId) + ", window surface"); 136 137 const eglu::NativeWindowFactory& windowFactory = eglu::selectNativeWindowFactory(displayFactory, m_testCtx.getCommandLine()); 138 139 try 140 { 141 const eglu::WindowParams params (width, height, eglu::parseWindowVisibility(m_testCtx.getCommandLine())); 142 de::UniquePtr<eglu::NativeWindow> window (windowFactory.createWindow(&nativeDisplay, display, config, DE_NULL, params)); 143 EGLSurface eglSurface = createWindowSurface(nativeDisplay, *window, display, config, DE_NULL); 144 eglu::UniqueSurface surface (egl, display, eglSurface); 145 146 executeForSurface(display, *surface, Config(config, EGL_WINDOW_BIT, 0)); 147 } 148 catch (const tcu::TestError& e) 149 { 150 log << e; 151 isOk = false; 152 failReason = e.what(); 153 } 154 } 155 156 if (m_surfaceTypeMask & EGL_PIXMAP_BIT) 157 { 158 tcu::ScopedLogSection(log, 159 string("Config") + de::toString(configId) + "-Pixmap", 160 string("Config ID ") + de::toString(configId) + ", pixmap surface"); 161 162 const eglu::NativePixmapFactory& pixmapFactory = eglu::selectNativePixmapFactory(displayFactory, m_testCtx.getCommandLine()); 163 164 try 165 { 166 de::UniquePtr<eglu::NativePixmap> pixmap (pixmapFactory.createPixmap(&nativeDisplay, display, config, DE_NULL, width, height)); 167 EGLSurface eglSurface = createPixmapSurface(nativeDisplay, *pixmap, display, config, DE_NULL); 168 eglu::UniqueSurface surface (egl, display, eglSurface); 169 170 executeForSurface(display, *surface, Config(config, EGL_PIXMAP_BIT, 0)); 171 } 172 catch (const tcu::TestError& e) 173 { 174 log << e; 175 isOk = false; 176 failReason = e.what(); 177 } 178 } 179 180 if (m_surfaceTypeMask & EGL_PBUFFER_BIT) 181 { 182 tcu::ScopedLogSection(log, 183 string("Config") + de::toString(configId) + "-Pbuffer", 184 string("Config ID ") + de::toString(configId) + ", pbuffer surface"); 185 try 186 { 187 const EGLint surfaceAttribs[] = 188 { 189 EGL_WIDTH, width, 190 EGL_HEIGHT, height, 191 EGL_NONE 192 }; 193 194 eglu::UniqueSurface surface(egl, display, egl.createPbufferSurface(display, config, surfaceAttribs)); 195 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()"); 196 197 executeForSurface(display, *surface, Config(config, EGL_PBUFFER_BIT, 0)); 198 } 199 catch (const tcu::TestError& e) 200 { 201 log << e; 202 isOk = false; 203 failReason = e.what(); 204 } 205 } 206 207 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 208 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason.c_str()); 209 } 210 211 // SingleContextRenderCase 212 213 SingleContextRenderCase::SingleContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint apiMask, EGLint surfaceTypeMask, const eglu::FilterList& filters) 214 : RenderCase (eglTestCtx, name, description, surfaceTypeMask, filters) 215 , m_apiMask (apiMask) 216 { 217 } 218 219 SingleContextRenderCase::~SingleContextRenderCase (void) 220 { 221 } 222 223 void SingleContextRenderCase::executeForSurface (EGLDisplay display, EGLSurface surface, const Config& config) 224 { 225 const Library& egl = m_eglTestCtx.getLibrary(); 226 const EGLint apis[] = { EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT }; 227 tcu::TestLog& log = m_testCtx.getLog(); 228 const EGLint configApiMask = eglu::getConfigAttribInt(egl, display, config.config, EGL_RENDERABLE_TYPE); 229 230 checkBuildClientAPISupport(m_apiMask); 231 232 for (int apiNdx = 0; apiNdx < DE_LENGTH_OF_ARRAY(apis); apiNdx++) 233 { 234 EGLint apiBit = apis[apiNdx]; 235 236 // Skip API if build or current config doesn't support it. 237 if ((apiBit & m_apiMask) == 0 || (apiBit & configApiMask) == 0) 238 continue; 239 240 EGLint api = EGL_NONE; 241 const char* apiName = DE_NULL; 242 vector<EGLint> contextAttribs; 243 244 // Select api enum and build context attributes. 245 switch (apiBit) 246 { 247 case EGL_OPENGL_ES2_BIT: 248 api = EGL_OPENGL_ES_API; 249 apiName = "OpenGL ES 2.x"; 250 contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION); 251 contextAttribs.push_back(2); 252 break; 253 254 case EGL_OPENGL_ES3_BIT_KHR: 255 api = EGL_OPENGL_ES_API; 256 apiName = "OpenGL ES 3.x"; 257 contextAttribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); 258 contextAttribs.push_back(3); 259 break; 260 261 case EGL_OPENGL_ES_BIT: 262 api = EGL_OPENGL_ES_API; 263 apiName = "OpenGL ES 1.x"; 264 contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION); 265 contextAttribs.push_back(1); 266 break; 267 268 case EGL_OPENVG_BIT: 269 api = EGL_OPENVG_API; 270 apiName = "OpenVG"; 271 break; 272 273 default: 274 DE_ASSERT(DE_FALSE); 275 } 276 277 contextAttribs.push_back(EGL_NONE); 278 279 log << TestLog::Message << apiName << TestLog::EndMessage; 280 281 EGLU_CHECK_CALL(egl, bindAPI(api)); 282 283 eglu::UniqueContext context (egl, display, egl.createContext(display, config.config, EGL_NO_CONTEXT, &contextAttribs[0])); 284 285 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, *context)); 286 executeForContext(display, *context, surface, Config(config.config, config.surfaceTypeBit, apiBit)); 287 288 // Call SwapBuffers() / WaitClient() to finish rendering 289 postSurface(egl, display, surface, config.surfaceTypeBit); 290 } 291 292 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 293 } 294 295 // MultiContextRenderCase 296 297 MultiContextRenderCase::MultiContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi) 298 : RenderCase (eglTestCtx, name, description, surfaceType, filters) 299 , m_numContextsPerApi (numContextsPerApi) 300 , m_apiMask (api) 301 { 302 } 303 304 MultiContextRenderCase::~MultiContextRenderCase (void) 305 { 306 } 307 308 void MultiContextRenderCase::executeForSurface (EGLDisplay display, EGLSurface surface, const Config& config) 309 { 310 const Library& egl = m_eglTestCtx.getLibrary(); 311 const EGLint configApiMask = eglu::getConfigAttribInt(egl, display, config.config, EGL_RENDERABLE_TYPE); 312 vector<std::pair<EGLint, EGLContext> > contexts; 313 contexts.reserve(3*m_numContextsPerApi); // 3 types of contexts at maximum. 314 315 checkBuildClientAPISupport(m_apiMask); 316 317 // ConfigFilter should make sure that config always supports all of the APIs. 318 TCU_CHECK_INTERNAL((configApiMask & m_apiMask) == m_apiMask); 319 320 try 321 { 322 // Create contexts that will participate in rendering. 323 for (int ndx = 0; ndx < m_numContextsPerApi; ndx++) 324 { 325 if (m_apiMask & EGL_OPENGL_ES2_BIT) 326 { 327 static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 328 EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API)); 329 contexts.push_back(std::make_pair(EGL_OPENGL_ES2_BIT, egl.createContext(display, config.config, EGL_NO_CONTEXT, &attribs[0]))); 330 } 331 332 if (m_apiMask & EGL_OPENGL_ES3_BIT_KHR) 333 { 334 static const EGLint attribs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_NONE }; 335 EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API)); 336 contexts.push_back(std::make_pair(EGL_OPENGL_ES3_BIT_KHR, egl.createContext(display, config.config, EGL_NO_CONTEXT, &attribs[0]))); 337 } 338 339 if (m_apiMask & EGL_OPENGL_ES_BIT) 340 { 341 static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; 342 EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API)); 343 contexts.push_back(std::make_pair(EGL_OPENGL_ES_BIT, egl.createContext(display, config.config, EGL_NO_CONTEXT, &attribs[0]))); 344 } 345 346 if (m_apiMask & EGL_OPENVG_BIT) 347 { 348 static const EGLint attribs[] = { EGL_NONE }; 349 EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENVG_API)); 350 contexts.push_back(std::make_pair(EGL_OPENVG_BIT, egl.createContext(display, config.config, EGL_NO_CONTEXT, &attribs[0]))); 351 } 352 } 353 354 EGLU_CHECK_MSG(egl, "eglCreateContext()"); 355 356 // Execute for contexts. 357 executeForContexts(display, surface, Config(config.config, config.surfaceTypeBit, m_apiMask), contexts); 358 359 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 360 } 361 catch (...) 362 { 363 // Make sure all contexts have been destroyed. 364 for (vector<std::pair<EGLint, EGLContext> >::iterator i = contexts.begin(); i != contexts.end(); i++) 365 egl.destroyContext(display, i->second); 366 throw; 367 } 368 369 // Destroy contexts. 370 for (vector<std::pair<EGLint, EGLContext> >::iterator i = contexts.begin(); i != contexts.end(); i++) 371 egl.destroyContext(display, i->second); 372 } 373 374 // Utilities 375 376 template <int Red, int Green, int Blue, int Alpha> 377 static bool colorBits (const eglu::CandidateConfig& c) 378 { 379 return c.redSize() == Red && 380 c.greenSize() == Green && 381 c.blueSize() == Blue && 382 c.alphaSize() == Alpha; 383 } 384 385 template <int Red, int Green, int Blue, int Alpha> 386 static bool notColorBits (const eglu::CandidateConfig& c) 387 { 388 return c.redSize() != Red || 389 c.greenSize() != Green || 390 c.blueSize() != Blue || 391 c.alphaSize() != Alpha; 392 } 393 394 template <deUint32 Type> 395 static bool surfaceType (const eglu::CandidateConfig& c) 396 { 397 return (c.surfaceType() & Type) == Type; 398 } 399 400 static bool isConformant (const eglu::CandidateConfig& c) 401 { 402 return c.get(EGL_CONFIG_CAVEAT) != EGL_NON_CONFORMANT_CONFIG; 403 } 404 405 static bool notFloat (const eglu::CandidateConfig& c) 406 { 407 return c.colorComponentType() != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT; 408 } 409 410 static bool notYUV (const eglu::CandidateConfig& c) 411 { 412 return c.colorBufferType() != EGL_YUV_BUFFER_EXT; 413 } 414 415 void getDefaultRenderFilterLists (vector<RenderFilterList>& filterLists, const eglu::FilterList& baseFilters) 416 { 417 static const struct 418 { 419 const char* name; 420 eglu::ConfigFilter filter; 421 } s_colorRules[] = 422 { 423 { "rgb565", colorBits<5, 6, 5, 0> }, 424 { "rgb888", colorBits<8, 8, 8, 0> }, 425 { "rgba4444", colorBits<4, 4, 4, 4> }, 426 { "rgba5551", colorBits<5, 5, 5, 1> }, 427 { "rgba8888", colorBits<8, 8, 8, 8> }, 428 }; 429 430 static const struct 431 { 432 const char* name; 433 EGLint bits; 434 eglu::ConfigFilter filter; 435 } s_surfaceRules[] = 436 { 437 { "window", EGL_WINDOW_BIT, surfaceType<EGL_WINDOW_BIT> }, 438 { "pixmap", EGL_PIXMAP_BIT, surfaceType<EGL_PIXMAP_BIT>, }, 439 { "pbuffer", EGL_PBUFFER_BIT, surfaceType<EGL_PBUFFER_BIT> } 440 }; 441 442 for (int colorNdx = 0; colorNdx < DE_LENGTH_OF_ARRAY(s_colorRules); colorNdx++) 443 { 444 for (int surfaceNdx = 0; surfaceNdx < DE_LENGTH_OF_ARRAY(s_surfaceRules); surfaceNdx++) 445 { 446 const string name = string(s_colorRules[colorNdx].name) + "_" + s_surfaceRules[surfaceNdx].name; 447 RenderFilterList filters (name.c_str(), "", s_surfaceRules[surfaceNdx].bits); 448 449 filters << baseFilters 450 << s_colorRules[colorNdx].filter 451 << s_surfaceRules[surfaceNdx].filter 452 << isConformant; 453 454 filterLists.push_back(filters); 455 } 456 } 457 458 // Add other config ids to "other" set 459 { 460 RenderFilterList filters ("other", "", EGL_WINDOW_BIT|EGL_PIXMAP_BIT|EGL_PBUFFER_BIT); 461 462 filters << baseFilters 463 << notColorBits<5, 6, 5, 0> 464 << notColorBits<8, 8, 8, 0> 465 << notColorBits<4, 4, 4, 4> 466 << notColorBits<5, 5, 5, 1> 467 << notColorBits<8, 8, 8, 8> 468 << isConformant 469 << notFloat 470 << notYUV; 471 472 filterLists.push_back(filters); 473 } 474 } 475 476 } // egl 477 } // deqp 478