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 33 #include "tcuRenderTarget.hpp" 34 #include "tcuTestLog.hpp" 35 #include "tcuCommandLine.hpp" 36 37 #include "deStringUtil.hpp" 38 #include "deUniquePtr.hpp" 39 40 #include <algorithm> 41 #include <iterator> 42 #include <memory> 43 #include <set> 44 45 #include <EGL/eglext.h> 46 47 #if !defined(EGL_OPENGL_ES3_BIT_KHR) 48 # define EGL_OPENGL_ES3_BIT_KHR 0x0040 49 #endif 50 #if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR) 51 # define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION 52 #endif 53 54 using std::string; 55 using std::vector; 56 using std::set; 57 58 using tcu::TestLog; 59 60 namespace deqp 61 { 62 namespace egl 63 { 64 65 // \todo [2013-04-24 pyry] Should we instead store surface bit somewhere? 66 template<class Derived, class Base> 67 inline bool instanceOf (Base& obj) 68 { 69 return dynamic_cast<Derived*>(&obj) != DE_NULL; 70 } 71 72 static void postSurface (tcu::egl::Surface& surface) 73 { 74 const bool isWindow = instanceOf<tcu::egl::WindowSurface>(surface); 75 const bool isPixmap = instanceOf<tcu::egl::PixmapSurface>(surface); 76 const bool isPbuffer = instanceOf<tcu::egl::PbufferSurface>(surface); 77 78 DE_ASSERT((isWindow?1:0) + (isPixmap?1:0) + (isPbuffer?1:0) == 1); 79 80 if (isWindow) 81 { 82 tcu::egl::WindowSurface& window = static_cast<tcu::egl::WindowSurface&>(surface); 83 window.swapBuffers(); 84 } 85 else if (isPixmap) 86 { 87 TCU_CHECK_EGL_CALL(eglWaitClient()); 88 } 89 else 90 { 91 DE_ASSERT(isPbuffer); 92 DE_UNREF(isPbuffer); 93 TCU_CHECK_EGL_CALL(eglWaitClient()); 94 } 95 } 96 97 // RenderCase 98 99 RenderCase::RenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint apiMask, EGLint surfaceTypeMask, const vector<EGLint>& configIds) 100 : SimpleConfigCase (eglTestCtx, name, description, configIds) 101 , m_apiMask (apiMask) 102 , m_surfaceTypeMask (surfaceTypeMask) 103 { 104 } 105 106 RenderCase::~RenderCase (void) 107 { 108 } 109 110 EGLint RenderCase::getSupportedApis (void) 111 { 112 EGLint apiMask = 0; 113 114 #if defined(DEQP_SUPPORT_GLES2) 115 apiMask |= EGL_OPENGL_ES2_BIT; 116 #endif 117 118 #if defined(DEQP_SUPPORT_GLES3) 119 apiMask |= EGL_OPENGL_ES3_BIT_KHR; 120 #endif 121 122 #if defined(DEQP_SUPPORT_GLES1) 123 apiMask |= EGL_OPENGL_ES_BIT; 124 #endif 125 126 #if defined(DEQP_SUPPORT_VG) 127 apiMask |= EGL_OPENVG_BIT; 128 #endif 129 130 return apiMask; 131 } 132 133 void RenderCase::executeForConfig (tcu::egl::Display& defaultDisplay, EGLConfig config) 134 { 135 tcu::TestLog& log = m_testCtx.getLog(); 136 int width = 128; 137 int height = 128; 138 EGLint configId = defaultDisplay.getConfigAttrib(config, EGL_CONFIG_ID); 139 bool isOk = true; 140 string failReason = ""; 141 142 if (m_surfaceTypeMask & EGL_WINDOW_BIT) 143 { 144 tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Window").c_str(), 145 (string("Config ID ") + de::toString(configId) + ", window surface").c_str()); 146 147 try 148 { 149 tcu::egl::Display& display = m_eglTestCtx.getDisplay(); 150 de::UniquePtr<eglu::NativeWindow> window (m_eglTestCtx.createNativeWindow(display.getEGLDisplay(), config, DE_NULL, width, height, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); 151 EGLSurface eglSurface = createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, display.getEGLDisplay(), config, DE_NULL); 152 tcu::egl::WindowSurface surface (display, eglSurface); 153 154 executeForSurface(display, surface, config); 155 } 156 catch (const tcu::TestError& e) 157 { 158 log << e; 159 isOk = false; 160 failReason = e.what(); 161 } 162 } 163 164 if (m_surfaceTypeMask & EGL_PIXMAP_BIT) 165 { 166 tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Pixmap").c_str(), 167 (string("Config ID ") + de::toString(configId) + ", pixmap surface").c_str()); 168 169 try 170 { 171 tcu::egl::Display& display = m_eglTestCtx.getDisplay(); 172 std::auto_ptr<eglu::NativePixmap> pixmap (m_eglTestCtx.createNativePixmap(display.getEGLDisplay(), config, DE_NULL, width, height)); 173 EGLSurface eglSurface = createPixmapSurface(m_eglTestCtx.getNativeDisplay(), *pixmap, display.getEGLDisplay(), config, DE_NULL); 174 tcu::egl::PixmapSurface surface (display, eglSurface); 175 176 executeForSurface(display, surface, config); 177 } 178 catch (const tcu::TestError& e) 179 { 180 log << e; 181 isOk = false; 182 failReason = e.what(); 183 } 184 } 185 186 if (m_surfaceTypeMask & EGL_PBUFFER_BIT) 187 { 188 tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Pbuffer").c_str(), 189 (string("Config ID ") + de::toString(configId) + ", pbuffer surface").c_str()); 190 try 191 { 192 EGLint surfaceAttribs[] = 193 { 194 EGL_WIDTH, width, 195 EGL_HEIGHT, height, 196 EGL_NONE 197 }; 198 199 tcu::egl::PbufferSurface surface(defaultDisplay, config, surfaceAttribs); 200 201 executeForSurface(defaultDisplay, surface, config); 202 } 203 catch (const tcu::TestError& e) 204 { 205 log << e; 206 isOk = false; 207 failReason = e.what(); 208 } 209 } 210 211 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 212 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason.c_str()); 213 } 214 215 // SingleContextRenderCase 216 217 SingleContextRenderCase::SingleContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint apiMask, EGLint surfaceTypeMask, const std::vector<EGLint>& configIds) 218 : RenderCase(eglTestCtx, name, description, apiMask, surfaceTypeMask, configIds) 219 { 220 } 221 222 SingleContextRenderCase::~SingleContextRenderCase (void) 223 { 224 } 225 226 void SingleContextRenderCase::executeForSurface (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config) 227 { 228 EGLint supportedApis = getSupportedApis(); 229 const EGLint apis[] = { EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT }; 230 tcu::TestLog& log = m_testCtx.getLog(); 231 232 // Check if case is supported 233 if ((m_apiMask & supportedApis) != m_apiMask) 234 throw tcu::NotSupportedError("Client APIs not supported", "", __FILE__, __LINE__); 235 236 for (int apiNdx = 0; apiNdx < DE_LENGTH_OF_ARRAY(apis); apiNdx++) 237 { 238 EGLint apiBit = apis[apiNdx]; 239 240 if ((apiBit & m_apiMask) == 0) 241 continue; // Skip this api. 242 243 EGLint api = EGL_NONE; 244 const char* apiName = DE_NULL; 245 vector<EGLint> contextAttribs; 246 247 // Select api enum and build context attributes. 248 switch (apiBit) 249 { 250 case EGL_OPENGL_ES2_BIT: 251 api = EGL_OPENGL_ES_API; 252 apiName = "OpenGL ES 2.x"; 253 contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION); 254 contextAttribs.push_back(2); 255 break; 256 257 case EGL_OPENGL_ES3_BIT_KHR: 258 api = EGL_OPENGL_ES_API; 259 apiName = "OpenGL ES 3.x"; 260 contextAttribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); 261 contextAttribs.push_back(3); 262 break; 263 264 case EGL_OPENGL_ES_BIT: 265 api = EGL_OPENGL_ES_API; 266 apiName = "OpenGL ES 1.x"; 267 contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION); 268 contextAttribs.push_back(1); 269 break; 270 271 case EGL_OPENVG_BIT: 272 api = EGL_OPENVG_API; 273 apiName = "OpenVG"; 274 break; 275 276 default: 277 DE_ASSERT(DE_FALSE); 278 } 279 280 contextAttribs.push_back(EGL_NONE); 281 282 log << TestLog::Message << apiName << TestLog::EndMessage; 283 284 tcu::egl::Context context(display, config, &contextAttribs[0], api); 285 286 context.makeCurrent(surface, surface); 287 executeForContext(display, context, surface, apiBit); 288 289 // Call SwapBuffers() / WaitClient() to finish rendering 290 postSurface(surface); 291 } 292 } 293 294 // MultiContextRenderCase 295 296 MultiContextRenderCase::MultiContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const vector<EGLint>& configIds, int numContextsPerApi) 297 : RenderCase (eglTestCtx, name, description, api, surfaceType, configIds) 298 , m_numContextsPerApi (numContextsPerApi) 299 { 300 } 301 302 MultiContextRenderCase::~MultiContextRenderCase (void) 303 { 304 } 305 306 void MultiContextRenderCase::executeForSurface (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config) 307 { 308 vector<std::pair<EGLint, tcu::egl::Context*> > contexts; 309 contexts.reserve(3*m_numContextsPerApi); // 3 types of contexts at maximum. 310 311 try 312 { 313 // Create contexts that will participate in rendering. 314 for (int ndx = 0; ndx < m_numContextsPerApi; ndx++) 315 { 316 if (m_apiMask & EGL_OPENGL_ES2_BIT) 317 { 318 static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 319 contexts.push_back(std::make_pair(EGL_OPENGL_ES2_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API))); 320 } 321 322 if (m_apiMask & EGL_OPENGL_ES3_BIT_KHR) 323 { 324 static const EGLint attribs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_NONE }; 325 contexts.push_back(std::make_pair(EGL_OPENGL_ES3_BIT_KHR, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API))); 326 } 327 328 if (m_apiMask & EGL_OPENGL_ES_BIT) 329 { 330 static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; 331 contexts.push_back(std::make_pair(EGL_OPENGL_ES_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API))); 332 } 333 334 if (m_apiMask & EGL_OPENVG_BIT) 335 { 336 static const EGLint attribs[] = { EGL_NONE }; 337 contexts.push_back(std::make_pair(EGL_OPENVG_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENVG_API))); 338 } 339 } 340 341 // Execute for contexts. 342 executeForContexts(display, surface, config, contexts); 343 } 344 catch (const std::exception&) 345 { 346 // Make sure all contexts have been destroyed. 347 for (vector<std::pair<EGLint, tcu::egl::Context*> >::iterator i = contexts.begin(); i != contexts.end(); i++) 348 delete i->second; 349 throw; 350 } 351 352 // Destroy contexts. 353 for (vector<std::pair<EGLint, tcu::egl::Context*> >::iterator i = contexts.begin(); i != contexts.end(); i++) 354 delete i->second; 355 } 356 357 // Utilities 358 359 void addRenderConfigIdSet ( 360 vector<RenderConfigIdSet>& configSets, 361 const vector<eglu::ConfigInfo>& configInfos, 362 const eglu::FilterList& baseFilters, 363 const char* name, 364 tcu::RGBA colorBits, 365 EGLint surfaceType) 366 { 367 eglu::FilterList filters = baseFilters; 368 filters << (eglu::ConfigColorBits() == colorBits) << (eglu::ConfigSurfaceType() & surfaceType); 369 370 vector<EGLint> matchingConfigs; 371 372 for (vector<eglu::ConfigInfo>::const_iterator configIter = configInfos.begin(); configIter != configInfos.end(); configIter++) 373 { 374 if (!filters.match(*configIter)) 375 continue; 376 377 matchingConfigs.push_back(configIter->configId); 378 } 379 380 configSets.push_back(RenderConfigIdSet(name, "", matchingConfigs, surfaceType)); 381 } 382 383 void addRenderConfigIdSet ( 384 vector<RenderConfigIdSet>& configSets, 385 const vector<eglu::ConfigInfo>& configInfos, 386 const eglu::FilterList& baseFilters, 387 const char* name, 388 tcu::RGBA colorBits) 389 { 390 addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_window").c_str(), colorBits, EGL_WINDOW_BIT); 391 addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_pixmap").c_str(), colorBits, EGL_PIXMAP_BIT); 392 addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_pbuffer").c_str(), colorBits, EGL_PBUFFER_BIT); 393 } 394 395 void getDefaultRenderConfigIdSets (vector<RenderConfigIdSet>& configSets, const vector<eglu::ConfigInfo>& configInfos, const eglu::FilterList& baseFilters) 396 { 397 using tcu::RGBA; 398 399 addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgb565", RGBA(5, 6, 5, 0)); 400 addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgb888", RGBA(8, 8, 8, 0)); 401 addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba4444", RGBA(4, 4, 4, 4)); 402 addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba5551", RGBA(5, 5, 5, 1)); 403 addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba8888", RGBA(8, 8, 8, 8)); 404 405 // Add other config ids to "other" set 406 { 407 set<EGLint> usedConfigs; 408 vector<EGLint> otherCfgSet; 409 410 for (vector<RenderConfigIdSet>::const_iterator setIter = configSets.begin(); setIter != configSets.end(); setIter++) 411 { 412 const vector<EGLint>& setCfgs = setIter->getConfigIds(); 413 for (vector<EGLint>::const_iterator i = setCfgs.begin(); i != setCfgs.end(); i++) 414 usedConfigs.insert(*i); 415 } 416 417 for (vector<eglu::ConfigInfo>::const_iterator cfgIter = configInfos.begin(); cfgIter != configInfos.end(); cfgIter++) 418 { 419 if (!baseFilters.match(*cfgIter)) 420 continue; 421 422 EGLint id = cfgIter->configId; 423 424 if (usedConfigs.find(id) == usedConfigs.end()) 425 otherCfgSet.push_back(id); 426 } 427 428 configSets.push_back(RenderConfigIdSet("other", "", otherCfgSet, EGL_WINDOW_BIT|EGL_PIXMAP_BIT|EGL_PBUFFER_BIT)); 429 } 430 } 431 432 } // egl 433 } // deqp 434