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