1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 Google Inc. 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief CTS runner. 23 */ /*-------------------------------------------------------------------*/ 24 25 #include "glcTestRunner.hpp" 26 #include "deFilePath.hpp" 27 #include "deStringUtil.hpp" 28 #include "deUniquePtr.hpp" 29 #include "glcConfigList.hpp" 30 #include "qpXmlWriter.h" 31 #include "tcuApp.hpp" 32 #include "tcuCommandLine.hpp" 33 #include "tcuTestLog.hpp" 34 #include "tcuTestSessionExecutor.hpp" 35 36 #include <iterator> 37 38 namespace glcts 39 { 40 41 using std::vector; 42 using std::string; 43 44 // RunSession 45 46 class RunSession 47 { 48 public: 49 RunSession(tcu::Platform& platform, tcu::Archive& archive, const int numArgs, const char* const* args) 50 : m_cmdLine(numArgs, args) 51 , m_log(m_cmdLine.getLogFileName(), m_cmdLine.getLogFlags()) 52 , m_app(platform, archive, m_log, m_cmdLine) 53 { 54 } 55 56 inline bool iterate(void) 57 { 58 return m_app.iterate(); 59 } 60 61 inline const tcu::TestRunStatus& getResult(void) const 62 { 63 return m_app.getResult(); 64 } 65 66 private: 67 tcu::CommandLine m_cmdLine; 68 tcu::TestLog m_log; 69 tcu::App m_app; 70 }; 71 72 static void appendConfigArgs(const Config& config, std::vector<std::string>& args, const char* fboConfig) 73 { 74 if (fboConfig != NULL) 75 { 76 args.push_back(string("--deqp-gl-config-name=") + fboConfig); 77 args.push_back("--deqp-surface-type=fbo"); 78 } 79 80 if (config.type != CONFIGTYPE_DEFAULT) 81 { 82 // \todo [2013-05-06 pyry] Test all surface types for some configs? 83 if (fboConfig == NULL) 84 { 85 if (config.surfaceTypes & SURFACETYPE_WINDOW) 86 args.push_back("--deqp-surface-type=window"); 87 else if (config.surfaceTypes & SURFACETYPE_PBUFFER) 88 args.push_back("--deqp-surface-type=pbuffer"); 89 else if (config.surfaceTypes & SURFACETYPE_PIXMAP) 90 args.push_back("--deqp-surface-type=pixmap"); 91 } 92 93 args.push_back(string("--deqp-gl-config-id=") + de::toString(config.id)); 94 95 if (config.type == CONFIGTYPE_EGL) 96 args.push_back("--deqp-gl-context-type=egl"); 97 else if (config.type == CONFIGTYPE_WGL) 98 args.push_back("--deqp-gl-context-type=wgl"); 99 } 100 } 101 102 typedef struct configInfo 103 { 104 deInt32 redBits; 105 deInt32 greenBits; 106 deInt32 blueBits; 107 deInt32 alphaBits; 108 deInt32 depthBits; 109 deInt32 stencilBits; 110 deInt32 samples; 111 } configInfo; 112 113 static configInfo parseConfigBitsFromName(const char* configName) 114 { 115 configInfo cfgInfo; 116 static const struct 117 { 118 const char* name; 119 int redBits; 120 int greenBits; 121 int blueBits; 122 int alphaBits; 123 } colorCfgs[] = { 124 { "rgba8888", 8, 8, 8, 8 }, { "rgb565", 5, 6, 5, 0 }, 125 }; 126 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorCfgs); ndx++) 127 { 128 if (!strncmp(configName, colorCfgs[ndx].name, strlen(colorCfgs[ndx].name))) 129 { 130 cfgInfo.redBits = colorCfgs[ndx].redBits; 131 cfgInfo.greenBits = colorCfgs[ndx].greenBits; 132 cfgInfo.blueBits = colorCfgs[ndx].blueBits; 133 cfgInfo.alphaBits = colorCfgs[ndx].alphaBits; 134 135 configName += strlen(colorCfgs[ndx].name); 136 break; 137 } 138 } 139 140 static const struct 141 { 142 const char* name; 143 int depthBits; 144 } depthCfgs[] = { 145 { "d0", 0 }, { "d24", 24 }, 146 }; 147 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthCfgs); ndx++) 148 { 149 if (!strncmp(configName, depthCfgs[ndx].name, strlen(depthCfgs[ndx].name))) 150 { 151 cfgInfo.depthBits = depthCfgs[ndx].depthBits; 152 153 configName += strlen(depthCfgs[ndx].name); 154 break; 155 } 156 } 157 158 static const struct 159 { 160 const char* name; 161 int stencilBits; 162 } stencilCfgs[] = { 163 { "s0", 0 }, { "s8", 8 }, 164 }; 165 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilCfgs); ndx++) 166 { 167 if (!strncmp(configName, stencilCfgs[ndx].name, strlen(stencilCfgs[ndx].name))) 168 { 169 cfgInfo.stencilBits = stencilCfgs[ndx].stencilBits; 170 171 configName += strlen(stencilCfgs[ndx].name); 172 break; 173 } 174 } 175 176 static const struct 177 { 178 const char* name; 179 int samples; 180 } multiSampleCfgs[] = { 181 { "ms0", 0 }, { "ms4", 4 }, 182 }; 183 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(multiSampleCfgs); ndx++) 184 { 185 if (!strncmp(configName, multiSampleCfgs[ndx].name, strlen(multiSampleCfgs[ndx].name))) 186 { 187 cfgInfo.samples = multiSampleCfgs[ndx].samples; 188 189 configName += strlen(multiSampleCfgs[ndx].name); 190 break; 191 } 192 } 193 194 return cfgInfo; 195 } 196 197 static const char* getApiName(glu::ApiType apiType) 198 { 199 if (apiType == glu::ApiType::es(2, 0)) 200 return "gles2"; 201 else if (apiType == glu::ApiType::es(3, 0)) 202 return "gles3"; 203 else if (apiType == glu::ApiType::es(3, 1)) 204 return "gles31"; 205 else if (apiType == glu::ApiType::es(3, 2)) 206 return "gles32"; 207 else if (apiType == glu::ApiType::core(3, 0)) 208 return "gl30"; 209 else if (apiType == glu::ApiType::core(3, 1)) 210 return "gl31"; 211 else if (apiType == glu::ApiType::core(3, 2)) 212 return "gl32"; 213 else if (apiType == glu::ApiType::core(3, 3)) 214 return "gl33"; 215 else if (apiType == glu::ApiType::core(4, 0)) 216 return "gl40"; 217 else if (apiType == glu::ApiType::core(4, 1)) 218 return "gl41"; 219 else if (apiType == glu::ApiType::core(4, 2)) 220 return "gl42"; 221 else if (apiType == glu::ApiType::core(4, 3)) 222 return "gl43"; 223 else if (apiType == glu::ApiType::core(4, 4)) 224 return "gl44"; 225 else if (apiType == glu::ApiType::core(4, 5)) 226 return "gl45"; 227 else if (apiType == glu::ApiType::core(4, 6)) 228 return "gl46"; 229 else 230 throw std::runtime_error("Unknown context type"); 231 } 232 233 static const string getCaseListFileOption(const char* mustpassDir, const char* apiName, const char* mustpassName) 234 { 235 #if DE_OS == DE_OS_ANDROID 236 const string case_list_option = "--deqp-caselist-resource="; 237 #else 238 const string case_list_option = "--deqp-caselist-file="; 239 #endif 240 return case_list_option + mustpassDir + apiName + "-" + mustpassName + ".txt"; 241 } 242 243 static const string getLogFileName(const char* apiName, const char* configName, const int iterId, const int runId, 244 const int width, const int height, const int seed) 245 { 246 string res = string("config-") + apiName + "-" + configName + "-cfg-" + de::toString(iterId) + "-run-" + 247 de::toString(runId) + "-width-" + de::toString(width) + "-height-" + de::toString(height); 248 if (seed != -1) 249 { 250 res += "-seed-" + de::toString(seed); 251 } 252 res += ".qpa"; 253 254 return res; 255 } 256 257 static void getBaseOptions(std::vector<std::string>& args, const char* mustpassDir, const char* apiName, 258 const char* configName, const char* screenRotation, int width, int height) 259 { 260 args.push_back(getCaseListFileOption(mustpassDir, apiName, configName)); 261 args.push_back(string("--deqp-screen-rotation=") + screenRotation); 262 args.push_back(string("--deqp-surface-width=") + de::toString(width)); 263 args.push_back(string("--deqp-surface-height=") + de::toString(height)); 264 args.push_back("--deqp-watchdog=disable"); 265 } 266 267 static bool isGLConfigCompatible(configInfo cfgInfo, const AOSPConfig& config) 268 { 269 return cfgInfo.redBits == config.redBits && cfgInfo.greenBits == config.greenBits && 270 cfgInfo.blueBits == config.blueBits && cfgInfo.alphaBits == config.alphaBits && 271 cfgInfo.depthBits == config.depthBits && cfgInfo.stencilBits == config.stencilBits && 272 cfgInfo.samples == config.samples; 273 } 274 275 static void getTestRunsForAOSPEGL(vector<TestRunParams>& runs, const ConfigList& configs) 276 { 277 #include "glcAospMustpassEgl.hpp" 278 279 for (int i = 0; i < DE_LENGTH_OF_ARRAY(aosp_mustpass_egl_first_cfg); ++i) 280 { 281 configInfo cfgInfo = parseConfigBitsFromName(aosp_mustpass_egl_first_cfg[i].glConfigName); 282 283 vector<AOSPConfig>::const_iterator cfgIter; 284 for (cfgIter = configs.aospConfigs.begin(); cfgIter != configs.aospConfigs.end(); ++cfgIter) 285 { 286 // find first compatible config 287 if ((*cfgIter).type == CONFIGTYPE_EGL && isGLConfigCompatible(cfgInfo, *cfgIter)) 288 { 289 break; 290 } 291 } 292 293 if (cfgIter == configs.aospConfigs.end()) 294 { 295 // No suitable configuration found. Skipping EGL tests 296 continue; 297 } 298 299 const char* apiName = "egl"; 300 301 const int width = aosp_mustpass_egl_first_cfg[i].surfaceWidth; 302 const int height = aosp_mustpass_egl_first_cfg[i].surfaceHeight; 303 304 TestRunParams params; 305 params.logFilename = 306 getLogFileName(apiName, aosp_mustpass_egl_first_cfg[i].configName, 1, i, width, height, -1); 307 getBaseOptions(params.args, mustpassDir, apiName, aosp_mustpass_egl_first_cfg[i].configName, 308 aosp_mustpass_egl_first_cfg[i].screenRotation, width, height); 309 310 params.args.push_back(string("--deqp-gl-config-name=") + string(aosp_mustpass_egl_first_cfg[i].glConfigName)); 311 312 runs.push_back(params); 313 } 314 } 315 316 static void getTestRunsForAOSPES(vector<TestRunParams>& runs, const ConfigList& configs, const glu::ApiType apiType) 317 { 318 #include "glcAospMustpassEs.hpp" 319 320 for (int i = 0; i < DE_LENGTH_OF_ARRAY(aosp_mustpass_es_first_cfg); ++i) 321 { 322 if (!glu::contextSupports(glu::ContextType(apiType), aosp_mustpass_es_first_cfg[i].apiType)) 323 continue; 324 325 configInfo cfgInfo = parseConfigBitsFromName(aosp_mustpass_es_first_cfg[i].glConfigName); 326 327 vector<AOSPConfig>::const_iterator cfgIter; 328 for (cfgIter = configs.aospConfigs.begin(); cfgIter != configs.aospConfigs.end(); ++cfgIter) 329 { 330 // find first compatible config 331 if (isGLConfigCompatible(cfgInfo, *cfgIter)) 332 { 333 break; 334 } 335 } 336 337 if (cfgIter == configs.aospConfigs.end()) 338 { 339 TCU_FAIL(("No suitable configuration found for GL config " + 340 de::toString(aosp_mustpass_es_first_cfg[i].glConfigName)) 341 .c_str()); 342 return; 343 } 344 345 const char* apiName = getApiName(aosp_mustpass_es_first_cfg[i].apiType); 346 347 const int width = aosp_mustpass_es_first_cfg[i].surfaceWidth; 348 const int height = aosp_mustpass_es_first_cfg[i].surfaceHeight; 349 350 TestRunParams params; 351 params.logFilename = getLogFileName(apiName, aosp_mustpass_es_first_cfg[i].configName, 1, i, width, height, -1); 352 getBaseOptions(params.args, mustpassDir, apiName, aosp_mustpass_es_first_cfg[i].configName, 353 aosp_mustpass_es_first_cfg[i].screenRotation, width, height); 354 355 params.args.push_back(string("--deqp-gl-config-name=") + string(aosp_mustpass_es_first_cfg[i].glConfigName)); 356 357 //set surface type 358 if ((*cfgIter).surfaceTypes & SURFACETYPE_WINDOW) 359 params.args.push_back("--deqp-surface-type=window"); 360 else if ((*cfgIter).surfaceTypes & SURFACETYPE_PBUFFER) 361 params.args.push_back("--deqp-surface-type=pbuffer"); 362 else if ((*cfgIter).surfaceTypes & SURFACETYPE_PIXMAP) 363 params.args.push_back("--deqp-surface-type=pixmap"); 364 runs.push_back(params); 365 } 366 } 367 368 static void getTestRunsForNoContext(glu::ApiType type, vector<TestRunParams>& runs, const ConfigList& configs, const RunParams* runParams, 369 const int numRunParams, const char* mustpassDir) 370 { 371 vector<Config>::const_iterator cfgIter = configs.configs.begin(); 372 373 for (int i = 0; i < numRunParams; ++i) 374 { 375 if (!glu::contextSupports(glu::ContextType(type), runParams[i].apiType)) 376 continue; 377 378 const char* apiName = getApiName(runParams[i].apiType); 379 380 const int width = runParams[i].surfaceWidth; 381 const int height = runParams[i].surfaceHeight; 382 const int seed = runParams[i].baseSeed; 383 384 TestRunParams params; 385 params.logFilename = getLogFileName(apiName, runParams[i].configName, 1, i, width, height, seed); 386 387 getBaseOptions(params.args, mustpassDir, apiName, runParams[i].configName, runParams[i].screenRotation, width, 388 height); 389 390 params.args.push_back(string("--deqp-base-seed=") + de::toString(seed)); 391 392 appendConfigArgs(*cfgIter, params.args, runParams[i].fboConfig); 393 394 runs.push_back(params); 395 } 396 } 397 398 static void getTestRunsForNoContextES(glu::ApiType type, vector<TestRunParams>& runs, const ConfigList& configs) 399 { 400 #include "glcKhronosMustpassEsNocontext.hpp" 401 getTestRunsForNoContext(type, runs, configs, khronos_mustpass_es_nocontext_first_cfg, 402 DE_LENGTH_OF_ARRAY(khronos_mustpass_es_nocontext_first_cfg), mustpassDir); 403 } 404 405 static void getTestRunsForES(glu::ApiType type, const ConfigList& configs, vector<TestRunParams>& runs) 406 { 407 getTestRunsForAOSPEGL(runs, configs); 408 getTestRunsForAOSPES(runs, configs, type); 409 getTestRunsForNoContextES(type, runs, configs); 410 411 #include "glcKhronosMustpassEs.hpp" 412 413 for (vector<Config>::const_iterator cfgIter = configs.configs.begin(); cfgIter != configs.configs.end(); ++cfgIter) 414 { 415 const bool isFirst = cfgIter == configs.configs.begin(); 416 const int numRunParams = isFirst ? DE_LENGTH_OF_ARRAY(khronos_mustpass_es_first_cfg) : 417 DE_LENGTH_OF_ARRAY(khronos_mustpass_es_other_cfg); 418 const RunParams* runParams = isFirst ? khronos_mustpass_es_first_cfg : khronos_mustpass_es_other_cfg; 419 420 for (int runNdx = 0; runNdx < numRunParams; runNdx++) 421 { 422 if (!glu::contextSupports(glu::ContextType(type), runParams[runNdx].apiType)) 423 continue; 424 425 const char* apiName = getApiName(runParams[runNdx].apiType); 426 427 const int width = runParams[runNdx].surfaceWidth; 428 const int height = runParams[runNdx].surfaceHeight; 429 const int seed = runParams[runNdx].baseSeed; 430 431 TestRunParams params; 432 433 params.logFilename = 434 getLogFileName(apiName, runParams[runNdx].configName, cfgIter->id, runNdx, width, height, seed); 435 436 getBaseOptions(params.args, mustpassDir, apiName, runParams[runNdx].configName, 437 runParams[runNdx].screenRotation, width, height); 438 params.args.push_back(string("--deqp-base-seed=") + de::toString(seed)); 439 440 appendConfigArgs(*cfgIter, params.args, runParams[runNdx].fboConfig); 441 442 runs.push_back(params); 443 } 444 } 445 } 446 447 static void getTestRunsForNoContextGL(glu::ApiType type, vector<TestRunParams>& runs, const ConfigList& configs) 448 { 449 #include "glcKhronosMustpassGlNocontext.hpp" 450 getTestRunsForNoContext(type, runs, configs, khronos_mustpass_gl_nocontext_first_cfg, 451 DE_LENGTH_OF_ARRAY(khronos_mustpass_gl_nocontext_first_cfg), mustpassDir); 452 } 453 454 static void getTestRunsForGL(glu::ApiType type, const ConfigList& configs, vector<TestRunParams>& runs) 455 { 456 getTestRunsForNoContextGL(type, runs, configs); 457 #include "glcKhronosMustpassGl.hpp" 458 459 for (vector<Config>::const_iterator cfgIter = configs.configs.begin(); cfgIter != configs.configs.end(); ++cfgIter) 460 { 461 const bool isFirst = cfgIter == configs.configs.begin(); 462 const int numRunParams = isFirst ? DE_LENGTH_OF_ARRAY(khronos_mustpass_gl_first_cfg) : 463 DE_LENGTH_OF_ARRAY(khronos_mustpass_gl_other_cfg); 464 const RunParams* runParams = isFirst ? khronos_mustpass_gl_first_cfg : khronos_mustpass_gl_other_cfg; 465 466 for (int runNdx = 0; runNdx < numRunParams; runNdx++) 467 { 468 if (type != runParams[runNdx].apiType) 469 continue; 470 471 const char* apiName = getApiName(runParams[runNdx].apiType); 472 473 const int width = runParams[runNdx].surfaceWidth; 474 const int height = runParams[runNdx].surfaceHeight; 475 const int seed = runParams[runNdx].baseSeed; 476 477 TestRunParams params; 478 479 params.logFilename = 480 getLogFileName(apiName, runParams[runNdx].configName, cfgIter->id, runNdx, width, height, seed); 481 482 getBaseOptions(params.args, mustpassDir, apiName, runParams[runNdx].configName, 483 runParams[runNdx].screenRotation, width, height); 484 params.args.push_back(string("--deqp-base-seed=") + de::toString(seed)); 485 486 appendConfigArgs(*cfgIter, params.args, runParams[runNdx].fboConfig); 487 488 runs.push_back(params); 489 } 490 } 491 } 492 493 static void getTestRunParams(glu::ApiType type, const ConfigList& configs, vector<TestRunParams>& runs) 494 { 495 switch (type.getProfile()) 496 { 497 case glu::PROFILE_CORE: 498 getTestRunsForGL(type, configs, runs); 499 break; 500 case glu::PROFILE_ES: 501 getTestRunsForES(type, configs, runs); 502 break; 503 default: 504 throw std::runtime_error("Unknown context type"); 505 } 506 } 507 508 struct FileDeleter 509 { 510 void operator()(FILE* file) const 511 { 512 if (file) 513 fclose(file); 514 } 515 }; 516 517 struct XmlWriterDeleter 518 { 519 void operator()(qpXmlWriter* writer) const 520 { 521 if (writer) 522 qpXmlWriter_destroy(writer); 523 } 524 }; 525 526 static const char* getRunTypeName(glu::ApiType type) 527 { 528 if (type == glu::ApiType::es(2, 0)) 529 return "es2"; 530 else if (type == glu::ApiType::es(3, 0)) 531 return "es3"; 532 else if (type == glu::ApiType::es(3, 1)) 533 return "es31"; 534 else if (type == glu::ApiType::es(3, 2)) 535 return "es32"; 536 else if (type == glu::ApiType::core(3, 0)) 537 return "gl30"; 538 else if (type == glu::ApiType::core(3, 1)) 539 return "gl31"; 540 else if (type == glu::ApiType::core(3, 2)) 541 return "gl32"; 542 else if (type == glu::ApiType::core(3, 3)) 543 return "gl33"; 544 else if (type == glu::ApiType::core(4, 0)) 545 return "gl40"; 546 else if (type == glu::ApiType::core(4, 1)) 547 return "gl41"; 548 else if (type == glu::ApiType::core(4, 2)) 549 return "gl42"; 550 else if (type == glu::ApiType::core(4, 3)) 551 return "gl43"; 552 else if (type == glu::ApiType::core(4, 4)) 553 return "gl44"; 554 else if (type == glu::ApiType::core(4, 5)) 555 return "gl45"; 556 else if (type == glu::ApiType::core(4, 6)) 557 return "gl46"; 558 else 559 return DE_NULL; 560 } 561 562 #define XML_CHECK(X) \ 563 if (!(X)) \ 564 throw tcu::Exception("Writing XML failed") 565 566 static void writeRunSummary(const TestRunSummary& summary, const char* filename) 567 { 568 de::UniquePtr<FILE, FileDeleter> out(fopen(filename, "wb")); 569 if (!out) 570 throw tcu::Exception(string("Failed to open ") + filename); 571 572 de::UniquePtr<qpXmlWriter, XmlWriterDeleter> writer(qpXmlWriter_createFileWriter(out.get(), DE_FALSE, DE_FALSE)); 573 if (!writer) 574 throw std::bad_alloc(); 575 576 XML_CHECK(qpXmlWriter_startDocument(writer.get())); 577 578 { 579 qpXmlAttribute attribs[2]; 580 581 attribs[0] = qpSetStringAttrib("Type", getRunTypeName(summary.runType)); 582 attribs[1] = qpSetBoolAttrib("Conformant", summary.isConformant ? DE_TRUE : DE_FALSE); 583 584 XML_CHECK(qpXmlWriter_startElement(writer.get(), "Summary", DE_LENGTH_OF_ARRAY(attribs), attribs)); 585 } 586 587 // Config run 588 { 589 qpXmlAttribute attribs[1]; 590 attribs[0] = qpSetStringAttrib("FileName", summary.configLogFilename.c_str()); 591 XML_CHECK(qpXmlWriter_startElement(writer.get(), "Configs", DE_LENGTH_OF_ARRAY(attribs), attribs) && 592 qpXmlWriter_endElement(writer.get(), "Configs")); 593 } 594 595 // Record test run parameters (log filename & command line). 596 for (vector<TestRunParams>::const_iterator runIter = summary.runParams.begin(); runIter != summary.runParams.end(); 597 ++runIter) 598 { 599 string cmdLine; 600 qpXmlAttribute attribs[2]; 601 602 for (vector<string>::const_iterator argIter = runIter->args.begin(); argIter != runIter->args.end(); ++argIter) 603 { 604 if (argIter != runIter->args.begin()) 605 cmdLine += " "; 606 cmdLine += *argIter; 607 } 608 609 attribs[0] = qpSetStringAttrib("FileName", runIter->logFilename.c_str()); 610 attribs[1] = qpSetStringAttrib("CmdLine", cmdLine.c_str()); 611 612 XML_CHECK(qpXmlWriter_startElement(writer.get(), "TestRun", DE_LENGTH_OF_ARRAY(attribs), attribs) && 613 qpXmlWriter_endElement(writer.get(), "TestRun")); 614 } 615 616 XML_CHECK(qpXmlWriter_endElement(writer.get(), "Summary")); 617 XML_CHECK(qpXmlWriter_endDocument(writer.get())); 618 } 619 620 #undef XML_CHECK 621 622 TestRunner::TestRunner(tcu::Platform& platform, tcu::Archive& archive, const char* logDirPath, glu::ApiType type, 623 deUint32 flags) 624 : m_platform(platform) 625 , m_archive(archive) 626 , m_logDirPath(logDirPath) 627 , m_type(type) 628 , m_flags(flags) 629 , m_iterState(ITERATE_INIT) 630 , m_curSession(DE_NULL) 631 , m_sessionsExecuted(0) 632 , m_sessionsPassed(0) 633 , m_sessionsFailed(0) 634 { 635 } 636 637 TestRunner::~TestRunner(void) 638 { 639 delete m_curSession; 640 } 641 642 bool TestRunner::iterate(void) 643 { 644 switch (m_iterState) 645 { 646 case ITERATE_INIT: 647 init(); 648 m_iterState = (m_sessionIter != m_runSessions.end()) ? ITERATE_INIT_SESSION : ITERATE_DEINIT; 649 return true; 650 651 case ITERATE_DEINIT: 652 deinit(); 653 m_iterState = ITERATE_INIT; 654 return false; 655 656 case ITERATE_INIT_SESSION: 657 DE_ASSERT(m_sessionIter != m_runSessions.end()); 658 initSession(*m_sessionIter); 659 if (m_flags & PRINT_SUMMARY) 660 m_iterState = ITERATE_DEINIT_SESSION; 661 else 662 m_iterState = ITERATE_ITERATE_SESSION; 663 return true; 664 665 case ITERATE_DEINIT_SESSION: 666 deinitSession(); 667 ++m_sessionIter; 668 m_iterState = (m_sessionIter != m_runSessions.end()) ? ITERATE_INIT_SESSION : ITERATE_DEINIT; 669 return true; 670 671 case ITERATE_ITERATE_SESSION: 672 if (!iterateSession()) 673 m_iterState = ITERATE_DEINIT_SESSION; 674 return true; 675 676 default: 677 DE_ASSERT(false); 678 return false; 679 } 680 } 681 682 void TestRunner::init(void) 683 { 684 DE_ASSERT(m_runSessions.empty() && m_summary.runParams.empty()); 685 686 tcu::print("Running %s conformance\n", glu::getApiTypeDescription(m_type)); 687 688 m_summary.runType = m_type; 689 690 // Get list of configs to test. 691 ConfigList configList; 692 getDefaultConfigList(m_platform, m_type, configList); 693 694 tcu::print(" found %d compatible and %d excluded configs\n", (int)configList.configs.size(), 695 (int)configList.excludedConfigs.size()); 696 697 // Config list run. 698 { 699 const char* configLogFilename = "configs.qpa"; 700 TestRunParams configRun; 701 702 configRun.logFilename = configLogFilename; 703 configRun.args.push_back("--deqp-case=CTS-Configs.*"); 704 m_runSessions.push_back(configRun); 705 706 m_summary.configLogFilename = configLogFilename; 707 } 708 709 // Conformance test type specific runs 710 getTestRunParams(m_type, configList, m_runSessions); 711 712 // Record run params for summary. 713 for (std::vector<TestRunParams>::const_iterator runIter = m_runSessions.begin() + 1; runIter != m_runSessions.end(); 714 ++runIter) 715 m_summary.runParams.push_back(*runIter); 716 717 // Session iterator 718 m_sessionIter = m_runSessions.begin(); 719 } 720 721 void TestRunner::deinit(void) 722 { 723 // Print out totals. 724 bool isConformant = m_sessionsExecuted == m_sessionsPassed; 725 DE_ASSERT(m_sessionsExecuted == m_sessionsPassed + m_sessionsFailed); 726 tcu::print("\n%d/%d sessions passed, conformance test %s\n", m_sessionsPassed, m_sessionsExecuted, 727 isConformant ? "PASSED" : "FAILED"); 728 729 m_summary.isConformant = isConformant; 730 731 // Write out summary. 732 writeRunSummary(m_summary, de::FilePath::join(m_logDirPath, "cts-run-summary.xml").getPath()); 733 734 m_runSessions.clear(); 735 m_summary.clear(); 736 } 737 738 void TestRunner::initSession(const TestRunParams& runParams) 739 { 740 DE_ASSERT(!m_curSession); 741 742 tcu::print("\n Test run %d / %d\n", (int)(m_sessionIter - m_runSessions.begin() + 1), (int)m_runSessions.size()); 743 744 // Compute final args for run. 745 vector<string> args(runParams.args); 746 args.push_back(string("--deqp-log-filename=") + de::FilePath::join(m_logDirPath, runParams.logFilename).getPath()); 747 748 if (!(m_flags & VERBOSE_IMAGES)) 749 args.push_back("--deqp-log-images=disable"); 750 751 if (!(m_flags & VERBOSE_SHADERS)) 752 args.push_back("--deqp-log-shader-sources=disable"); 753 754 std::ostringstream ostr; 755 std::ostream_iterator<string> out_it(ostr, ", "); 756 std::copy(args.begin(), args.end(), out_it); 757 tcu::print("\n Config: %s \n\n", ostr.str().c_str()); 758 759 // Translate to argc, argv 760 vector<const char*> argv; 761 argv.push_back("cts-runner"); // Dummy binary name 762 for (vector<string>::const_iterator i = args.begin(); i != args.end(); i++) 763 argv.push_back(i->c_str()); 764 765 // Create session 766 m_curSession = new RunSession(m_platform, m_archive, (int)argv.size(), &argv[0]); 767 } 768 769 void TestRunner::deinitSession(void) 770 { 771 DE_ASSERT(m_curSession); 772 773 // Collect results. 774 // \note NotSupported is treated as pass. 775 const tcu::TestRunStatus& result = m_curSession->getResult(); 776 bool isOk = 777 result.numExecuted == (result.numPassed + result.numNotSupported + result.numWarnings) && result.isComplete; 778 779 DE_ASSERT(result.numExecuted == result.numPassed + result.numFailed + result.numNotSupported + result.numWarnings); 780 781 m_sessionsExecuted += 1; 782 (isOk ? m_sessionsPassed : m_sessionsFailed) += 1; 783 784 delete m_curSession; 785 m_curSession = DE_NULL; 786 } 787 788 inline bool TestRunner::iterateSession(void) 789 { 790 return m_curSession->iterate(); 791 } 792 793 } // glcts 794