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 ((requiredAPIs & builtClientAPIs) != requiredAPIs) 109 TCU_THROW(InternalError, "Test case requires client API not supported in current build"); 110} 111 112void 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 208SingleContextRenderCase::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 214SingleContextRenderCase::~SingleContextRenderCase (void) 215{ 216} 217 218void 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 292MultiContextRenderCase::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 299MultiContextRenderCase::~MultiContextRenderCase (void) 300{ 301} 302 303void 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 371template <int Red, int Green, int Blue, int Alpha> 372static 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 380template <int Red, int Green, int Blue, int Alpha> 381static 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 389template <deUint32 Type> 390static bool surfaceType (const eglu::CandidateConfig& c) 391{ 392 return (c.surfaceType() & Type) == Type; 393} 394 395static bool isConformant (const eglu::CandidateConfig& c) 396{ 397 return c.get(EGL_CONFIG_CAVEAT) != EGL_NON_CONFORMANT_CONFIG; 398} 399 400void 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