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