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 Config query tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "teglQueryConfigTests.hpp" 25#include "teglSimpleConfigCase.hpp" 26#include "tcuTestLog.hpp" 27#include "tcuTestContext.hpp" 28#include "tcuCommandLine.hpp" 29#include "egluCallLogWrapper.hpp" 30#include "egluStrUtil.hpp" 31#include "egluUtil.hpp" 32#include "eglwLibrary.hpp" 33#include "eglwEnums.hpp" 34#include "deRandom.hpp" 35 36#include <string> 37#include <vector> 38 39namespace deqp 40{ 41namespace egl 42{ 43 44using eglu::ConfigInfo; 45using tcu::TestLog; 46using namespace eglw; 47 48static void logConfigAttribute (TestLog& log, EGLenum attrib, EGLint value) 49{ 50 log << TestLog::Message << " " << eglu::getConfigAttribName(attrib) << ": " << eglu::getConfigAttribValueStr(attrib, value) << TestLog::EndMessage; 51} 52 53static bool isAttributePresent (const eglu::Version& version, EGLenum attribute) 54{ 55 switch (attribute) 56 { 57 case EGL_CONFORMANT: 58 if (version < eglu::Version(1, 3)) return false; 59 break; 60 case EGL_LUMINANCE_SIZE: 61 case EGL_ALPHA_MASK_SIZE: 62 case EGL_COLOR_BUFFER_TYPE: 63 case EGL_MATCH_NATIVE_PIXMAP: 64 if (version < eglu::Version(1, 2)) return false; 65 break; 66 case EGL_BIND_TO_TEXTURE_RGB: 67 case EGL_BIND_TO_TEXTURE_RGBA: 68 case EGL_MAX_SWAP_INTERVAL: 69 case EGL_MIN_SWAP_INTERVAL: 70 case EGL_RENDERABLE_TYPE: 71 if (version < eglu::Version(1, 1)) return false; 72 break; 73 default: 74 break; 75 } 76 77 return true; 78} 79 80class GetConfigsBoundsCase : public TestCase, protected eglu::CallLogWrapper 81{ 82public: 83 GetConfigsBoundsCase (EglTestContext& eglTestCtx, const char* name, const char* description) 84 : TestCase (eglTestCtx, name, description) 85 , CallLogWrapper(eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog()) 86 , m_display (EGL_NO_DISPLAY) 87 { 88 } 89 90 void init (void) 91 { 92 DE_ASSERT(m_display == EGL_NO_DISPLAY); 93 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 94 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 95 } 96 97 void deinit (void) 98 { 99 m_eglTestCtx.getLibrary().terminate(m_display); 100 m_display = EGL_NO_DISPLAY; 101 } 102 103 void checkGetConfigsBounds (de::Random& rnd, const int numConfigAll, const int numConfigRequested) 104 { 105 tcu::TestLog& log = m_testCtx.getLog(); 106 std::vector<EGLConfig> buffer (numConfigAll + 10); 107 108 std::vector<deUint32> magicBuffer ((buffer.size() * sizeof(EGLConfig)) / sizeof(deUint32) + 1); 109 const EGLConfig* magicConfigs = reinterpret_cast<EGLConfig*>(&magicBuffer[0]); 110 111 int numConfigReturned; 112 113 // Fill buffers with magic 114 for (size_t ndx = 0; ndx < magicBuffer.size(); ndx++) magicBuffer[ndx] = rnd.getUint32(); 115 for (size_t ndx = 0; ndx < buffer.size(); ndx++) buffer[ndx] = magicConfigs[ndx]; 116 117 eglGetConfigs(m_display, &buffer[0], numConfigRequested, &numConfigReturned); 118 eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); 119 120 log << TestLog::Message << numConfigReturned << " configs returned" << TestLog::EndMessage; 121 122 // Compare results with stored magic 123 { 124 int numOverwritten = 0; 125 126 for (size_t ndx = 0; ndx < buffer.size(); ndx++) 127 { 128 if (buffer[ndx] == magicConfigs[ndx]) 129 { 130 numOverwritten = (int)ndx; 131 break; 132 } 133 } 134 135 log << TestLog::Message << numOverwritten << " values actually written" << TestLog::EndMessage; 136 137 if (numConfigReturned > deMax32(numConfigRequested, 0)) 138 { 139 log << TestLog::Message << "Fail, more configs returned than requested." << TestLog::EndMessage; 140 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Too many configs returned"); 141 } 142 143 if (numOverwritten > deMax32(numConfigReturned, 0)) 144 { 145 log << TestLog::Message << "Fail, buffer overflow detected." << TestLog::EndMessage; 146 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer overflow"); 147 } 148 else if (numOverwritten != numConfigReturned) 149 { 150 log << TestLog::Message << "Fail, reported number of returned configs differs from number of values written." << TestLog::EndMessage; 151 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect size"); 152 } 153 } 154 } 155 156 IterateResult iterate (void) 157 { 158 tcu::TestLog& log = m_testCtx.getLog(); 159 EGLint numConfigAll; 160 161 enableLogging(true); 162 163 eglGetConfigs(m_display, 0, 0, &numConfigAll); 164 165 log << TestLog::Message << numConfigAll << " configs available" << TestLog::EndMessage; 166 log << TestLog::Message << TestLog::EndMessage; 167 168 if (numConfigAll > 0) 169 { 170 de::Random rnd (123); 171 172 for (int i = 0; i < 5; i++) 173 { 174 checkGetConfigsBounds(rnd, numConfigAll, rnd.getInt(0, numConfigAll)); 175 log << TestLog::Message << TestLog::EndMessage; 176 } 177 178 checkGetConfigsBounds(rnd, numConfigAll, -1); 179 } 180 else 181 { 182 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "No configs"); 183 } 184 185 enableLogging(false); 186 187 return STOP; 188 } 189 190protected: 191 EGLDisplay m_display; 192}; 193 194class GetConfigAttribCase : public TestCase, protected eglu::CallLogWrapper 195{ 196public: 197 GetConfigAttribCase (EglTestContext& eglTestCtx, const char* name, const char* description); 198 199 void init (void); 200 void deinit (void); 201 IterateResult iterate (void); 202 203 EGLint getValue (EGLConfig config, EGLenum attrib, bool logValue=true); 204 205 virtual void executeTest (EGLConfig config) = 0; 206 207protected: 208 EGLDisplay m_display; 209 210private: 211 std::vector<EGLConfig> m_configs; 212 std::vector<EGLConfig>::const_iterator m_configsIter; 213}; 214 215GetConfigAttribCase::GetConfigAttribCase (EglTestContext& eglTestCtx, const char* name, const char* description) 216 : TestCase (eglTestCtx, name, description) 217 , CallLogWrapper (eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog()) 218 , m_display (EGL_NO_DISPLAY) 219{ 220} 221 222void GetConfigAttribCase::init (void) 223{ 224 DE_ASSERT(m_display == EGL_NO_DISPLAY); 225 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 226 m_configs = eglu::getConfigs(m_eglTestCtx.getLibrary(), m_display); 227 m_configsIter = m_configs.begin(); 228 229 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 230} 231 232void GetConfigAttribCase::deinit (void) 233{ 234 m_eglTestCtx.getLibrary().terminate(m_display); 235 m_display = EGL_NO_DISPLAY; 236} 237 238tcu::TestNode::IterateResult GetConfigAttribCase::iterate (void) 239{ 240 tcu::TestLog& log = m_testCtx.getLog(); 241 242 if (m_configsIter == m_configs.end()) 243 { 244 log << TestLog::Message << "No configs available." << TestLog::EndMessage; 245 return STOP; 246 } 247 248 { 249 const EGLConfig config = *m_configsIter; 250 EGLint id; 251 252 eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &id); 253 eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); 254 log << TestLog::Message << "Config ID " << id << TestLog::EndMessage; 255 256 executeTest(config); 257 } 258 259 log << TestLog::Message << TestLog::EndMessage; 260 261 m_configsIter++; 262 263 if (m_configsIter == m_configs.end()) 264 return STOP; 265 else 266 return CONTINUE; 267} 268 269EGLint GetConfigAttribCase::getValue (EGLConfig config, EGLenum attrib, bool logValue) 270{ 271 TestLog& log = m_testCtx.getLog(); 272 EGLint value; 273 274 eglGetConfigAttrib(m_display, config, attrib, &value); 275 eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); 276 277 if (logValue) 278 logConfigAttribute(log, attrib, value); 279 280 return value; 281} 282 283class GetConfigAttribSimpleCase : public GetConfigAttribCase 284{ 285public: 286 GetConfigAttribSimpleCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLenum attribute) 287 : GetConfigAttribCase(eglTestCtx, name, description) 288 , m_attrib(attribute) 289 { 290 } 291 292 void checkColorBufferType (EGLint value) 293 { 294 const bool isRGBBuffer = value == EGL_RGB_BUFFER; 295 const bool isLuminanceBuffer = value == EGL_LUMINANCE_BUFFER; 296 const bool isYuvBuffer = value == EGL_YUV_BUFFER_EXT; 297 const bool hasYuvSupport = eglu::hasExtension(m_eglTestCtx.getLibrary(), m_display, "EGL_EXT_yuv_surface"); 298 299 if (!(isRGBBuffer || isLuminanceBuffer || (isYuvBuffer && hasYuvSupport))) 300 { 301 TestLog& log = m_testCtx.getLog(); 302 303 log << TestLog::Message << "Fail, invalid EGL_COLOR_BUFFER_TYPE value" << TestLog::EndMessage; 304 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 305 } 306 } 307 308 void checkCaveat (EGLint value) 309 { 310 if (!(value == EGL_NONE || value == EGL_SLOW_CONFIG || value == EGL_NON_CONFORMANT_CONFIG)) 311 { 312 TestLog& log = m_testCtx.getLog(); 313 314 log << TestLog::Message << "Fail, invalid EGL_CONFIG_CAVEAT value" << TestLog::EndMessage; 315 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 316 } 317 } 318 319 void checkTransparentType (EGLint value) 320 { 321 if (!(value == EGL_NONE || value == EGL_TRANSPARENT_RGB)) 322 { 323 TestLog& log = m_testCtx.getLog(); 324 325 log << TestLog::Message << "Fail, invalid EGL_TRANSPARENT_TYPE value" << TestLog::EndMessage; 326 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 327 } 328 } 329 330 void checkBoolean (EGLenum attrib, EGLint value) 331 { 332 if (!(value == EGL_FALSE || value == EGL_TRUE)) 333 { 334 TestLog& log = m_testCtx.getLog(); 335 336 log << TestLog::Message << "Fail, " << eglu::getConfigAttribStr(attrib) << " should be a boolean value." << TestLog::EndMessage; 337 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 338 } 339 } 340 341 void checkInteger (EGLenum attrib, EGLint value) 342 { 343 if (attrib == EGL_NATIVE_VISUAL_ID || attrib == EGL_NATIVE_VISUAL_TYPE) // Implementation-defined 344 return; 345 346 if (attrib == EGL_CONFIG_ID && value < 1) 347 { 348 TestLog& log = m_testCtx.getLog(); 349 350 log << TestLog::Message << "Fail, config IDs should be positive integer values beginning from 1." << TestLog::EndMessage; 351 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 352 } 353 } 354 355 void checkSurfaceTypeMask (EGLint value) 356 { 357 const EGLint wantedBits = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT; 358 359 if ((value & wantedBits) == 0) 360 { 361 TestLog& log = m_testCtx.getLog(); 362 363 log << TestLog::Message << "Fail, config does not actually support creation of any surface type?" << TestLog::EndMessage; 364 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 365 } 366 } 367 368 void checkAttribute (EGLenum attrib, EGLint value) 369 { 370 switch (attrib) 371 { 372 case EGL_COLOR_BUFFER_TYPE: 373 checkColorBufferType(value); 374 break; 375 case EGL_CONFIG_CAVEAT: 376 checkCaveat(value); 377 break; 378 case EGL_TRANSPARENT_TYPE: 379 checkTransparentType(value); 380 break; 381 case EGL_CONFORMANT: 382 case EGL_RENDERABLE_TYPE: 383 // Just print what we know 384 break; 385 case EGL_SURFACE_TYPE: 386 checkSurfaceTypeMask(value); 387 break; 388 case EGL_BIND_TO_TEXTURE_RGB: 389 case EGL_BIND_TO_TEXTURE_RGBA: 390 case EGL_NATIVE_RENDERABLE: 391 checkBoolean(attrib, value); 392 break; 393 default: 394 checkInteger(attrib, value); 395 } 396 } 397 398 void executeTest (EGLConfig config) 399 { 400 TestLog& log = m_testCtx.getLog(); 401 eglu::Version version = eglu::getVersion(m_eglTestCtx.getLibrary(), m_display); 402 403 if (!isAttributePresent(version, m_attrib)) 404 { 405 log << TestLog::Message << eglu::getConfigAttribStr(m_attrib) << " not supported by this EGL version"; 406 } 407 else 408 { 409 EGLint value; 410 411 enableLogging(true); 412 413 eglGetConfigAttrib(m_display, config, m_attrib, &value); 414 eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); 415 416 logConfigAttribute(log, m_attrib, value); 417 checkAttribute(m_attrib, value); 418 419 enableLogging(false); 420 } 421 } 422 423private: 424 EGLenum m_attrib; 425}; 426 427class GetConfigAttribBufferSizeCase : public GetConfigAttribCase 428{ 429public: 430 GetConfigAttribBufferSizeCase (EglTestContext& eglTestCtx, const char* name, const char* description) 431 : GetConfigAttribCase(eglTestCtx, name, description) 432 { 433 } 434 435 void executeTest (EGLConfig config) 436 { 437 TestLog& log = m_testCtx.getLog(); 438 439 const EGLint colorBufferType = getValue(config, EGL_COLOR_BUFFER_TYPE); 440 441 const EGLint bufferSize = getValue(config, EGL_BUFFER_SIZE); 442 const EGLint redSize = getValue(config, EGL_RED_SIZE); 443 const EGLint greenSize = getValue(config, EGL_GREEN_SIZE); 444 const EGLint blueSize = getValue(config, EGL_BLUE_SIZE); 445 const EGLint luminanceSize = getValue(config, EGL_LUMINANCE_SIZE); 446 const EGLint alphaSize = getValue(config, EGL_ALPHA_SIZE); 447 448 if (alphaSize < 0) 449 { 450 log << TestLog::Message << "Fail, alpha size must be zero or positive." << TestLog::EndMessage; 451 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid alpha size"); 452 } 453 454 if (colorBufferType == EGL_RGB_BUFFER) 455 { 456 if (luminanceSize != 0) 457 { 458 log << TestLog::Message << "Fail, luminance size must be zero for an RGB buffer." << TestLog::EndMessage; 459 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid luminance size"); 460 } 461 462 if (redSize <= 0 || greenSize <= 0 || blueSize <= 0) 463 { 464 log << TestLog::Message << "Fail, RGB component sizes must be positive for an RGB buffer." << TestLog::EndMessage; 465 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid color component size"); 466 } 467 468 if (bufferSize != (redSize + greenSize + blueSize + alphaSize)) 469 { 470 log << TestLog::Message << "Fail, buffer size must be equal to the sum of RGB component sizes and alpha size." << TestLog::EndMessage; 471 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid buffer size"); 472 } 473 } 474 else if (colorBufferType == EGL_LUMINANCE_BUFFER) 475 { 476 if (luminanceSize <= 0) 477 { 478 log << TestLog::Message << "Fail, luminance size must be positive for a luminance buffer." << TestLog::EndMessage; 479 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid luminance size"); 480 } 481 482 if (redSize != 0 || greenSize != 0 || blueSize != 0) 483 { 484 log << TestLog::Message << "Fail, RGB component sizes must be zero for a luminance buffer." << TestLog::EndMessage; 485 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid color component size"); 486 } 487 488 if (bufferSize != (luminanceSize + alphaSize)) 489 { 490 log << TestLog::Message << "Fail, buffer size must be equal to the sum of luminance size and alpha size." << TestLog::EndMessage; 491 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid buffer size"); 492 } 493 } 494 } 495}; 496 497class GetConfigAttribTransparentValueCase : public GetConfigAttribCase 498{ 499public: 500 GetConfigAttribTransparentValueCase (EglTestContext& eglTestCtx, const char* name, const char* description) 501 : GetConfigAttribCase(eglTestCtx, name, description) 502 { 503 } 504 505 void executeTest (EGLConfig config) 506 { 507 TestLog& log = m_testCtx.getLog(); 508 509 const EGLint transparentType = getValue(config, EGL_TRANSPARENT_TYPE); 510 const EGLint redValue = getValue(config, EGL_TRANSPARENT_RED_VALUE); 511 const EGLint greenValue = getValue(config, EGL_TRANSPARENT_GREEN_VALUE); 512 const EGLint blueValue = getValue(config, EGL_TRANSPARENT_BLUE_VALUE); 513 514 const EGLint redSize = getValue(config, EGL_RED_SIZE); 515 const EGLint greenSize = getValue(config, EGL_GREEN_SIZE); 516 const EGLint blueSize = getValue(config, EGL_BLUE_SIZE); 517 518 if (transparentType == EGL_TRANSPARENT_RGB) 519 { 520 if ( (redValue < 0 || redValue >= (1 << redSize)) 521 || (greenValue < 0 || greenValue >= (1 << greenSize)) 522 || (blueValue < 0 || blueValue >= (1 << blueSize)) ) 523 { 524 log << TestLog::Message << "Fail, transparent color values must lie between 0 and the maximum component value." << TestLog::EndMessage; 525 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid transparent color value"); 526 } 527 } 528 } 529}; 530 531QueryConfigTests::QueryConfigTests (EglTestContext& eglTestCtx) 532 : TestCaseGroup(eglTestCtx, "query_config", "Surface config query tests") 533{ 534} 535 536QueryConfigTests::~QueryConfigTests (void) 537{ 538} 539 540void QueryConfigTests::init (void) 541{ 542 // eglGetGonfigs 543 { 544 tcu::TestCaseGroup* getConfigsGroup = new tcu::TestCaseGroup(m_testCtx, "get_configs", "eglGetConfigs tests"); 545 addChild(getConfigsGroup); 546 547 getConfigsGroup->addChild(new GetConfigsBoundsCase(m_eglTestCtx, "get_configs_bounds", "eglGetConfigs bounds checking test")); 548 } 549 550 // eglGetConfigAttrib 551 { 552 static const struct 553 { 554 EGLenum attribute; 555 const char* testName; 556 } attributes[] = 557 { 558 { EGL_BUFFER_SIZE, "buffer_size" }, 559 { EGL_RED_SIZE, "red_size" }, 560 { EGL_GREEN_SIZE, "green_size" }, 561 { EGL_BLUE_SIZE, "blue_size" }, 562 { EGL_LUMINANCE_SIZE, "luminance_size" }, 563 { EGL_ALPHA_SIZE, "alpha_size" }, 564 { EGL_ALPHA_MASK_SIZE, "alpha_mask_size" }, 565 { EGL_BIND_TO_TEXTURE_RGB, "bind_to_texture_rgb" }, 566 { EGL_BIND_TO_TEXTURE_RGBA, "bind_to_texture_rgba" }, 567 { EGL_COLOR_BUFFER_TYPE, "color_buffer_type" }, 568 { EGL_CONFIG_CAVEAT, "config_caveat" }, 569 { EGL_CONFIG_ID, "config_id" }, 570 { EGL_CONFORMANT, "conformant" }, 571 { EGL_DEPTH_SIZE, "depth_size" }, 572 { EGL_LEVEL, "level" }, 573 { EGL_MAX_SWAP_INTERVAL, "max_swap_interval" }, 574 { EGL_MIN_SWAP_INTERVAL, "min_swap_interval" }, 575 { EGL_NATIVE_RENDERABLE, "native_renderable" }, 576 { EGL_NATIVE_VISUAL_TYPE, "native_visual_type" }, 577 { EGL_RENDERABLE_TYPE, "renderable_type" }, 578 { EGL_SAMPLE_BUFFERS, "sample_buffers" }, 579 { EGL_SAMPLES, "samples" }, 580 { EGL_STENCIL_SIZE, "stencil_size" }, 581 { EGL_SURFACE_TYPE, "surface_type" }, 582 { EGL_TRANSPARENT_TYPE, "transparent_type" }, 583 { EGL_TRANSPARENT_RED_VALUE, "transparent_red_value" }, 584 { EGL_TRANSPARENT_GREEN_VALUE, "transparent_green_value" }, 585 { EGL_TRANSPARENT_BLUE_VALUE, "transparent_blue_value" } 586 }; 587 588 tcu::TestCaseGroup* simpleGroup = new tcu::TestCaseGroup(m_testCtx, "get_config_attrib", "eglGetConfigAttrib() tests"); 589 addChild(simpleGroup); 590 591 for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(attributes); ndx++) 592 { 593 simpleGroup->addChild(new GetConfigAttribSimpleCase(m_eglTestCtx, attributes[ndx].testName, "Simple attribute query case", attributes[ndx].attribute)); 594 } 595 } 596 597 // Attribute constraints 598 { 599 tcu::TestCaseGroup* constraintsGroup = new tcu::TestCaseGroup(m_testCtx, "constraints", "Attribute constraint tests"); 600 addChild(constraintsGroup); 601 602 constraintsGroup->addChild(new GetConfigAttribBufferSizeCase(m_eglTestCtx, "color_buffer_size", "Color buffer component sizes")); 603 constraintsGroup->addChild(new GetConfigAttribTransparentValueCase(m_eglTestCtx, "transparent_value", "Transparent color value")); 604 } 605} 606 607} // egl 608} // deqp 609