1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 Drawing tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fDrawTests.hpp" 25 #include "deRandom.hpp" 26 #include "deStringUtil.hpp" 27 #include "deMemory.h" 28 #include "tcuRenderTarget.hpp" 29 #include "tcuVectorUtil.hpp" 30 #include "sglrGLContext.hpp" 31 #include "glsDrawTest.hpp" 32 #include "gluStrUtil.hpp" 33 #include "gluPixelTransfer.hpp" 34 #include "gluCallLogWrapper.hpp" 35 36 #include "glwEnums.hpp" 37 #include "glwFunctions.hpp" 38 39 #include <set> 40 41 namespace deqp 42 { 43 namespace gles31 44 { 45 namespace Functional 46 { 47 namespace 48 { 49 50 enum TestIterationType 51 { 52 TYPE_DRAW_COUNT, // !< test with 1, 5, and 25 primitives 53 TYPE_INSTANCE_COUNT, // !< test with 1, 4, and 11 instances 54 55 TYPE_LAST 56 }; 57 58 static const char* s_commonVertexShaderSource = "#version 310 es\n" 59 "in highp vec4 a_position;\n" 60 "void main (void)\n" 61 "{\n" 62 " gl_Position = a_position;\n" 63 "}\n"; 64 static const char* s_commonFragmentShaderSource = "#version 310 es\n" 65 "layout(location = 0) out highp vec4 fragColor;\n" 66 "void main (void)\n" 67 "{\n" 68 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 69 "}\n"; 70 71 static const char* s_colorVertexShaderSource = "#version 310 es\n" 72 "in highp vec4 a_position;\n" 73 "in highp vec4 a_color;\n" 74 "out highp vec4 v_color;\n" 75 "void main (void)\n" 76 "{\n" 77 " gl_Position = a_position;\n" 78 " v_color = a_color;\n" 79 "}\n"; 80 static const char* s_colorFragmentShaderSource = "#version 310 es\n" 81 "layout(location = 0) out highp vec4 fragColor;\n" 82 "in highp vec4 v_color;\n" 83 "void main (void)\n" 84 "{\n" 85 " fragColor = v_color;\n" 86 "}\n"; 87 struct DrawElementsCommand 88 { 89 deUint32 count; 90 deUint32 primCount; 91 deUint32 firstIndex; 92 deInt32 baseVertex; 93 deUint32 reservedMustBeZero; 94 }; 95 DE_STATIC_ASSERT(5 * sizeof(deUint32) == sizeof(DrawElementsCommand)); // tight packing 96 97 struct DrawArraysCommand 98 { 99 deUint32 count; 100 deUint32 primCount; 101 deUint32 first; 102 deUint32 reservedMustBeZero; 103 }; 104 DE_STATIC_ASSERT(4 * sizeof(deUint32) == sizeof(DrawArraysCommand)); // tight packing 105 106 // Verifies image contains only yellow or greeen, or a linear combination 107 // of these colors. 108 static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log) 109 { 110 using tcu::TestLog; 111 112 const tcu::RGBA green (0, 255, 0, 255); 113 const tcu::RGBA yellow (255, 255, 0, 255); 114 const int colorThreshold = 20; 115 116 tcu::Surface error (image.getWidth(), image.getHeight()); 117 bool isOk = true; 118 119 for (int y = 0; y < image.getHeight(); y++) 120 for (int x = 0; x < image.getWidth(); x++) 121 { 122 const tcu::RGBA pixel = image.getPixel(x, y); 123 bool pixelOk = true; 124 125 // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow) 126 if (de::abs(pixel.getGreen() - 255) > colorThreshold) 127 pixelOk = false; 128 129 // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow) 130 if (de::abs(pixel.getBlue() - 0) > colorThreshold) 131 pixelOk = false; 132 133 error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255))); 134 isOk = isOk && pixelOk; 135 } 136 137 if (!isOk) 138 { 139 log << TestLog::Message << "Image verification failed." << TestLog::EndMessage; 140 log << TestLog::ImageSet("Verfication result", "Result of rendering") 141 << TestLog::Image("Result", "Result", image) 142 << TestLog::Image("ErrorMask", "Error mask", error) 143 << TestLog::EndImageSet; 144 } 145 else 146 { 147 log << TestLog::ImageSet("Verfication result", "Result of rendering") 148 << TestLog::Image("Result", "Result", image) 149 << TestLog::EndImageSet; 150 } 151 152 return isOk; 153 } 154 155 static void addTestIterations (gls::DrawTest* test, gls::DrawTestSpec& spec, TestIterationType type) 156 { 157 if (type == TYPE_DRAW_COUNT) 158 { 159 spec.primitiveCount = 1; 160 test->addIteration(spec, "draw count = 1"); 161 162 spec.primitiveCount = 5; 163 test->addIteration(spec, "draw count = 5"); 164 165 spec.primitiveCount = 25; 166 test->addIteration(spec, "draw count = 25"); 167 } 168 else if (type == TYPE_INSTANCE_COUNT) 169 { 170 spec.instanceCount = 1; 171 test->addIteration(spec, "instance count = 1"); 172 173 spec.instanceCount = 4; 174 test->addIteration(spec, "instance count = 4"); 175 176 spec.instanceCount = 11; 177 test->addIteration(spec, "instance count = 11"); 178 } 179 else 180 DE_ASSERT(false); 181 } 182 183 static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method) 184 { 185 spec.apiType = glu::ApiType::es(3,1); 186 spec.primitive = gls::DrawTestSpec::PRIMITIVE_TRIANGLES; 187 spec.primitiveCount = 5; 188 spec.drawMethod = method; 189 spec.indexType = gls::DrawTestSpec::INDEXTYPE_LAST; 190 spec.indexPointerOffset = 0; 191 spec.indexStorage = gls::DrawTestSpec::STORAGE_LAST; 192 spec.first = 0; 193 spec.indexMin = 0; 194 spec.indexMax = 0; 195 spec.instanceCount = 1; 196 spec.indirectOffset = 0; 197 198 spec.attribs.resize(2); 199 200 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 201 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 202 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 203 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 204 spec.attribs[0].componentCount = 4; 205 spec.attribs[0].offset = 0; 206 spec.attribs[0].stride = 0; 207 spec.attribs[0].normalize = false; 208 spec.attribs[0].instanceDivisor = 0; 209 spec.attribs[0].useDefaultAttribute = false; 210 211 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 212 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 213 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; 214 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 215 spec.attribs[1].componentCount = 2; 216 spec.attribs[1].offset = 0; 217 spec.attribs[1].stride = 0; 218 spec.attribs[1].normalize = false; 219 spec.attribs[1].instanceDivisor = 0; 220 spec.attribs[1].useDefaultAttribute = false; 221 } 222 223 static std::string sizeToString (int size) 224 { 225 if (size < 1024) 226 return de::toString(size) + " byte(s)"; 227 if (size < 1024*1024) 228 return de::toString(size / 1024) + " KB"; 229 return de::toString(size / 1024 / 1024) + " MB"; 230 } 231 232 class AttributeGroup : public TestCaseGroup 233 { 234 public: 235 AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage); 236 ~AttributeGroup (void); 237 238 void init (void); 239 240 private: 241 gls::DrawTestSpec::DrawMethod m_method; 242 gls::DrawTestSpec::Primitive m_primitive; 243 gls::DrawTestSpec::IndexType m_indexType; 244 gls::DrawTestSpec::Storage m_indexStorage; 245 }; 246 247 AttributeGroup::AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage) 248 : TestCaseGroup (context, name, descr) 249 , m_method (drawMethod) 250 , m_primitive (primitive) 251 , m_indexType (indexType) 252 , m_indexStorage (indexStorage) 253 { 254 } 255 256 AttributeGroup::~AttributeGroup (void) 257 { 258 } 259 260 void AttributeGroup::init (void) 261 { 262 // Single attribute 263 { 264 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array."); 265 gls::DrawTestSpec spec; 266 267 spec.apiType = glu::ApiType::es(3,1); 268 spec.primitive = m_primitive; 269 spec.primitiveCount = 5; 270 spec.drawMethod = m_method; 271 spec.indexType = m_indexType; 272 spec.indexPointerOffset = 0; 273 spec.indexStorage = m_indexStorage; 274 spec.first = 0; 275 spec.indexMin = 0; 276 spec.indexMax = 0; 277 spec.instanceCount = 1; 278 spec.indirectOffset = 0; 279 280 spec.attribs.resize(1); 281 282 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 283 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 284 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 285 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 286 spec.attribs[0].componentCount = 2; 287 spec.attribs[0].offset = 0; 288 spec.attribs[0].stride = 0; 289 spec.attribs[0].normalize = false; 290 spec.attribs[0].instanceDivisor = 0; 291 spec.attribs[0].useDefaultAttribute = false; 292 293 addTestIterations(test, spec, TYPE_DRAW_COUNT); 294 295 this->addChild(test); 296 } 297 298 // Multiple attribute 299 { 300 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes", "Multiple attribute arrays."); 301 gls::DrawTestSpec spec; 302 303 spec.apiType = glu::ApiType::es(3,1); 304 spec.primitive = m_primitive; 305 spec.primitiveCount = 5; 306 spec.drawMethod = m_method; 307 spec.indexType = m_indexType; 308 spec.indexPointerOffset = 0; 309 spec.indexStorage = m_indexStorage; 310 spec.first = 0; 311 spec.indexMin = 0; 312 spec.indexMax = 0; 313 spec.instanceCount = 1; 314 spec.indirectOffset = 0; 315 316 spec.attribs.resize(2); 317 318 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 319 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 320 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 321 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 322 spec.attribs[0].componentCount = 4; 323 spec.attribs[0].offset = 0; 324 spec.attribs[0].stride = 0; 325 spec.attribs[0].normalize = false; 326 spec.attribs[0].instanceDivisor = 0; 327 spec.attribs[0].useDefaultAttribute = false; 328 329 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 330 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 331 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; 332 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 333 spec.attribs[1].componentCount = 2; 334 spec.attribs[1].offset = 0; 335 spec.attribs[1].stride = 0; 336 spec.attribs[1].normalize = false; 337 spec.attribs[1].instanceDivisor = 0; 338 spec.attribs[1].useDefaultAttribute = false; 339 340 addTestIterations(test, spec, TYPE_DRAW_COUNT); 341 342 this->addChild(test); 343 } 344 345 // Multiple attribute, second one divided 346 { 347 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes", "Instanced attribute array."); 348 gls::DrawTestSpec spec; 349 350 spec.apiType = glu::ApiType::es(3,1); 351 spec.primitive = m_primitive; 352 spec.primitiveCount = 5; 353 spec.drawMethod = m_method; 354 spec.indexType = m_indexType; 355 spec.indexPointerOffset = 0; 356 spec.indexStorage = m_indexStorage; 357 spec.first = 0; 358 spec.indexMin = 0; 359 spec.indexMax = 0; 360 spec.instanceCount = 1; 361 spec.indirectOffset = 0; 362 363 spec.attribs.resize(3); 364 365 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 366 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 367 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 368 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 369 spec.attribs[0].componentCount = 4; 370 spec.attribs[0].offset = 0; 371 spec.attribs[0].stride = 0; 372 spec.attribs[0].normalize = false; 373 spec.attribs[0].instanceDivisor = 0; 374 spec.attribs[0].useDefaultAttribute = false; 375 376 // Add another position component so the instances wont be drawn on each other 377 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 378 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 379 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; 380 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 381 spec.attribs[1].componentCount = 2; 382 spec.attribs[1].offset = 0; 383 spec.attribs[1].stride = 0; 384 spec.attribs[1].normalize = false; 385 spec.attribs[1].instanceDivisor = 1; 386 spec.attribs[1].useDefaultAttribute = false; 387 spec.attribs[1].additionalPositionAttribute = true; 388 389 // Instanced color 390 spec.attribs[2].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 391 spec.attribs[2].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 392 spec.attribs[2].storage = gls::DrawTestSpec::STORAGE_BUFFER; 393 spec.attribs[2].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 394 spec.attribs[2].componentCount = 3; 395 spec.attribs[2].offset = 0; 396 spec.attribs[2].stride = 0; 397 spec.attribs[2].normalize = false; 398 spec.attribs[2].instanceDivisor = 1; 399 spec.attribs[2].useDefaultAttribute = false; 400 401 addTestIterations(test, spec, TYPE_INSTANCE_COUNT); 402 403 this->addChild(test); 404 } 405 406 // Multiple attribute, second one default 407 { 408 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute", "Attribute specified with glVertexAttrib*."); 409 gls::DrawTestSpec spec; 410 411 spec.apiType = glu::ApiType::es(3,1); 412 spec.primitive = m_primitive; 413 spec.primitiveCount = 5; 414 spec.drawMethod = m_method; 415 spec.indexType = m_indexType; 416 spec.indexPointerOffset = 0; 417 spec.indexStorage = m_indexStorage; 418 spec.first = 0; 419 spec.indexMin = 0; 420 spec.indexMax = 0; 421 spec.instanceCount = 1; 422 spec.indirectOffset = 0; 423 424 spec.attribs.resize(2); 425 426 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 427 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 428 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 429 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 430 spec.attribs[0].componentCount = 2; 431 spec.attribs[0].offset = 0; 432 spec.attribs[0].stride = 0; 433 spec.attribs[0].normalize = false; 434 spec.attribs[0].instanceDivisor = 0; 435 spec.attribs[0].useDefaultAttribute = false; 436 437 struct IOPair 438 { 439 gls::DrawTestSpec::InputType input; 440 gls::DrawTestSpec::OutputType output; 441 int componentCount; 442 } iopairs[] = 443 { 444 { gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, 4 }, 445 { gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2 }, 446 { gls::DrawTestSpec::INPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4 }, 447 { gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4 }, 448 }; 449 450 for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx) 451 { 452 const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) + de::toString(iopairs[ioNdx].componentCount) + " to " + gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output); 453 454 spec.attribs[1].inputType = iopairs[ioNdx].input; 455 spec.attribs[1].outputType = iopairs[ioNdx].output; 456 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; 457 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 458 spec.attribs[1].componentCount = iopairs[ioNdx].componentCount; 459 spec.attribs[1].offset = 0; 460 spec.attribs[1].stride = 0; 461 spec.attribs[1].normalize = false; 462 spec.attribs[1].instanceDivisor = 0; 463 spec.attribs[1].useDefaultAttribute = true; 464 465 test->addIteration(spec, desc.c_str()); 466 } 467 468 this->addChild(test); 469 } 470 } 471 472 class IndexGroup : public TestCaseGroup 473 { 474 public: 475 IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 476 ~IndexGroup (void); 477 478 void init (void); 479 480 private: 481 gls::DrawTestSpec::DrawMethod m_method; 482 }; 483 484 IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 485 : TestCaseGroup (context, name, descr) 486 , m_method (drawMethod) 487 { 488 } 489 490 IndexGroup::~IndexGroup (void) 491 { 492 } 493 494 void IndexGroup::init (void) 495 { 496 struct IndexTest 497 { 498 gls::DrawTestSpec::IndexType type; 499 int offsets[3]; 500 }; 501 502 const IndexTest tests[] = 503 { 504 { gls::DrawTestSpec::INDEXTYPE_BYTE, { 0, 1, -1 } }, 505 { gls::DrawTestSpec::INDEXTYPE_SHORT, { 0, 2, -1 } }, 506 { gls::DrawTestSpec::INDEXTYPE_INT, { 0, 4, -1 } }, 507 }; 508 509 gls::DrawTestSpec spec; 510 genBasicSpec(spec, m_method); 511 512 spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; 513 514 for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx) 515 { 516 const IndexTest& indexTest = tests[testNdx]; 517 518 const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type); 519 const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type); 520 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()); 521 522 spec.indexType = indexTest.type; 523 524 for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx) 525 { 526 const std::string iterationDesc = std::string("first vertex ") + de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type)); 527 spec.indexPointerOffset = indexTest.offsets[iterationNdx]; 528 test->addIteration(spec, iterationDesc.c_str()); 529 } 530 531 addChild(test); 532 } 533 } 534 535 class BaseVertexGroup : public TestCaseGroup 536 { 537 public: 538 BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 539 ~BaseVertexGroup (void); 540 541 void init (void); 542 543 private: 544 gls::DrawTestSpec::DrawMethod m_method; 545 }; 546 547 BaseVertexGroup::BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 548 : TestCaseGroup (context, name, descr) 549 , m_method (drawMethod) 550 { 551 } 552 553 BaseVertexGroup::~BaseVertexGroup (void) 554 { 555 } 556 557 void BaseVertexGroup::init (void) 558 { 559 struct IndexTest 560 { 561 bool positiveBase; 562 gls::DrawTestSpec::IndexType type; 563 int baseVertex[2]; 564 }; 565 566 const IndexTest tests[] = 567 { 568 { true, gls::DrawTestSpec::INDEXTYPE_BYTE, { 1, 2 } }, 569 { true, gls::DrawTestSpec::INDEXTYPE_SHORT, { 1, 2 } }, 570 { true, gls::DrawTestSpec::INDEXTYPE_INT, { 1, 2 } }, 571 { false, gls::DrawTestSpec::INDEXTYPE_BYTE, { -1, -2 } }, 572 { false, gls::DrawTestSpec::INDEXTYPE_SHORT, { -1, -2 } }, 573 { false, gls::DrawTestSpec::INDEXTYPE_INT, { -1, -2 } }, 574 }; 575 576 gls::DrawTestSpec spec; 577 genBasicSpec(spec, m_method); 578 579 spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; 580 581 for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx) 582 { 583 const IndexTest& indexTest = tests[testNdx]; 584 585 const std::string name = std::string("index_") + (indexTest.positiveBase ? "" : "neg_") + gls::DrawTestSpec::indexTypeToString(indexTest.type); 586 const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type); 587 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()); 588 589 spec.indexType = indexTest.type; 590 591 for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx) 592 { 593 const std::string iterationDesc = std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]); 594 spec.baseVertex = indexTest.baseVertex[iterationNdx]; 595 test->addIteration(spec, iterationDesc.c_str()); 596 } 597 598 addChild(test); 599 } 600 } 601 602 class FirstGroup : public TestCaseGroup 603 { 604 public: 605 FirstGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 606 ~FirstGroup (void); 607 608 void init (void); 609 610 private: 611 gls::DrawTestSpec::DrawMethod m_method; 612 }; 613 614 FirstGroup::FirstGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 615 : TestCaseGroup (context, name, descr) 616 , m_method (drawMethod) 617 { 618 } 619 620 FirstGroup::~FirstGroup (void) 621 { 622 } 623 624 void FirstGroup::init (void) 625 { 626 const int firsts[] = 627 { 628 1, 3, 17 629 }; 630 631 gls::DrawTestSpec spec; 632 genBasicSpec(spec, m_method); 633 634 for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); ++firstNdx) 635 { 636 const std::string name = std::string("first_") + de::toString(firsts[firstNdx]); 637 const std::string desc = std::string("first ") + de::toString(firsts[firstNdx]); 638 gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()); 639 640 spec.first = firsts[firstNdx]; 641 642 addTestIterations(test, spec, TYPE_DRAW_COUNT); 643 644 this->addChild(test); 645 } 646 } 647 648 class MethodGroup : public TestCaseGroup 649 { 650 public: 651 MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 652 ~MethodGroup (void); 653 654 void init (void); 655 656 private: 657 gls::DrawTestSpec::DrawMethod m_method; 658 }; 659 660 MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 661 : TestCaseGroup (context, name, descr) 662 , m_method (drawMethod) 663 { 664 } 665 666 MethodGroup::~MethodGroup (void) 667 { 668 } 669 670 void MethodGroup::init (void) 671 { 672 const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT); 673 const bool hasFirst = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT); 674 675 const gls::DrawTestSpec::Primitive primitive[] = 676 { 677 gls::DrawTestSpec::PRIMITIVE_POINTS, 678 gls::DrawTestSpec::PRIMITIVE_TRIANGLES, 679 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, 680 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP, 681 gls::DrawTestSpec::PRIMITIVE_LINES, 682 gls::DrawTestSpec::PRIMITIVE_LINE_STRIP, 683 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP 684 }; 685 686 if (hasFirst) 687 { 688 // First-tests 689 this->addChild(new FirstGroup(m_context, "first", "First tests", m_method)); 690 } 691 692 if (indexed) 693 { 694 // Index-tests 695 this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method)); 696 this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method)); 697 } 698 699 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx) 700 { 701 const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]); 702 const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]); 703 704 this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx], gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER)); 705 } 706 } 707 708 class GridProgram : public sglr::ShaderProgram 709 { 710 public: 711 GridProgram (void); 712 713 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const; 714 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const; 715 }; 716 717 GridProgram::GridProgram (void) 718 : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration() 719 << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT) 720 << sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT) 721 << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT) 722 << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT) 723 << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT) 724 << sglr::pdec::VertexSource("#version 310 es\n" 725 "in highp vec4 a_position;\n" 726 "in highp vec4 a_offset;\n" 727 "in highp vec4 a_color;\n" 728 "out highp vec4 v_color;\n" 729 "void main(void)\n" 730 "{\n" 731 " gl_Position = a_position + a_offset;\n" 732 " v_color = a_color;\n" 733 "}\n") 734 << sglr::pdec::FragmentSource( 735 "#version 310 es\n" 736 "layout(location = 0) out highp vec4 dEQP_FragColor;\n" 737 "in highp vec4 v_color;\n" 738 "void main(void)\n" 739 "{\n" 740 " dEQP_FragColor = v_color;\n" 741 "}\n")) 742 { 743 } 744 745 void GridProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 746 { 747 for (int ndx = 0; ndx < numPackets; ++ndx) 748 { 749 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) + rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx); 750 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[2], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx); 751 } 752 } 753 754 void GridProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 755 { 756 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 757 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 758 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx)); 759 } 760 761 class InstancedGridRenderTest : public TestCase 762 { 763 public: 764 InstancedGridRenderTest (Context& context, const char* name, const char* desc, int gridSide, bool useIndices); 765 ~InstancedGridRenderTest (void); 766 767 IterateResult iterate (void); 768 769 private: 770 void renderTo (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst); 771 772 const int m_gridSide; 773 const bool m_useIndices; 774 }; 775 776 InstancedGridRenderTest::InstancedGridRenderTest (Context& context, const char* name, const char* desc, int gridSide, bool useIndices) 777 : TestCase (context, name, desc) 778 , m_gridSide (gridSide) 779 , m_useIndices (useIndices) 780 { 781 } 782 783 InstancedGridRenderTest::~InstancedGridRenderTest (void) 784 { 785 } 786 787 InstancedGridRenderTest::IterateResult InstancedGridRenderTest::iterate (void) 788 { 789 const int renderTargetWidth = de::min(1024, m_context.getRenderTarget().getWidth()); 790 const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight()); 791 792 sglr::GLContext ctx (m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight)); 793 tcu::Surface surface (renderTargetWidth, renderTargetHeight); 794 GridProgram program; 795 796 // render 797 798 renderTo(ctx, program, surface); 799 800 // verify image 801 // \note the green/yellow pattern is only for clarity. The test will only verify that all instances were drawn by looking for anything non-green/yellow. 802 if (verifyImageYellowGreen(surface, m_testCtx.getLog())) 803 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 804 else 805 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid"); 806 return STOP; 807 } 808 809 void InstancedGridRenderTest::renderTo (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst) 810 { 811 const tcu::Vec4 green (0, 1, 0, 1); 812 const tcu::Vec4 yellow (1, 1, 0, 1); 813 814 deUint32 vaoID = 0; 815 deUint32 positionBuf = 0; 816 deUint32 offsetBuf = 0; 817 deUint32 colorBuf = 0; 818 deUint32 indexBuf = 0; 819 deUint32 drawIndirectBuf= 0; 820 deUint32 programID = ctx.createProgram(&program); 821 deInt32 posLocation = ctx.getAttribLocation(programID, "a_position"); 822 deInt32 offsetLocation = ctx.getAttribLocation(programID, "a_offset"); 823 deInt32 colorLocation = ctx.getAttribLocation(programID, "a_color"); 824 825 float cellW = 2.0f / m_gridSide; 826 float cellH = 2.0f / m_gridSide; 827 const tcu::Vec4 vertexPositions[] = 828 { 829 tcu::Vec4(0, 0, 0, 1), 830 tcu::Vec4(cellW, 0, 0, 1), 831 tcu::Vec4(0, cellH, 0, 1), 832 833 tcu::Vec4(0, cellH, 0, 1), 834 tcu::Vec4(cellW, 0, 0, 1), 835 tcu::Vec4(cellW, cellH, 0, 1), 836 }; 837 838 const deUint16 indices[] = 839 { 840 0, 4, 3, 841 2, 1, 5 842 }; 843 844 std::vector<tcu::Vec4> offsets; 845 for (int x = 0; x < m_gridSide; ++x) 846 for (int y = 0; y < m_gridSide; ++y) 847 offsets.push_back(tcu::Vec4(x * cellW - 1.0f, y * cellW - 1.0f, 0, 0)); 848 849 std::vector<tcu::Vec4> colors; 850 for (int x = 0; x < m_gridSide; ++x) 851 for (int y = 0; y < m_gridSide; ++y) 852 colors.push_back(((x + y) % 2 == 0) ? (green) : (yellow)); 853 854 ctx.genVertexArrays(1, &vaoID); 855 ctx.bindVertexArray(vaoID); 856 857 ctx.genBuffers(1, &positionBuf); 858 ctx.bindBuffer(GL_ARRAY_BUFFER, positionBuf); 859 ctx.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 860 ctx.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 861 ctx.vertexAttribDivisor(posLocation, 0); 862 ctx.enableVertexAttribArray(posLocation); 863 864 ctx.genBuffers(1, &offsetBuf); 865 ctx.bindBuffer(GL_ARRAY_BUFFER, offsetBuf); 866 ctx.bufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(tcu::Vec4), &offsets[0], GL_STATIC_DRAW); 867 ctx.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 868 ctx.vertexAttribDivisor(offsetLocation, 1); 869 ctx.enableVertexAttribArray(offsetLocation); 870 871 ctx.genBuffers(1, &colorBuf); 872 ctx.bindBuffer(GL_ARRAY_BUFFER, colorBuf); 873 ctx.bufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(tcu::Vec4), &colors[0], GL_STATIC_DRAW); 874 ctx.vertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 875 ctx.vertexAttribDivisor(colorLocation, 1); 876 ctx.enableVertexAttribArray(colorLocation); 877 878 if (m_useIndices) 879 { 880 ctx.genBuffers(1, &indexBuf); 881 ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf); 882 ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 883 } 884 885 ctx.genBuffers(1, &drawIndirectBuf); 886 ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf); 887 888 if (m_useIndices) 889 { 890 DrawElementsCommand command; 891 command.count = 6; 892 command.primCount = m_gridSide * m_gridSide; 893 command.firstIndex = 0; 894 command.baseVertex = 0; 895 command.reservedMustBeZero = 0; 896 897 ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW); 898 } 899 else 900 { 901 DrawArraysCommand command; 902 command.count = 6; 903 command.primCount = m_gridSide * m_gridSide; 904 command.first = 0; 905 command.reservedMustBeZero = 0; 906 907 ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW); 908 } 909 910 ctx.clearColor(0, 0, 0, 1); 911 ctx.clear(GL_COLOR_BUFFER_BIT); 912 913 ctx.viewport(0, 0, dst.getWidth(), dst.getHeight()); 914 915 ctx.useProgram(programID); 916 if (m_useIndices) 917 ctx.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, DE_NULL); 918 else 919 ctx.drawArraysIndirect(GL_TRIANGLES, DE_NULL); 920 ctx.useProgram(0); 921 922 glu::checkError(ctx.getError(), "", __FILE__, __LINE__); 923 924 ctx.deleteBuffers(1, &drawIndirectBuf); 925 if (m_useIndices) 926 ctx.deleteBuffers(1, &indexBuf); 927 ctx.deleteBuffers(1, &colorBuf); 928 ctx.deleteBuffers(1, &offsetBuf); 929 ctx.deleteBuffers(1, &positionBuf); 930 ctx.deleteVertexArrays(1, &vaoID); 931 ctx.deleteProgram(programID); 932 933 ctx.finish(); 934 ctx.readPixels(dst, 0, 0, dst.getWidth(), dst.getHeight()); 935 936 glu::checkError(ctx.getError(), "", __FILE__, __LINE__); 937 } 938 939 class InstancingGroup : public TestCaseGroup 940 { 941 public: 942 InstancingGroup (Context& context, const char* name, const char* descr); 943 ~InstancingGroup (void); 944 945 void init (void); 946 }; 947 948 InstancingGroup::InstancingGroup (Context& context, const char* name, const char* descr) 949 : TestCaseGroup (context, name, descr) 950 { 951 } 952 953 InstancingGroup::~InstancingGroup (void) 954 { 955 } 956 957 void InstancingGroup::init (void) 958 { 959 const int gridWidths[] = 960 { 961 2, 962 5, 963 10, 964 32, 965 100, 966 }; 967 968 // drawArrays 969 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx) 970 { 971 const std::string name = std::string("draw_arrays_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]); 972 const std::string desc = std::string("DrawArraysIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]); 973 974 this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], false)); 975 } 976 977 // drawElements 978 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx) 979 { 980 const std::string name = std::string("draw_elements_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]); 981 const std::string desc = std::string("DrawElementsIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]); 982 983 this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], true)); 984 } 985 } 986 987 class ComputeShaderGeneratedCase : public TestCase 988 { 989 public: 990 enum DrawMethod 991 { 992 DRAWMETHOD_DRAWARRAYS, 993 DRAWMETHOD_DRAWELEMENTS, 994 DRAWMETHOD_LAST 995 }; 996 997 ComputeShaderGeneratedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int drawCallCount); 998 ~ComputeShaderGeneratedCase (void); 999 void init (void); 1000 void deinit (void); 1001 1002 IterateResult iterate (void); 1003 std::string genComputeSource (bool computeCmd, bool computeData, bool computeIndices) const; 1004 1005 private: 1006 void createDrawCommand (void); 1007 void createDrawData (void); 1008 void createDrawIndices (void); 1009 1010 virtual void runComputeShader (void) = 0; 1011 void renderTo (tcu::Surface& image); 1012 1013 protected: 1014 deUint32 calcDrawBufferSize (void) const; 1015 deUint32 calcIndexBufferSize (void) const; 1016 1017 const DrawMethod m_drawMethod; 1018 const bool m_computeCmd; 1019 const bool m_computeData; 1020 const bool m_computeIndices; 1021 const int m_commandSize; 1022 const int m_numDrawCmds; 1023 const int m_gridSize; 1024 1025 glw::GLuint m_cmdBufferID; 1026 glw::GLuint m_dataBufferID; 1027 glw::GLuint m_indexBufferID; 1028 1029 private: 1030 glu::ShaderProgram* m_shaderProgram; 1031 }; 1032 1033 ComputeShaderGeneratedCase::ComputeShaderGeneratedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int drawCallCount) 1034 : TestCase (context, name, desc) 1035 , m_drawMethod (method) 1036 , m_computeCmd (computeCmd) 1037 , m_computeData (computeData) 1038 , m_computeIndices (computeIndices) 1039 , m_commandSize ((method==DRAWMETHOD_DRAWARRAYS) ? (sizeof(DrawArraysCommand)) : (sizeof(DrawElementsCommand))) 1040 , m_numDrawCmds (drawCallCount) 1041 , m_gridSize (gridSize) 1042 , m_cmdBufferID (0) 1043 , m_dataBufferID (0) 1044 , m_indexBufferID (0) 1045 , m_shaderProgram (DE_NULL) 1046 { 1047 const int triangleCount = m_gridSize * m_gridSize * 2; 1048 1049 DE_ASSERT(method < DRAWMETHOD_LAST); 1050 DE_ASSERT(!computeIndices || method == DRAWMETHOD_DRAWELEMENTS); 1051 DE_ASSERT(triangleCount % m_numDrawCmds == 0); 1052 DE_UNREF(triangleCount); 1053 } 1054 1055 ComputeShaderGeneratedCase::~ComputeShaderGeneratedCase (void) 1056 { 1057 deinit(); 1058 } 1059 1060 void ComputeShaderGeneratedCase::init (void) 1061 { 1062 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1063 1064 // generate basic shader 1065 1066 m_shaderProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_colorVertexShaderSource) << glu::FragmentSource(s_colorFragmentShaderSource)); 1067 m_testCtx.getLog() << *m_shaderProgram; 1068 1069 if (!m_shaderProgram->isOk()) 1070 throw tcu::TestError("Failed to compile shader."); 1071 1072 // gen buffers 1073 gl.genBuffers(1, &m_cmdBufferID); 1074 gl.genBuffers(1, &m_dataBufferID); 1075 gl.genBuffers(1, &m_indexBufferID); 1076 1077 // check the SSBO buffers are of legal size 1078 { 1079 const deUint64 drawBufferElementSize = sizeof(tcu::Vec4); 1080 const deUint64 indexBufferElementSize = sizeof(deUint32); 1081 const int commandBufferSize = m_commandSize * m_numDrawCmds; 1082 deInt64 maxSSBOSize = 0; 1083 1084 gl.getInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxSSBOSize); 1085 1086 if (m_computeData && (deUint64)calcDrawBufferSize()*drawBufferElementSize > (deUint64)maxSSBOSize) 1087 throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for vertex attrib buffers"); 1088 if (m_computeIndices && (deUint64)calcIndexBufferSize()*indexBufferElementSize > (deUint64)maxSSBOSize) 1089 throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for index buffers"); 1090 if (m_computeCmd && (deUint64)commandBufferSize > (deUint64)maxSSBOSize) 1091 throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for command buffers"); 1092 } 1093 } 1094 1095 void ComputeShaderGeneratedCase::deinit (void) 1096 { 1097 if (m_cmdBufferID) 1098 { 1099 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_cmdBufferID); 1100 m_cmdBufferID = 0; 1101 } 1102 if (m_dataBufferID) 1103 { 1104 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBufferID); 1105 m_dataBufferID = 0; 1106 } 1107 if (m_indexBufferID) 1108 { 1109 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID); 1110 m_indexBufferID = 0; 1111 } 1112 1113 if (m_shaderProgram) 1114 { 1115 delete m_shaderProgram; 1116 m_shaderProgram = DE_NULL; 1117 } 1118 } 1119 1120 ComputeShaderGeneratedCase::IterateResult ComputeShaderGeneratedCase::iterate (void) 1121 { 1122 const int renderTargetWidth = de::min(1024, m_context.getRenderTarget().getWidth()); 1123 const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight()); 1124 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1125 tcu::Surface surface (renderTargetWidth, renderTargetHeight); 1126 1127 m_testCtx.getLog() << tcu::TestLog::Message << "Preparing to draw " << m_gridSize << " x " << m_gridSize << " grid." << tcu::TestLog::EndMessage; 1128 1129 try 1130 { 1131 // Gen command buffer 1132 if (!m_computeCmd) 1133 { 1134 m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw command buffer." << tcu::TestLog::EndMessage; 1135 createDrawCommand(); 1136 } 1137 1138 // Gen data buffer 1139 if (!m_computeData) 1140 { 1141 m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw data buffer." << tcu::TestLog::EndMessage; 1142 createDrawData(); 1143 } 1144 1145 // Gen index buffer 1146 if (!m_computeIndices && m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1147 { 1148 m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw index buffer." << tcu::TestLog::EndMessage; 1149 createDrawIndices(); 1150 } 1151 1152 // Run compute shader 1153 { 1154 m_testCtx.getLog() 1155 << tcu::TestLog::Message << "Filling following buffers using compute shader:\n" 1156 << ((m_computeCmd) ? ("\tcommand buffer\n") : ("")) 1157 << ((m_computeData) ? ("\tdata buffer\n") : ("")) 1158 << ((m_computeIndices) ? ("\tindex buffer\n") : ("")) 1159 << tcu::TestLog::EndMessage; 1160 runComputeShader(); 1161 } 1162 1163 // Ensure data is written to the buffers before we try to read it 1164 { 1165 const glw::GLuint barriers = ((m_computeCmd) ? (GL_COMMAND_BARRIER_BIT) : (0)) | 1166 ((m_computeData) ? (GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) : (0)) | 1167 ((m_computeIndices) ? (GL_ELEMENT_ARRAY_BARRIER_BIT) : (0)); 1168 1169 m_testCtx.getLog() << tcu::TestLog::Message << "Memory barrier. Barriers = " << glu::getMemoryBarrierFlagsStr(barriers) << tcu::TestLog::EndMessage; 1170 gl.memoryBarrier(barriers); 1171 } 1172 1173 // Draw from buffers 1174 1175 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing from buffers with " << m_numDrawCmds << " draw call(s)." << tcu::TestLog::EndMessage; 1176 renderTo(surface); 1177 } 1178 catch (glu::OutOfMemoryError&) 1179 { 1180 m_testCtx.getLog() << tcu::TestLog::Message << "Got GL_OUT_OF_MEMORY." << tcu::TestLog::EndMessage; 1181 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Got GL_OUT_OF_MEMORY"); 1182 return STOP; 1183 } 1184 1185 1186 // verify image 1187 // \note the green/yellow pattern is only for clarity. The test will only verify that all grid cells were drawn by looking for anything non-green/yellow. 1188 if (verifyImageYellowGreen(surface, m_testCtx.getLog())) 1189 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1190 else 1191 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid"); 1192 return STOP; 1193 } 1194 1195 std::string ComputeShaderGeneratedCase::genComputeSource (bool computeCmd, bool computeData, bool computeIndices) const 1196 { 1197 const int cmdLayoutBinding = 0; 1198 const int dataLayoutBinding = (computeCmd) ? (1) : (0); 1199 const int indexLayoutBinding = (computeCmd && computeData) ? (2) : (computeCmd || computeData) ? (1) : (0); 1200 1201 std::ostringstream buf; 1202 1203 buf << "#version 310 es\n\n" 1204 << "precision highp int;\n" 1205 << "precision highp float;\n\n"; 1206 1207 if (computeCmd && m_drawMethod==DRAWMETHOD_DRAWARRAYS) 1208 buf << "struct DrawArraysIndirectCommand {\n" 1209 << " uint count;\n" 1210 << " uint primCount;\n" 1211 << " uint first;\n" 1212 << " uint reservedMustBeZero;\n" 1213 << "};\n\n"; 1214 else if (computeCmd && m_drawMethod==DRAWMETHOD_DRAWELEMENTS) 1215 buf << "struct DrawElementsIndirectCommand {\n" 1216 << " uint count;\n" 1217 << " uint primCount;\n" 1218 << " uint firstIndex;\n" 1219 << " int baseVertex;\n" 1220 << " uint reservedMustBeZero;\n" 1221 << "};\n\n"; 1222 1223 buf << "layout(local_size_x = 1, local_size_y = 1) in;\n" 1224 << "layout(std430) buffer;\n\n"; 1225 1226 if (computeCmd) 1227 buf << "layout(binding = " << cmdLayoutBinding << ") writeonly buffer CommandBuffer {\n" 1228 << " " << ((m_drawMethod==DRAWMETHOD_DRAWARRAYS) ? ("DrawArraysIndirectCommand") : ("DrawElementsIndirectCommand")) << " commands[];\n" 1229 << "};\n"; 1230 if (computeData) 1231 buf << "layout(binding = " << dataLayoutBinding << ") writeonly buffer DataBuffer {\n" 1232 << " vec4 attribs[];\n" 1233 << "};\n"; 1234 if (computeIndices) 1235 buf << "layout(binding = " << indexLayoutBinding << ") writeonly buffer IndexBuffer {\n" 1236 << " uint indices[];\n" 1237 << "};\n"; 1238 1239 buf << "\n" 1240 << "void main() {\n" 1241 << " const uint gridSize = " << m_gridSize << "u;\n" 1242 << " const uint triangleCount = gridSize * gridSize * 2u;\n" 1243 << "\n"; 1244 1245 if (computeCmd) 1246 { 1247 buf << " // command\n" 1248 << " if (gl_GlobalInvocationID.x < " << m_numDrawCmds << "u && gl_GlobalInvocationID.y == 0u && gl_GlobalInvocationID.z == 0u) {\n" 1249 << " const uint numDrawCallTris = triangleCount / " << m_numDrawCmds << "u;\n" 1250 << " uint firstTri = gl_GlobalInvocationID.x * numDrawCallTris;\n\n" 1251 << " commands[gl_GlobalInvocationID.x].count = numDrawCallTris*3u;\n" 1252 << " commands[gl_GlobalInvocationID.x].primCount = 1u;\n"; 1253 1254 if (m_drawMethod==DRAWMETHOD_DRAWARRAYS) 1255 { 1256 buf << " commands[gl_GlobalInvocationID.x].first = firstTri*3u;\n"; 1257 } 1258 else if (m_drawMethod==DRAWMETHOD_DRAWELEMENTS) 1259 { 1260 buf << " commands[gl_GlobalInvocationID.x].firstIndex = firstTri*3u;\n"; 1261 buf << " commands[gl_GlobalInvocationID.x].baseVertex = 0;\n"; 1262 } 1263 1264 buf << " commands[gl_GlobalInvocationID.x].reservedMustBeZero = 0u;\n" 1265 << " }\n" 1266 << "\n"; 1267 } 1268 1269 if (computeData) 1270 { 1271 buf << " // vertex attribs\n" 1272 << " const vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n" 1273 << " const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"; 1274 1275 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1276 { 1277 buf << " if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n" 1278 << " uint y = gl_GlobalInvocationID.x;\n" 1279 << " uint x = gl_GlobalInvocationID.y;\n" 1280 << " float posX = (float(x) / float(gridSize)) * 2.0 - 1.0;\n" 1281 << " float posY = (float(y) / float(gridSize)) * 2.0 - 1.0;\n" 1282 << " const float cellSize = 2.0 / float(gridSize);\n" 1283 << " vec4 color = ((x + y)%2u != 0u) ? (yellow) : (green);\n" 1284 << "\n" 1285 << " attribs[((y * gridSize + x) * 6u + 0u) * 2u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1286 << " attribs[((y * gridSize + x) * 6u + 1u) * 2u + 0u] = vec4(posX + cellSize, posY, 0.0, 1.0);\n" 1287 << " attribs[((y * gridSize + x) * 6u + 2u) * 2u + 0u] = vec4(posX + cellSize, posY + cellSize, 0.0, 1.0);\n" 1288 << " attribs[((y * gridSize + x) * 6u + 3u) * 2u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1289 << " attribs[((y * gridSize + x) * 6u + 4u) * 2u + 0u] = vec4(posX + cellSize, posY + cellSize, 0.0, 1.0);\n" 1290 << " attribs[((y * gridSize + x) * 6u + 5u) * 2u + 0u] = vec4(posX, posY + cellSize, 0.0, 1.0);\n" 1291 << "\n" 1292 << " attribs[((y * gridSize + x) * 6u + 0u) * 2u + 1u] = color;\n" 1293 << " attribs[((y * gridSize + x) * 6u + 1u) * 2u + 1u] = color;\n" 1294 << " attribs[((y * gridSize + x) * 6u + 2u) * 2u + 1u] = color;\n" 1295 << " attribs[((y * gridSize + x) * 6u + 3u) * 2u + 1u] = color;\n" 1296 << " attribs[((y * gridSize + x) * 6u + 4u) * 2u + 1u] = color;\n" 1297 << " attribs[((y * gridSize + x) * 6u + 5u) * 2u + 1u] = color;\n" 1298 << " }\n"; 1299 } 1300 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1301 { 1302 buf << " if (gl_GlobalInvocationID.x < gridSize+1u && gl_GlobalInvocationID.y < gridSize+1u && gl_GlobalInvocationID.z == 0u) {\n" 1303 << " uint y = gl_GlobalInvocationID.x;\n" 1304 << " uint x = gl_GlobalInvocationID.y;\n" 1305 << " float posX = (float(x) / float(gridSize)) * 2.0 - 1.0;\n" 1306 << " float posY = (float(y) / float(gridSize)) * 2.0 - 1.0;\n" 1307 << "\n" 1308 << " attribs[(y * (gridSize+1u) + x) * 4u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1309 << " attribs[(y * (gridSize+1u) + x) * 4u + 1u] = green;\n" 1310 << " attribs[(y * (gridSize+1u) + x) * 4u + 2u] = vec4(posX, posY, 0.0, 1.0);\n" 1311 << " attribs[(y * (gridSize+1u) + x) * 4u + 3u] = yellow;\n" 1312 << " }\n"; 1313 } 1314 1315 buf << "\n"; 1316 } 1317 1318 if (computeIndices) 1319 { 1320 buf << " // indices\n" 1321 << " if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n" 1322 << " uint y = gl_GlobalInvocationID.x;\n" 1323 << " uint x = gl_GlobalInvocationID.y;\n" 1324 << " uint color = ((x + y)%2u);\n" 1325 << "\n" 1326 << " indices[(y * gridSize + x) * 6u + 0u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1327 << " indices[(y * gridSize + x) * 6u + 1u] = ((y+1u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1328 << " indices[(y * gridSize + x) * 6u + 2u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1329 << " indices[(y * gridSize + x) * 6u + 3u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1330 << " indices[(y * gridSize + x) * 6u + 4u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1331 << " indices[(y * gridSize + x) * 6u + 5u] = ((y+0u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1332 << " }\n" 1333 << "\n"; 1334 } 1335 1336 buf << "}\n"; 1337 1338 return buf.str(); 1339 } 1340 1341 void ComputeShaderGeneratedCase::createDrawCommand (void) 1342 { 1343 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1344 const int triangleCount = m_gridSize * m_gridSize * 2; 1345 const deUint32 numDrawCallTris = triangleCount / m_numDrawCmds; 1346 1347 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1348 { 1349 std::vector<DrawArraysCommand> cmds; 1350 1351 for (int ndx = 0; ndx < m_numDrawCmds; ++ndx) 1352 { 1353 const deUint32 firstTri = ndx * numDrawCallTris; 1354 DrawArraysCommand data; 1355 1356 data.count = numDrawCallTris*3; 1357 data.primCount = 1; 1358 data.first = firstTri*3; 1359 data.reservedMustBeZero = 0; 1360 1361 cmds.push_back(data); 1362 } 1363 1364 DE_ASSERT((int)(sizeof(DrawArraysCommand)*cmds.size()) == m_numDrawCmds * m_commandSize); 1365 1366 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1367 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawArraysCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW); 1368 } 1369 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1370 { 1371 std::vector<DrawElementsCommand> cmds; 1372 1373 for (int ndx = 0; ndx < m_numDrawCmds; ++ndx) 1374 { 1375 const deUint32 firstTri = ndx * numDrawCallTris; 1376 DrawElementsCommand data; 1377 1378 data.count = numDrawCallTris*3; 1379 data.primCount = 1; 1380 data.firstIndex = firstTri*3; 1381 data.baseVertex = 0; 1382 data.reservedMustBeZero = 0; 1383 1384 cmds.push_back(data); 1385 } 1386 1387 DE_ASSERT((int)(sizeof(DrawElementsCommand)*cmds.size()) == m_numDrawCmds * m_commandSize); 1388 1389 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1390 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawElementsCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW); 1391 } 1392 else 1393 DE_ASSERT(false); 1394 1395 glu::checkError(gl.getError(), "create draw command", __FILE__, __LINE__); 1396 } 1397 1398 void ComputeShaderGeneratedCase::createDrawData (void) 1399 { 1400 const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f); 1401 const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); 1402 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1403 1404 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1405 { 1406 // Store elements in the order they are drawn. Interleave color. 1407 std::vector<tcu::Vec4> buffer(m_gridSize*m_gridSize*6*2); 1408 1409 DE_ASSERT(buffer.size() == calcDrawBufferSize()); 1410 1411 for (int y = 0; y < m_gridSize; ++y) 1412 for (int x = 0; x < m_gridSize; ++x) 1413 { 1414 const float posX = (x / (float)m_gridSize) * 2.0f - 1.0f; 1415 const float posY = (y / (float)m_gridSize) * 2.0f - 1.0f; 1416 const float cellSize = 2.0f / (float)m_gridSize; 1417 const tcu::Vec4& color = ((x + y)%2) ? (yellow) : (green); 1418 1419 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1420 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 0] = tcu::Vec4(posX + cellSize, posY, 0.0f, 1.0f); 1421 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f); 1422 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1423 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f); 1424 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 0] = tcu::Vec4(posX, posY + cellSize, 0.0f, 1.0f); 1425 1426 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 1] = color; 1427 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 1] = color; 1428 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 1] = color; 1429 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 1] = color; 1430 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 1] = color; 1431 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 1] = color; 1432 } 1433 1434 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1435 gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW); 1436 } 1437 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1438 { 1439 // Elements are indexed by index buffer. Interleave color. Two vertices per position since 2 colors 1440 1441 std::vector<tcu::Vec4> buffer((m_gridSize+1)*(m_gridSize+1)*4); 1442 1443 DE_ASSERT(buffer.size() == calcDrawBufferSize()); 1444 1445 for (int y = 0; y < m_gridSize+1; ++y) 1446 for (int x = 0; x < m_gridSize+1; ++x) 1447 { 1448 const float posX = (x / (float)m_gridSize) * 2.0f - 1.0f; 1449 const float posY = (y / (float)m_gridSize) * 2.0f - 1.0f; 1450 1451 buffer[(y * (m_gridSize+1) + x) * 4 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1452 buffer[(y * (m_gridSize+1) + x) * 4 + 1] = green; 1453 buffer[(y * (m_gridSize+1) + x) * 4 + 2] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1454 buffer[(y * (m_gridSize+1) + x) * 4 + 3] = yellow; 1455 } 1456 1457 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1458 gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW); 1459 } 1460 else 1461 DE_ASSERT(false); 1462 1463 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1464 } 1465 1466 void ComputeShaderGeneratedCase::createDrawIndices (void) 1467 { 1468 DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1469 1470 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1471 std::vector<deUint32> buffer (m_gridSize*m_gridSize*6); 1472 1473 DE_ASSERT(buffer.size() == calcIndexBufferSize()); 1474 1475 for (int y = 0; y < m_gridSize; ++y) 1476 for (int x = 0; x < m_gridSize; ++x) 1477 { 1478 const int color = ((x + y)%2); 1479 1480 buffer[(y * m_gridSize + x) * 6 + 0] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color; 1481 buffer[(y * m_gridSize + x) * 6 + 1] = ((y+1) * (m_gridSize+1) + (x+0)) * 2 + color; 1482 buffer[(y * m_gridSize + x) * 6 + 2] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color; 1483 buffer[(y * m_gridSize + x) * 6 + 3] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color; 1484 buffer[(y * m_gridSize + x) * 6 + 4] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color; 1485 buffer[(y * m_gridSize + x) * 6 + 5] = ((y+0) * (m_gridSize+1) + (x+1)) * 2 + color; 1486 } 1487 1488 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID); 1489 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(buffer.size() * sizeof(deUint32)), &buffer[0], GL_STATIC_DRAW); 1490 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1491 } 1492 1493 void ComputeShaderGeneratedCase::renderTo (tcu::Surface& dst) 1494 { 1495 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1496 const deInt32 positionLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_position"); 1497 const deInt32 colorLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_color"); 1498 deUint32 vaoID = 0; 1499 1500 gl.genVertexArrays(1, &vaoID); 1501 gl.bindVertexArray(vaoID); 1502 1503 // Setup buffers 1504 1505 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1506 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), DE_NULL); 1507 gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), ((const deUint8*)DE_NULL) + 4*sizeof(float)); 1508 gl.enableVertexAttribArray(positionLoc); 1509 gl.enableVertexAttribArray(colorLoc); 1510 1511 DE_ASSERT(positionLoc != -1); 1512 DE_ASSERT(colorLoc != -1); 1513 1514 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1515 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID); 1516 1517 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1518 1519 // draw 1520 1521 gl.clearColor(0, 0, 0, 1); 1522 gl.clear(GL_COLOR_BUFFER_BIT); 1523 gl.viewport(0, 0, dst.getWidth(), dst.getHeight()); 1524 1525 gl.useProgram(m_shaderProgram->getProgram()); 1526 for (int drawCmdNdx = 0; drawCmdNdx < m_numDrawCmds; ++drawCmdNdx) 1527 { 1528 const void* offset = ((deUint8*)DE_NULL) + drawCmdNdx*m_commandSize; 1529 1530 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1531 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset); 1532 else if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1533 gl.drawArraysIndirect(GL_TRIANGLES, offset); 1534 else 1535 DE_ASSERT(DE_FALSE); 1536 } 1537 gl.useProgram(0); 1538 1539 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1540 1541 // free 1542 1543 gl.deleteVertexArrays(1, &vaoID); 1544 1545 gl.finish(); 1546 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 1547 1548 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1549 } 1550 1551 deUint32 ComputeShaderGeneratedCase::calcDrawBufferSize (void) const 1552 { 1553 // returns size in "vec4"s 1554 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1555 return m_gridSize*m_gridSize*6*2; 1556 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1557 return (m_gridSize+1)*(m_gridSize+1)*4; 1558 else 1559 DE_ASSERT(DE_FALSE); 1560 1561 return 0; 1562 } 1563 1564 deUint32 ComputeShaderGeneratedCase::calcIndexBufferSize (void) const 1565 { 1566 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1567 return m_gridSize*m_gridSize*6; 1568 else 1569 return 0; 1570 } 1571 1572 class ComputeShaderGeneratedCombinedCase : public ComputeShaderGeneratedCase 1573 { 1574 public: 1575 ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls); 1576 ~ComputeShaderGeneratedCombinedCase (void); 1577 1578 void init (void); 1579 void deinit (void); 1580 1581 private: 1582 void runComputeShader (void); 1583 1584 glu::ShaderProgram* m_computeProgram; 1585 }; 1586 1587 ComputeShaderGeneratedCombinedCase::ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls) 1588 : ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls) 1589 , m_computeProgram (DE_NULL) 1590 { 1591 } 1592 1593 ComputeShaderGeneratedCombinedCase::~ComputeShaderGeneratedCombinedCase (void) 1594 { 1595 deinit(); 1596 } 1597 1598 void ComputeShaderGeneratedCombinedCase::init (void) 1599 { 1600 // generate compute shader 1601 1602 m_computeProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource(m_computeCmd, m_computeData, m_computeIndices))); 1603 m_testCtx.getLog() << *m_computeProgram; 1604 1605 if (!m_computeProgram->isOk()) 1606 throw tcu::TestError("Failed to compile compute shader."); 1607 1608 // init parent 1609 ComputeShaderGeneratedCase::init(); 1610 } 1611 1612 void ComputeShaderGeneratedCombinedCase::deinit (void) 1613 { 1614 // deinit parent 1615 ComputeShaderGeneratedCase::deinit(); 1616 1617 if (m_computeProgram) 1618 { 1619 delete m_computeProgram; 1620 m_computeProgram = DE_NULL; 1621 } 1622 } 1623 1624 void ComputeShaderGeneratedCombinedCase::runComputeShader (void) 1625 { 1626 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1627 const bool indexed = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1628 const tcu::IVec3 nullSize (0, 0, 0); 1629 const tcu::IVec3 commandDispatchSize = (m_computeCmd) ? (tcu::IVec3(m_numDrawCmds, 1, 1)) : (nullSize); 1630 const tcu::IVec3 drawElementsDataBufferDispatchSize = (m_computeData) ? (tcu::IVec3(m_gridSize+1, m_gridSize+1, 1)) : (nullSize); 1631 const tcu::IVec3 drawArraysDataBufferDispatchSize = (m_computeData) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize); 1632 const tcu::IVec3 indexBufferDispatchSize = (m_computeIndices && indexed) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize); 1633 1634 const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize); 1635 const tcu::IVec3 dispatchSize = tcu::max(tcu::max(commandDispatchSize, dataBufferDispatchSize), indexBufferDispatchSize); 1636 1637 gl.useProgram(m_computeProgram->getProgram()); 1638 glu::checkError(gl.getError(), "use compute shader", __FILE__, __LINE__); 1639 1640 // setup buffers 1641 1642 if (m_computeCmd) 1643 { 1644 const int bindingPoint = 0; 1645 const int bufferSize = m_commandSize * m_numDrawCmds; 1646 1647 m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1648 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID); 1649 1650 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1651 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1652 } 1653 1654 if (m_computeData) 1655 { 1656 const int bindingPoint = (m_computeCmd) ? (1) : (0); 1657 const int bufferSize = (int)(calcDrawBufferSize()*sizeof(tcu::Vec4)); 1658 1659 m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1660 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID); 1661 1662 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1663 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1664 } 1665 1666 if (m_computeIndices) 1667 { 1668 const int bindingPoint = (m_computeCmd && m_computeData) ? (2) : (m_computeCmd || m_computeData) ? (1) : (0); 1669 const int bufferSize = (int)(calcIndexBufferSize()*sizeof(deUint32)); 1670 1671 m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1672 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID); 1673 1674 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1675 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1676 } 1677 1678 glu::checkError(gl.getError(), "setup buffers", __FILE__, __LINE__); 1679 1680 // calculate 1681 1682 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching compute, size = " << dispatchSize << tcu::TestLog::EndMessage; 1683 gl.dispatchCompute(dispatchSize.x(), dispatchSize.y(), dispatchSize.z()); 1684 1685 glu::checkError(gl.getError(), "calculate", __FILE__, __LINE__); 1686 } 1687 1688 class ComputeShaderGeneratedSeparateCase : public ComputeShaderGeneratedCase 1689 { 1690 public: 1691 ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls); 1692 ~ComputeShaderGeneratedSeparateCase (void); 1693 1694 void init (void); 1695 void deinit (void); 1696 1697 private: 1698 std::string genCmdComputeSource (void); 1699 std::string genDataComputeSource (void); 1700 std::string genIndexComputeSource (void); 1701 void runComputeShader (void); 1702 1703 glu::ShaderProgram* m_computeCmdProgram; 1704 glu::ShaderProgram* m_computeDataProgram; 1705 glu::ShaderProgram* m_computeIndicesProgram; 1706 }; 1707 1708 ComputeShaderGeneratedSeparateCase::ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls) 1709 : ComputeShaderGeneratedCase (context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls) 1710 , m_computeCmdProgram (DE_NULL) 1711 , m_computeDataProgram (DE_NULL) 1712 , m_computeIndicesProgram (DE_NULL) 1713 { 1714 } 1715 1716 ComputeShaderGeneratedSeparateCase::~ComputeShaderGeneratedSeparateCase (void) 1717 { 1718 deinit(); 1719 } 1720 1721 void ComputeShaderGeneratedSeparateCase::init (void) 1722 { 1723 // generate cmd compute shader 1724 1725 if (m_computeCmd) 1726 { 1727 m_computeCmdProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genCmdComputeSource())); 1728 m_testCtx.getLog() << *m_computeCmdProgram; 1729 1730 if (!m_computeCmdProgram->isOk()) 1731 throw tcu::TestError("Failed to compile command compute shader."); 1732 } 1733 1734 // generate data compute shader 1735 1736 if (m_computeData) 1737 { 1738 m_computeDataProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genDataComputeSource())); 1739 m_testCtx.getLog() << *m_computeDataProgram; 1740 1741 if (!m_computeDataProgram->isOk()) 1742 throw tcu::TestError("Failed to compile data compute shader."); 1743 } 1744 1745 // generate index compute shader 1746 1747 if (m_computeIndices) 1748 { 1749 m_computeIndicesProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genIndexComputeSource())); 1750 m_testCtx.getLog() << *m_computeIndicesProgram; 1751 1752 if (!m_computeIndicesProgram->isOk()) 1753 throw tcu::TestError("Failed to compile data compute shader."); 1754 } 1755 1756 // init parent 1757 ComputeShaderGeneratedCase::init(); 1758 } 1759 1760 void ComputeShaderGeneratedSeparateCase::deinit (void) 1761 { 1762 // deinit parent 1763 ComputeShaderGeneratedCase::deinit(); 1764 1765 if (m_computeCmdProgram) 1766 { 1767 delete m_computeCmdProgram; 1768 m_computeCmdProgram = DE_NULL; 1769 } 1770 if (m_computeDataProgram) 1771 { 1772 delete m_computeDataProgram; 1773 m_computeDataProgram = DE_NULL; 1774 } 1775 if (m_computeIndicesProgram) 1776 { 1777 delete m_computeIndicesProgram; 1778 m_computeIndicesProgram = DE_NULL; 1779 } 1780 } 1781 1782 std::string ComputeShaderGeneratedSeparateCase::genCmdComputeSource (void) 1783 { 1784 return ComputeShaderGeneratedCase::genComputeSource(true, false, false); 1785 } 1786 1787 std::string ComputeShaderGeneratedSeparateCase::genDataComputeSource (void) 1788 { 1789 return ComputeShaderGeneratedCase::genComputeSource(false, true, false); 1790 } 1791 1792 std::string ComputeShaderGeneratedSeparateCase::genIndexComputeSource (void) 1793 { 1794 return ComputeShaderGeneratedCase::genComputeSource(false, false, true); 1795 } 1796 1797 void ComputeShaderGeneratedSeparateCase::runComputeShader (void) 1798 { 1799 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1800 1801 // Compute command 1802 1803 if (m_computeCmd) 1804 { 1805 const int bindingPoint = 0; 1806 const tcu::IVec3 commandDispatchSize (m_numDrawCmds, 1, 1); 1807 const int bufferSize = m_commandSize * m_numDrawCmds; 1808 1809 gl.useProgram(m_computeCmdProgram->getProgram()); 1810 1811 // setup buffers 1812 1813 m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1814 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID); 1815 1816 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1817 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1818 1819 // calculate 1820 1821 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching command compute, size = " << commandDispatchSize << tcu::TestLog::EndMessage; 1822 gl.dispatchCompute(commandDispatchSize.x(), commandDispatchSize.y(), commandDispatchSize.z()); 1823 1824 glu::checkError(gl.getError(), "calculate cmd", __FILE__, __LINE__); 1825 } 1826 1827 // Compute data 1828 1829 if (m_computeData) 1830 { 1831 const int bindingPoint = 0; 1832 const tcu::IVec3 drawElementsDataBufferDispatchSize (m_gridSize+1, m_gridSize+1, 1); 1833 const tcu::IVec3 drawArraysDataBufferDispatchSize (m_gridSize, m_gridSize, 1); 1834 const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize); 1835 const int bufferSize = (int)(calcDrawBufferSize()*sizeof(tcu::Vec4)); 1836 1837 gl.useProgram(m_computeDataProgram->getProgram()); 1838 1839 // setup buffers 1840 1841 m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1842 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID); 1843 1844 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1845 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1846 1847 // calculate 1848 1849 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching data compute, size = " << dataBufferDispatchSize << tcu::TestLog::EndMessage; 1850 gl.dispatchCompute(dataBufferDispatchSize.x(), dataBufferDispatchSize.y(), dataBufferDispatchSize.z()); 1851 1852 glu::checkError(gl.getError(), "calculate data", __FILE__, __LINE__); 1853 } 1854 1855 // Compute indices 1856 1857 if (m_computeIndices) 1858 { 1859 const int bindingPoint = 0; 1860 const tcu::IVec3 indexBufferDispatchSize (m_gridSize, m_gridSize, 1); 1861 const int bufferSize = (int)(calcIndexBufferSize()*sizeof(deUint32)); 1862 1863 DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1864 1865 gl.useProgram(m_computeIndicesProgram->getProgram()); 1866 1867 // setup buffers 1868 1869 m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1870 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID); 1871 1872 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1873 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1874 1875 // calculate 1876 1877 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching index compute, size = " << indexBufferDispatchSize << tcu::TestLog::EndMessage; 1878 gl.dispatchCompute(indexBufferDispatchSize.x(), indexBufferDispatchSize.y(), indexBufferDispatchSize.z()); 1879 1880 glu::checkError(gl.getError(), "calculate indices", __FILE__, __LINE__); 1881 } 1882 1883 glu::checkError(gl.getError(), "post dispatch", __FILE__, __LINE__); 1884 } 1885 1886 class ComputeShaderGeneratedGroup : public TestCaseGroup 1887 { 1888 public: 1889 ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr); 1890 ~ComputeShaderGeneratedGroup (void); 1891 1892 void init (void); 1893 }; 1894 1895 ComputeShaderGeneratedGroup::ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr) 1896 : TestCaseGroup (context, name, descr) 1897 { 1898 } 1899 1900 ComputeShaderGeneratedGroup::~ComputeShaderGeneratedGroup (void) 1901 { 1902 } 1903 1904 void ComputeShaderGeneratedGroup::init (void) 1905 { 1906 const int gridSize = 8; 1907 tcu::TestCaseGroup* const separateGroup = new tcu::TestCaseGroup(m_testCtx, "separate", "Use separate compute shaders for each buffer"); 1908 tcu::TestCaseGroup* const combinedGroup = new tcu::TestCaseGroup(m_testCtx, "combined", "Use combined compute shader for all buffers"); 1909 tcu::TestCaseGroup* const largeGroup = new tcu::TestCaseGroup(m_testCtx, "large", "Draw shapes with large buffers"); 1910 1911 this->addChild(separateGroup); 1912 this->addChild(combinedGroup); 1913 this->addChild(largeGroup); 1914 1915 // .separate 1916 { 1917 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd", "Command from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, false, false, gridSize, 1)); 1918 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_data", "Data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false, true, false, gridSize, 1)); 1919 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1)); 1920 1921 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd", "Command from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, false, gridSize, 1)); 1922 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data", "Data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, false, gridSize, 1)); 1923 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_indices", "Indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, false, true, gridSize, 1)); 1924 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1)); 1925 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1)); 1926 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1)); 1927 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1)); 1928 } 1929 1930 // .combined 1931 { 1932 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1)); 1933 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1)); 1934 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1)); 1935 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1)); 1936 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1)); 1937 } 1938 1939 // .large 1940 { 1941 struct TestSpec 1942 { 1943 int gridSize; 1944 int numDrawCommands; 1945 }; 1946 struct TestMethod 1947 { 1948 ComputeShaderGeneratedCase::DrawMethod method; 1949 bool separateCompute; 1950 }; 1951 1952 static const TestSpec specs[] = 1953 { 1954 { 100, 1 }, // !< drawArrays array size ~ 1.9 MB 1955 { 200, 1 }, // !< drawArrays array size ~ 7.7 MB 1956 { 500, 1 }, // !< drawArrays array size ~ 48 MB 1957 { 1000, 1 }, // !< drawArrays array size ~ 192 MB 1958 { 1200, 1 }, // !< drawArrays array size ~ 277 MB 1959 { 1500, 1 }, // !< drawArrays array size ~ 430 MB 1960 1961 { 100, 8 }, // !< drawArrays array size ~ 1.9 MB 1962 { 200, 8 }, // !< drawArrays array size ~ 7.7 MB 1963 { 500, 8 }, // !< drawArrays array size ~ 48 MB 1964 { 1000, 8 }, // !< drawArrays array size ~ 192 MB 1965 { 1200, 8 }, // !< drawArrays array size ~ 277 MB 1966 { 1500, 8 }, // !< drawArrays array size ~ 430 MB 1967 1968 { 100, 200 }, // !< 50 cells per draw call 1969 { 200, 800 }, // !< 50 cells per draw call 1970 { 500, 2500 }, // !< 100 cells per draw call 1971 { 1000, 5000 }, // !< 250 cells per draw call 1972 }; 1973 static const TestMethod methods[] = 1974 { 1975 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true }, 1976 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false }, 1977 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true }, 1978 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false }, 1979 }; 1980 1981 for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(methods); ++methodNdx) 1982 for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); ++specNdx) 1983 { 1984 const std::string name = std::string("") 1985 + ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays") : ("drawelements")) 1986 + ((methods[methodNdx].separateCompute) ? ("_separate") : ("_combined")) 1987 + "_grid_" + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize) 1988 + "_drawcount_" + de::toString(specs[specNdx].numDrawCommands); 1989 1990 const std::string desc = std::string("Draw grid with ") 1991 + ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays indirect") : ("drawelements indirect")) 1992 + " calculating buffers in " + ((methods[methodNdx].separateCompute) ? ("separate") : ("combined")) + " compute shader." 1993 + " Grid size is " + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize) 1994 + ", draw count is " + de::toString(specs[specNdx].numDrawCommands); 1995 1996 const bool computeIndices = (methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS); 1997 1998 if (methods[methodNdx].separateCompute) 1999 largeGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands)); 2000 else 2001 largeGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands)); 2002 } 2003 } 2004 } 2005 2006 class RandomGroup : public TestCaseGroup 2007 { 2008 public: 2009 RandomGroup (Context& context, const char* name, const char* descr); 2010 ~RandomGroup (void); 2011 2012 void init (void); 2013 }; 2014 2015 template <int SIZE> 2016 struct UniformWeightArray 2017 { 2018 float weights[SIZE]; 2019 2020 UniformWeightArray (void) 2021 { 2022 for (int i=0; i<SIZE; ++i) 2023 weights[i] = 1.0f; 2024 } 2025 }; 2026 2027 RandomGroup::RandomGroup (Context& context, const char* name, const char* descr) 2028 : TestCaseGroup (context, name, descr) 2029 { 2030 } 2031 2032 RandomGroup::~RandomGroup (void) 2033 { 2034 } 2035 2036 void RandomGroup::init (void) 2037 { 2038 const int numAttempts = 100; 2039 2040 const int attribCounts[] = { 1, 2, 5 }; 2041 const float attribWeights[] = { 30, 10, 1 }; 2042 const int primitiveCounts[] = { 1, 5, 64 }; 2043 const float primitiveCountWeights[] = { 20, 10, 1 }; 2044 const int indexOffsets[] = { 0, 7, 13 }; 2045 const float indexOffsetWeights[] = { 20, 20, 1 }; 2046 const int firsts[] = { 0, 7, 13 }; 2047 const float firstWeights[] = { 20, 20, 1 }; 2048 2049 const int instanceCounts[] = { 1, 2, 16, 17 }; 2050 const float instanceWeights[] = { 20, 10, 5, 1 }; 2051 const int indexMins[] = { 0, 1, 3, 8 }; 2052 const int indexMaxs[] = { 4, 8, 128, 257 }; 2053 const float indexWeights[] = { 50, 50, 50, 50 }; 2054 const int offsets[] = { 0, 1, 5, 12 }; 2055 const float offsetWeights[] = { 50, 10, 10, 10 }; 2056 const int strides[] = { 0, 7, 16, 17 }; 2057 const float strideWeights[] = { 50, 10, 10, 10 }; 2058 const int instanceDivisors[] = { 0, 1, 3, 129 }; 2059 const float instanceDivisorWeights[]= { 70, 30, 10, 10 }; 2060 2061 const int indirectOffsets[] = { 0, 1, 2 }; 2062 const float indirectOffsetWeigths[] = { 2, 1, 1 }; 2063 const int baseVertices[] = { 0, 1, -2, 4, 3 }; 2064 const float baseVertexWeigths[] = { 4, 1, 1, 1, 1 }; 2065 2066 gls::DrawTestSpec::Primitive primitives[] = 2067 { 2068 gls::DrawTestSpec::PRIMITIVE_POINTS, 2069 gls::DrawTestSpec::PRIMITIVE_TRIANGLES, 2070 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, 2071 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP, 2072 gls::DrawTestSpec::PRIMITIVE_LINES, 2073 gls::DrawTestSpec::PRIMITIVE_LINE_STRIP, 2074 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP 2075 }; 2076 const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights; 2077 2078 gls::DrawTestSpec::DrawMethod drawMethods[] = 2079 { 2080 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT, 2081 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT, 2082 }; 2083 const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights; 2084 2085 gls::DrawTestSpec::IndexType indexTypes[] = 2086 { 2087 gls::DrawTestSpec::INDEXTYPE_BYTE, 2088 gls::DrawTestSpec::INDEXTYPE_SHORT, 2089 gls::DrawTestSpec::INDEXTYPE_INT, 2090 }; 2091 const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights; 2092 2093 gls::DrawTestSpec::InputType inputTypes[] = 2094 { 2095 gls::DrawTestSpec::INPUTTYPE_FLOAT, 2096 gls::DrawTestSpec::INPUTTYPE_FIXED, 2097 gls::DrawTestSpec::INPUTTYPE_BYTE, 2098 gls::DrawTestSpec::INPUTTYPE_SHORT, 2099 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE, 2100 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT, 2101 gls::DrawTestSpec::INPUTTYPE_INT, 2102 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, 2103 gls::DrawTestSpec::INPUTTYPE_HALF, 2104 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2105 gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10, 2106 }; 2107 const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights; 2108 2109 gls::DrawTestSpec::OutputType outputTypes[] = 2110 { 2111 gls::DrawTestSpec::OUTPUTTYPE_FLOAT, 2112 gls::DrawTestSpec::OUTPUTTYPE_VEC2, 2113 gls::DrawTestSpec::OUTPUTTYPE_VEC3, 2114 gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2115 gls::DrawTestSpec::OUTPUTTYPE_INT, 2116 gls::DrawTestSpec::OUTPUTTYPE_UINT, 2117 gls::DrawTestSpec::OUTPUTTYPE_IVEC2, 2118 gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 2119 gls::DrawTestSpec::OUTPUTTYPE_IVEC4, 2120 gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 2121 gls::DrawTestSpec::OUTPUTTYPE_UVEC3, 2122 gls::DrawTestSpec::OUTPUTTYPE_UVEC4, 2123 }; 2124 const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights; 2125 2126 gls::DrawTestSpec::Usage usages[] = 2127 { 2128 gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, 2129 gls::DrawTestSpec::USAGE_STATIC_DRAW, 2130 gls::DrawTestSpec::USAGE_STREAM_DRAW, 2131 gls::DrawTestSpec::USAGE_STREAM_READ, 2132 gls::DrawTestSpec::USAGE_STREAM_COPY, 2133 gls::DrawTestSpec::USAGE_STATIC_READ, 2134 gls::DrawTestSpec::USAGE_STATIC_COPY, 2135 gls::DrawTestSpec::USAGE_DYNAMIC_READ, 2136 gls::DrawTestSpec::USAGE_DYNAMIC_COPY, 2137 }; 2138 const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights; 2139 2140 std::set<deUint32> insertedHashes; 2141 size_t insertedCount = 0; 2142 2143 for (int ndx = 0; ndx < numAttempts; ++ndx) 2144 { 2145 de::Random random(0xc551393 + ndx); // random does not depend on previous cases 2146 2147 int attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights); 2148 int drawCommandSize; 2149 gls::DrawTestSpec spec; 2150 2151 spec.apiType = glu::ApiType::es(3,1); 2152 spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive> (DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights); 2153 spec.primitiveCount = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights); 2154 spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod> (DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights); 2155 2156 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT) 2157 drawCommandSize = sizeof(deUint32[4]); 2158 else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2159 drawCommandSize = sizeof(deUint32[5]); 2160 else 2161 { 2162 DE_ASSERT(DE_FALSE); 2163 return; 2164 } 2165 2166 spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType> (DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights); 2167 spec.indexPointerOffset = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights); 2168 spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; 2169 spec.first = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(firsts), DE_ARRAY_END(firsts), firstWeights); 2170 spec.indexMin = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexMins), DE_ARRAY_END(indexMins), indexWeights); 2171 spec.indexMax = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexMaxs), DE_ARRAY_END(indexMaxs), indexWeights); 2172 spec.instanceCount = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(instanceCounts), DE_ARRAY_END(instanceCounts), instanceWeights); 2173 spec.indirectOffset = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indirectOffsets), DE_ARRAY_END(indirectOffsets), indirectOffsetWeigths) * drawCommandSize; 2174 spec.baseVertex = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(baseVertices), DE_ARRAY_END(baseVertices), baseVertexWeigths); 2175 2176 // check spec is legal 2177 if (!spec.valid()) 2178 continue; 2179 2180 for (int attrNdx = 0; attrNdx < attributeCount;) 2181 { 2182 bool valid; 2183 gls::DrawTestSpec::AttributeSpec attribSpec; 2184 2185 attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType> (DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights); 2186 attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType> (DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights); 2187 attribSpec.storage = gls::DrawTestSpec::STORAGE_BUFFER; 2188 attribSpec.usage = random.chooseWeighted<gls::DrawTestSpec::Usage> (DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights); 2189 attribSpec.componentCount = random.getInt(1, 4); 2190 attribSpec.offset = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights); 2191 attribSpec.stride = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights); 2192 attribSpec.normalize = random.getBool(); 2193 attribSpec.instanceDivisor = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights); 2194 attribSpec.useDefaultAttribute = random.getBool(); 2195 2196 // check spec is legal 2197 valid = attribSpec.valid(spec.apiType); 2198 2199 // we do not want interleaved elements. (Might result in some weird floating point values) 2200 if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride) 2201 valid = false; 2202 2203 // try again if not valid 2204 if (valid) 2205 { 2206 spec.attribs.push_back(attribSpec); 2207 ++attrNdx; 2208 } 2209 } 2210 2211 // Do not collapse all vertex positions to a single positions 2212 if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2213 spec.attribs[0].instanceDivisor = 0; 2214 2215 // Is render result meaningful? 2216 { 2217 // Only one vertex 2218 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2219 continue; 2220 if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2221 continue; 2222 2223 // Triangle only on one axis 2224 if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP) 2225 { 2226 if (spec.attribs[0].componentCount == 1) 2227 continue; 2228 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT) 2229 continue; 2230 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2) 2231 continue; 2232 } 2233 } 2234 2235 // Add case 2236 { 2237 deUint32 hash = spec.hash(); 2238 for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx) 2239 hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash(); 2240 2241 if (insertedHashes.find(hash) == insertedHashes.end()) 2242 { 2243 // Only aligned cases 2244 if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET && 2245 spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 2246 this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str())); 2247 insertedHashes.insert(hash); 2248 2249 ++insertedCount; 2250 } 2251 } 2252 } 2253 } 2254 2255 class BadCommandBufferCase : public TestCase 2256 { 2257 public: 2258 enum 2259 { 2260 CommandSize = 20 2261 }; 2262 2263 BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 m_expectedError); 2264 ~BadCommandBufferCase (void); 2265 2266 IterateResult iterate (void); 2267 2268 private: 2269 const deUint32 m_alignment; 2270 const deUint32 m_bufferSize; 2271 const bool m_writeCommandToBuffer; 2272 const deUint32 m_expectedError; 2273 }; 2274 2275 BadCommandBufferCase::BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 expectedError) 2276 : TestCase (context, name, desc) 2277 , m_alignment (alignment) 2278 , m_bufferSize (bufferSize) 2279 , m_writeCommandToBuffer (writeCommandToBuffer) 2280 , m_expectedError (expectedError) 2281 { 2282 } 2283 2284 BadCommandBufferCase::~BadCommandBufferCase (void) 2285 { 2286 } 2287 2288 BadCommandBufferCase::IterateResult BadCommandBufferCase::iterate (void) 2289 { 2290 const tcu::Vec4 vertexPositions[] = 2291 { 2292 tcu::Vec4(0, 0, 0, 1), 2293 tcu::Vec4(1, 0, 0, 1), 2294 tcu::Vec4(0, 1, 0, 1), 2295 }; 2296 2297 const deUint16 indices[] = 2298 { 2299 0, 2, 1, 2300 }; 2301 2302 DE_STATIC_ASSERT(CommandSize == sizeof(DrawElementsCommand)); 2303 2304 sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2305 2306 deUint32 vaoID = 0; 2307 deUint32 positionBuf = 0; 2308 deUint32 indexBuf = 0; 2309 deUint32 drawIndirectBuf= 0; 2310 deUint32 error; 2311 2312 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2313 deUint32 programID = program.getProgram(); 2314 deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2315 2316 DrawElementsCommand drawCommand; 2317 drawCommand.count = 3; 2318 drawCommand.primCount = 1; 2319 drawCommand.firstIndex = 0; 2320 drawCommand.baseVertex = 0; 2321 drawCommand.reservedMustBeZero = 0; 2322 2323 std::vector<deInt8> drawCommandBuffer; 2324 drawCommandBuffer.resize(m_bufferSize); 2325 2326 deMemset(&drawCommandBuffer[0], 0, (int)drawCommandBuffer.size()); 2327 2328 if (m_writeCommandToBuffer) 2329 { 2330 DE_ASSERT(drawCommandBuffer.size() >= sizeof(drawCommand) + m_alignment); 2331 deMemcpy(&drawCommandBuffer[m_alignment], &drawCommand, sizeof(drawCommand)); 2332 } 2333 2334 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2335 gl.genVertexArrays(1, &vaoID); 2336 gl.bindVertexArray(vaoID); 2337 2338 gl.genBuffers(1, &positionBuf); 2339 gl.bindBuffer(GL_ARRAY_BUFFER, positionBuf); 2340 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2341 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2342 gl.vertexAttribDivisor(posLocation, 0); 2343 gl.enableVertexAttribArray(posLocation); 2344 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2345 2346 gl.genBuffers(1, &indexBuf); 2347 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf); 2348 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2349 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2350 2351 gl.genBuffers(1, &drawIndirectBuf); 2352 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf); 2353 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, drawCommandBuffer.size(), &drawCommandBuffer[0], GL_STATIC_DRAW); 2354 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2355 2356 gl.viewport(0, 0, 1, 1); 2357 2358 gl.useProgram(programID); 2359 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(deUintptr)m_alignment); 2360 2361 error = gl.getError(); 2362 2363 gl.useProgram(0); 2364 2365 gl.deleteBuffers(1, &drawIndirectBuf); 2366 gl.deleteBuffers(1, &indexBuf); 2367 gl.deleteBuffers(1, &positionBuf); 2368 gl.deleteVertexArrays(1, &vaoID); 2369 2370 m_testCtx.getLog() << tcu::TestLog::Message << "drawElementsIndirect generated " << glu::getErrorStr(error) << ", expecting " << glu::getErrorStr(m_expectedError) << "." << tcu::TestLog::EndMessage; 2371 2372 if (error == m_expectedError) 2373 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2374 else 2375 { 2376 m_testCtx.getLog() << tcu::TestLog::Message << "\tUnexpected error." << tcu::TestLog::EndMessage; 2377 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2378 } 2379 2380 return STOP; 2381 } 2382 2383 class BadAlignmentCase : public BadCommandBufferCase 2384 { 2385 public: 2386 BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment); 2387 ~BadAlignmentCase (void); 2388 }; 2389 2390 BadAlignmentCase::BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment) 2391 : BadCommandBufferCase(context, name, desc, alignment, CommandSize+alignment, true, GL_INVALID_VALUE) 2392 { 2393 } 2394 2395 BadAlignmentCase::~BadAlignmentCase (void) 2396 { 2397 } 2398 2399 class BadBufferRangeCase : public BadCommandBufferCase 2400 { 2401 public: 2402 BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset); 2403 ~BadBufferRangeCase (void); 2404 }; 2405 2406 BadBufferRangeCase::BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset) 2407 : BadCommandBufferCase(context, name, desc, offset, CommandSize, false, GL_INVALID_OPERATION) 2408 { 2409 } 2410 2411 BadBufferRangeCase::~BadBufferRangeCase (void) 2412 { 2413 } 2414 2415 class BadStateCase : public TestCase 2416 { 2417 public: 2418 enum CaseType 2419 { 2420 CASE_CLIENT_BUFFER_VERTEXATTR = 0, 2421 CASE_CLIENT_BUFFER_COMMAND, 2422 CASE_DEFAULT_VAO, 2423 2424 CASE_CLIENT_LAST 2425 }; 2426 2427 BadStateCase (Context& context, const char* name, const char* desc, CaseType type); 2428 ~BadStateCase (void); 2429 2430 void init (void); 2431 void deinit (void); 2432 IterateResult iterate (void); 2433 2434 private: 2435 const CaseType m_caseType; 2436 }; 2437 2438 BadStateCase::BadStateCase (Context& context, const char* name, const char* desc, CaseType type) 2439 : TestCase (context, name, desc) 2440 , m_caseType (type) 2441 { 2442 DE_ASSERT(type < CASE_CLIENT_LAST); 2443 } 2444 2445 BadStateCase::~BadStateCase (void) 2446 { 2447 deinit(); 2448 } 2449 2450 void BadStateCase::init (void) 2451 { 2452 } 2453 2454 void BadStateCase::deinit (void) 2455 { 2456 } 2457 2458 BadStateCase::IterateResult BadStateCase::iterate (void) 2459 { 2460 const tcu::Vec4 vertexPositions[] = 2461 { 2462 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), 2463 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 2464 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 2465 }; 2466 2467 const deUint16 indices[] = 2468 { 2469 0, 2, 1, 2470 }; 2471 2472 sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2473 2474 deUint32 error; 2475 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2476 deUint32 vaoID = 0; 2477 deUint32 dataBufferID = 0; 2478 deUint32 indexBufferID = 0; 2479 deUint32 cmdBufferID = 0; 2480 2481 const deUint32 programID = program.getProgram(); 2482 const deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2483 2484 DrawElementsCommand drawCommand; 2485 drawCommand.count = 3; 2486 drawCommand.primCount = 1; 2487 drawCommand.firstIndex = 0; 2488 drawCommand.baseVertex = 0; 2489 drawCommand.reservedMustBeZero = 0; 2490 2491 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2492 2493 if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR) 2494 { 2495 // \note We use default VAO since we use client pointers. Trying indirect draw with default VAO is also an error. => This test does two illegal operations 2496 2497 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, vertexPositions); 2498 gl.enableVertexAttribArray(posLocation); 2499 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2500 } 2501 else if (m_caseType == CASE_CLIENT_BUFFER_COMMAND) 2502 { 2503 gl.genVertexArrays(1, &vaoID); 2504 gl.bindVertexArray(vaoID); 2505 2506 gl.genBuffers(1, &dataBufferID); 2507 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2508 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2509 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2510 gl.enableVertexAttribArray(posLocation); 2511 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2512 } 2513 else if (m_caseType == CASE_DEFAULT_VAO) 2514 { 2515 gl.genBuffers(1, &dataBufferID); 2516 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2517 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2518 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2519 gl.enableVertexAttribArray(posLocation); 2520 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2521 } 2522 else 2523 DE_ASSERT(DE_FALSE); 2524 2525 gl.genBuffers(1, &indexBufferID); 2526 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); 2527 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2528 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2529 2530 if (m_caseType != CASE_CLIENT_BUFFER_COMMAND) 2531 { 2532 gl.genBuffers(1, &cmdBufferID); 2533 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID); 2534 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2535 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2536 } 2537 2538 gl.viewport(0, 0, 1, 1); 2539 2540 gl.useProgram(programID); 2541 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (m_caseType != CASE_CLIENT_BUFFER_COMMAND) ? (DE_NULL) : (&drawCommand)); 2542 2543 error = gl.getError(); 2544 2545 gl.bindVertexArray(0); 2546 gl.useProgram(0); 2547 2548 if (error == GL_INVALID_OPERATION) 2549 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2550 else 2551 { 2552 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 2553 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2554 } 2555 2556 return STOP; 2557 } 2558 2559 class BadDrawModeCase : public TestCase 2560 { 2561 public: 2562 enum DrawType 2563 { 2564 DRAW_ARRAYS = 0, 2565 DRAW_ELEMENTS, 2566 DRAW_ELEMENTS_BAD_INDEX, 2567 2568 DRAW_LAST 2569 }; 2570 2571 BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type); 2572 ~BadDrawModeCase(void); 2573 2574 void init (void); 2575 void deinit (void); 2576 IterateResult iterate (void); 2577 2578 private: 2579 const DrawType m_drawType; 2580 }; 2581 2582 BadDrawModeCase::BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type) 2583 : TestCase (context, name, desc) 2584 , m_drawType (type) 2585 { 2586 DE_ASSERT(type < DRAW_LAST); 2587 } 2588 2589 BadDrawModeCase::~BadDrawModeCase (void) 2590 { 2591 deinit(); 2592 } 2593 2594 void BadDrawModeCase::init (void) 2595 { 2596 } 2597 2598 void BadDrawModeCase::deinit (void) 2599 { 2600 } 2601 2602 BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void) 2603 { 2604 const tcu::Vec4 vertexPositions[] = 2605 { 2606 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), 2607 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 2608 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 2609 }; 2610 2611 const deUint16 indices[] = 2612 { 2613 0, 2, 1, 2614 }; 2615 2616 sglr::GLContext gl (m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2617 2618 deUint32 error; 2619 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2620 deUint32 vaoID = 0; 2621 deUint32 dataBufferID = 0; 2622 deUint32 indexBufferID = 0; 2623 deUint32 cmdBufferID = 0; 2624 2625 const deUint32 programID = program.getProgram(); 2626 const deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2627 const glw::GLenum mode = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (GL_TRIANGLES) : (0x123); 2628 const glw::GLenum indexType = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (0x123) : (GL_UNSIGNED_SHORT); 2629 2630 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2631 2632 // vao 2633 2634 gl.genVertexArrays(1, &vaoID); 2635 gl.bindVertexArray(vaoID); 2636 2637 // va 2638 2639 gl.genBuffers(1, &dataBufferID); 2640 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2641 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2642 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2643 gl.enableVertexAttribArray(posLocation); 2644 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2645 2646 // index 2647 2648 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2649 { 2650 gl.genBuffers(1, &indexBufferID); 2651 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); 2652 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2653 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2654 } 2655 2656 // cmd 2657 2658 gl.genBuffers(1, &cmdBufferID); 2659 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID); 2660 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2661 { 2662 DrawElementsCommand drawCommand; 2663 drawCommand.count = 3; 2664 drawCommand.primCount = 1; 2665 drawCommand.firstIndex = 0; 2666 drawCommand.baseVertex = 0; 2667 drawCommand.reservedMustBeZero = 0; 2668 2669 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2670 } 2671 else if (m_drawType == DRAW_ARRAYS) 2672 { 2673 DrawArraysCommand drawCommand; 2674 drawCommand.count = 3; 2675 drawCommand.primCount = 1; 2676 drawCommand.first = 0; 2677 drawCommand.reservedMustBeZero = 0; 2678 2679 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2680 } 2681 else 2682 DE_ASSERT(DE_FALSE); 2683 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2684 2685 gl.viewport(0, 0, 1, 1); 2686 gl.useProgram(programID); 2687 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2688 gl.drawElementsIndirect(mode, indexType, DE_NULL); 2689 else if (m_drawType == DRAW_ARRAYS) 2690 gl.drawArraysIndirect(mode, DE_NULL); 2691 else 2692 DE_ASSERT(DE_FALSE); 2693 2694 error = gl.getError(); 2695 gl.useProgram(0); 2696 2697 if (error == GL_INVALID_ENUM) 2698 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2699 else 2700 { 2701 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_ENUM, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 2702 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2703 } 2704 2705 return STOP; 2706 } 2707 2708 class NegativeGroup : public TestCaseGroup 2709 { 2710 public: 2711 NegativeGroup (Context& context, const char* name, const char* descr); 2712 ~NegativeGroup (void); 2713 2714 void init (void); 2715 }; 2716 2717 NegativeGroup::NegativeGroup (Context& context, const char* name, const char* descr) 2718 : TestCaseGroup (context, name, descr) 2719 { 2720 } 2721 2722 NegativeGroup::~NegativeGroup (void) 2723 { 2724 } 2725 2726 void NegativeGroup::init (void) 2727 { 2728 // invalid alignment 2729 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_1", "Bad command alignment", 1)); 2730 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_2", "Bad command alignment", 2)); 2731 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_3", "Bad command alignment", 3)); 2732 2733 // command only partially or not at all in the buffer 2734 addChild(new BadBufferRangeCase (m_context, "command_offset_partially_in_buffer", "Command not fully in the buffer range", BadBufferRangeCase::CommandSize - 16)); 2735 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer", "Command not in the buffer range", BadBufferRangeCase::CommandSize)); 2736 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer_unsigned32_wrap", "Command not in the buffer range", 0xFFFFFFFC)); 2737 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer_signed32_wrap", "Command not in the buffer range", 0x7FFFFFFC)); 2738 2739 // use with client data and default vao 2740 addChild(new BadStateCase (m_context, "client_vertex_attrib_array", "Vertex attrib array in the client memory", BadStateCase::CASE_CLIENT_BUFFER_VERTEXATTR)); 2741 addChild(new BadStateCase (m_context, "client_command_array", "Command array in the client memory", BadStateCase::CASE_CLIENT_BUFFER_COMMAND)); 2742 addChild(new BadStateCase (m_context, "default_vao", "Use with default vao", BadStateCase::CASE_DEFAULT_VAO)); 2743 2744 // invalid mode & type 2745 addChild(new BadDrawModeCase (m_context, "invalid_mode_draw_arrays", "Call DrawArraysIndirect with bad mode", BadDrawModeCase::DRAW_ARRAYS)); 2746 addChild(new BadDrawModeCase (m_context, "invalid_mode_draw_elements", "Call DrawelementsIndirect with bad mode", BadDrawModeCase::DRAW_ELEMENTS)); 2747 addChild(new BadDrawModeCase (m_context, "invalid_type_draw_elements", "Call DrawelementsIndirect with bad type", BadDrawModeCase::DRAW_ELEMENTS_BAD_INDEX)); 2748 } 2749 2750 } // anonymous 2751 2752 DrawTests::DrawTests (Context& context) 2753 : TestCaseGroup(context, "draw_indirect", "Indirect drawing tests") 2754 { 2755 } 2756 2757 DrawTests::~DrawTests (void) 2758 { 2759 } 2760 2761 void DrawTests::init (void) 2762 { 2763 // Basic 2764 { 2765 const gls::DrawTestSpec::DrawMethod basicMethods[] = 2766 { 2767 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT, 2768 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT, 2769 }; 2770 2771 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx) 2772 { 2773 const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 2774 const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 2775 2776 this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx])); 2777 } 2778 } 2779 2780 // extreme instancing 2781 2782 this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count.")); 2783 2784 // compute shader generated commands 2785 2786 this->addChild(new ComputeShaderGeneratedGroup(m_context, "compute_interop", "draw tests with a draw command generated in compute shader.")); 2787 2788 // Random 2789 2790 this->addChild(new RandomGroup(m_context, "random", "random draw commands.")); 2791 2792 // negative 2793 2794 this->addChild(new NegativeGroup(m_context, "negative", "invalid draw commands with defined error codes.")); 2795 } 2796 2797 } // Functional 2798 } // gles31 2799 } // deqp 2800