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