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 posXp1 = (float(x+1u) / float(gridSize)) * 2.0 - 1.0;\n" 1281 << " float posY = (float(y) / float(gridSize)) * 2.0 - 1.0;\n" 1282 << " float posYp1 = (float(y+1u) / float(gridSize)) * 2.0 - 1.0;\n" 1283 << " vec4 color = ((x + y)%2u != 0u) ? (yellow) : (green);\n" 1284 << "\n" 1285 << " attribs[((y * gridSize + x) * 6u + 0u) * 2u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1286 << " attribs[((y * gridSize + x) * 6u + 1u) * 2u + 0u] = vec4(posXp1, posY, 0.0, 1.0);\n" 1287 << " attribs[((y * gridSize + x) * 6u + 2u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n" 1288 << " attribs[((y * gridSize + x) * 6u + 3u) * 2u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1289 << " attribs[((y * gridSize + x) * 6u + 4u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n" 1290 << " attribs[((y * gridSize + x) * 6u + 5u) * 2u + 0u] = vec4(posX, posYp1, 0.0, 1.0);\n" 1291 << "\n" 1292 << " attribs[((y * gridSize + x) * 6u + 0u) * 2u + 1u] = color;\n" 1293 << " attribs[((y * gridSize + x) * 6u + 1u) * 2u + 1u] = color;\n" 1294 << " attribs[((y * gridSize + x) * 6u + 2u) * 2u + 1u] = color;\n" 1295 << " attribs[((y * gridSize + x) * 6u + 3u) * 2u + 1u] = color;\n" 1296 << " attribs[((y * gridSize + x) * 6u + 4u) * 2u + 1u] = color;\n" 1297 << " attribs[((y * gridSize + x) * 6u + 5u) * 2u + 1u] = color;\n" 1298 << " }\n"; 1299 } 1300 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1301 { 1302 buf << " if (gl_GlobalInvocationID.x < gridSize+1u && gl_GlobalInvocationID.y < gridSize+1u && gl_GlobalInvocationID.z == 0u) {\n" 1303 << " uint y = gl_GlobalInvocationID.x;\n" 1304 << " uint x = gl_GlobalInvocationID.y;\n" 1305 << " float posX = (float(x) / float(gridSize)) * 2.0 - 1.0;\n" 1306 << " float posY = (float(y) / float(gridSize)) * 2.0 - 1.0;\n" 1307 << "\n" 1308 << " attribs[(y * (gridSize+1u) + x) * 4u + 0u] = vec4(posX, posY, 0.0, 1.0);\n" 1309 << " attribs[(y * (gridSize+1u) + x) * 4u + 1u] = green;\n" 1310 << " attribs[(y * (gridSize+1u) + x) * 4u + 2u] = vec4(posX, posY, 0.0, 1.0);\n" 1311 << " attribs[(y * (gridSize+1u) + x) * 4u + 3u] = yellow;\n" 1312 << " }\n"; 1313 } 1314 1315 buf << "\n"; 1316 } 1317 1318 if (computeIndices) 1319 { 1320 buf << " // indices\n" 1321 << " if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && gl_GlobalInvocationID.z == 0u) {\n" 1322 << " uint y = gl_GlobalInvocationID.x;\n" 1323 << " uint x = gl_GlobalInvocationID.y;\n" 1324 << " uint color = ((x + y)%2u);\n" 1325 << "\n" 1326 << " indices[(y * gridSize + x) * 6u + 0u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1327 << " indices[(y * gridSize + x) * 6u + 1u] = ((y+1u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1328 << " indices[(y * gridSize + x) * 6u + 2u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1329 << " indices[(y * gridSize + x) * 6u + 3u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n" 1330 << " indices[(y * gridSize + x) * 6u + 4u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1331 << " indices[(y * gridSize + x) * 6u + 5u] = ((y+0u) * (gridSize+1u) + (x+1u)) * 2u + color;\n" 1332 << " }\n" 1333 << "\n"; 1334 } 1335 1336 buf << "}\n"; 1337 1338 return buf.str(); 1339} 1340 1341void ComputeShaderGeneratedCase::createDrawCommand (void) 1342{ 1343 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1344 const int triangleCount = m_gridSize * m_gridSize * 2; 1345 const deUint32 numDrawCallTris = triangleCount / m_numDrawCmds; 1346 1347 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1348 { 1349 std::vector<DrawArraysCommand> cmds; 1350 1351 for (int ndx = 0; ndx < m_numDrawCmds; ++ndx) 1352 { 1353 const deUint32 firstTri = ndx * numDrawCallTris; 1354 DrawArraysCommand data; 1355 1356 data.count = numDrawCallTris*3; 1357 data.primCount = 1; 1358 data.first = firstTri*3; 1359 data.reservedMustBeZero = 0; 1360 1361 cmds.push_back(data); 1362 } 1363 1364 DE_ASSERT((int)(sizeof(DrawArraysCommand)*cmds.size()) == m_numDrawCmds * m_commandSize); 1365 1366 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1367 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawArraysCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW); 1368 } 1369 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1370 { 1371 std::vector<DrawElementsCommand> cmds; 1372 1373 for (int ndx = 0; ndx < m_numDrawCmds; ++ndx) 1374 { 1375 const deUint32 firstTri = ndx * numDrawCallTris; 1376 DrawElementsCommand data; 1377 1378 data.count = numDrawCallTris*3; 1379 data.primCount = 1; 1380 data.firstIndex = firstTri*3; 1381 data.baseVertex = 0; 1382 data.reservedMustBeZero = 0; 1383 1384 cmds.push_back(data); 1385 } 1386 1387 DE_ASSERT((int)(sizeof(DrawElementsCommand)*cmds.size()) == m_numDrawCmds * m_commandSize); 1388 1389 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1390 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawElementsCommand)*cmds.size()), &cmds[0], GL_STATIC_DRAW); 1391 } 1392 else 1393 DE_ASSERT(false); 1394 1395 glu::checkError(gl.getError(), "create draw command", __FILE__, __LINE__); 1396} 1397 1398void ComputeShaderGeneratedCase::createDrawData (void) 1399{ 1400 const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f); 1401 const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); 1402 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1403 1404 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1405 { 1406 // Store elements in the order they are drawn. Interleave color. 1407 std::vector<tcu::Vec4> buffer(m_gridSize*m_gridSize*6*2); 1408 1409 DE_ASSERT(buffer.size() == calcDrawBufferSize()); 1410 1411 for (int y = 0; y < m_gridSize; ++y) 1412 for (int x = 0; x < m_gridSize; ++x) 1413 { 1414 const float posX = ((float)x / (float)m_gridSize) * 2.0f - 1.0f; 1415 const float posY = ((float)y / (float)m_gridSize) * 2.0f - 1.0f; 1416 const float cellSize = 2.0f / (float)m_gridSize; 1417 const tcu::Vec4& color = ((x + y)%2) ? (yellow) : (green); 1418 1419 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1420 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 0] = tcu::Vec4(posX + cellSize, posY, 0.0f, 1.0f); 1421 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f); 1422 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1423 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 0] = tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f); 1424 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 0] = tcu::Vec4(posX, posY + cellSize, 0.0f, 1.0f); 1425 1426 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 1] = color; 1427 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 1] = color; 1428 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 1] = color; 1429 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 1] = color; 1430 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 1] = color; 1431 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 1] = color; 1432 } 1433 1434 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1435 gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW); 1436 } 1437 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1438 { 1439 // Elements are indexed by index buffer. Interleave color. Two vertices per position since 2 colors 1440 1441 std::vector<tcu::Vec4> buffer((m_gridSize+1)*(m_gridSize+1)*4); 1442 1443 DE_ASSERT(buffer.size() == calcDrawBufferSize()); 1444 1445 for (int y = 0; y < m_gridSize+1; ++y) 1446 for (int x = 0; x < m_gridSize+1; ++x) 1447 { 1448 const float posX = ((float)x / (float)m_gridSize) * 2.0f - 1.0f; 1449 const float posY = ((float)y / (float)m_gridSize) * 2.0f - 1.0f; 1450 1451 buffer[(y * (m_gridSize+1) + x) * 4 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1452 buffer[(y * (m_gridSize+1) + x) * 4 + 1] = green; 1453 buffer[(y * (m_gridSize+1) + x) * 4 + 2] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1454 buffer[(y * (m_gridSize+1) + x) * 4 + 3] = yellow; 1455 } 1456 1457 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1458 gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW); 1459 } 1460 else 1461 DE_ASSERT(false); 1462 1463 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1464} 1465 1466void ComputeShaderGeneratedCase::createDrawIndices (void) 1467{ 1468 DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1469 1470 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1471 std::vector<deUint32> buffer (m_gridSize*m_gridSize*6); 1472 1473 DE_ASSERT(buffer.size() == calcIndexBufferSize()); 1474 1475 for (int y = 0; y < m_gridSize; ++y) 1476 for (int x = 0; x < m_gridSize; ++x) 1477 { 1478 const int color = ((x + y)%2); 1479 1480 buffer[(y * m_gridSize + x) * 6 + 0] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color; 1481 buffer[(y * m_gridSize + x) * 6 + 1] = ((y+1) * (m_gridSize+1) + (x+0)) * 2 + color; 1482 buffer[(y * m_gridSize + x) * 6 + 2] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color; 1483 buffer[(y * m_gridSize + x) * 6 + 3] = ((y+0) * (m_gridSize+1) + (x+0)) * 2 + color; 1484 buffer[(y * m_gridSize + x) * 6 + 4] = ((y+1) * (m_gridSize+1) + (x+1)) * 2 + color; 1485 buffer[(y * m_gridSize + x) * 6 + 5] = ((y+0) * (m_gridSize+1) + (x+1)) * 2 + color; 1486 } 1487 1488 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID); 1489 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(buffer.size() * sizeof(deUint32)), &buffer[0], GL_STATIC_DRAW); 1490 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1491} 1492 1493void ComputeShaderGeneratedCase::renderTo (tcu::Surface& dst) 1494{ 1495 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1496 const deInt32 positionLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_position"); 1497 const deInt32 colorLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_color"); 1498 deUint32 vaoID = 0; 1499 1500 gl.genVertexArrays(1, &vaoID); 1501 gl.bindVertexArray(vaoID); 1502 1503 // Setup buffers 1504 1505 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID); 1506 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float), DE_NULL); 1507 gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float), ((const deUint8*)DE_NULL) + 4*sizeof(float)); 1508 gl.enableVertexAttribArray(positionLoc); 1509 gl.enableVertexAttribArray(colorLoc); 1510 1511 DE_ASSERT(positionLoc != -1); 1512 DE_ASSERT(colorLoc != -1); 1513 1514 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1515 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID); 1516 1517 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID); 1518 1519 // draw 1520 1521 gl.clearColor(0, 0, 0, 1); 1522 gl.clear(GL_COLOR_BUFFER_BIT); 1523 gl.viewport(0, 0, dst.getWidth(), dst.getHeight()); 1524 1525 gl.useProgram(m_shaderProgram->getProgram()); 1526 for (int drawCmdNdx = 0; drawCmdNdx < m_numDrawCmds; ++drawCmdNdx) 1527 { 1528 const void* offset = ((deUint8*)DE_NULL) + drawCmdNdx*m_commandSize; 1529 1530 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1531 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset); 1532 else if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1533 gl.drawArraysIndirect(GL_TRIANGLES, offset); 1534 else 1535 DE_ASSERT(DE_FALSE); 1536 } 1537 gl.useProgram(0); 1538 1539 // free 1540 1541 gl.deleteVertexArrays(1, &vaoID); 1542 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1543 1544 gl.finish(); 1545 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1546 1547 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 1548 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 1549} 1550 1551deUint32 ComputeShaderGeneratedCase::calcDrawBufferSize (void) const 1552{ 1553 // returns size in "vec4"s 1554 if (m_drawMethod == DRAWMETHOD_DRAWARRAYS) 1555 return m_gridSize*m_gridSize*6*2; 1556 else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1557 return (m_gridSize+1)*(m_gridSize+1)*4; 1558 else 1559 DE_ASSERT(DE_FALSE); 1560 1561 return 0; 1562} 1563 1564deUint32 ComputeShaderGeneratedCase::calcIndexBufferSize (void) const 1565{ 1566 if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) 1567 return m_gridSize*m_gridSize*6; 1568 else 1569 return 0; 1570} 1571 1572class ComputeShaderGeneratedCombinedCase : public ComputeShaderGeneratedCase 1573{ 1574public: 1575 ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls); 1576 ~ComputeShaderGeneratedCombinedCase (void); 1577 1578 void init (void); 1579 void deinit (void); 1580 1581private: 1582 void runComputeShader (void); 1583 1584 glu::ShaderProgram* m_computeProgram; 1585}; 1586 1587ComputeShaderGeneratedCombinedCase::ComputeShaderGeneratedCombinedCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls) 1588 : ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls) 1589 , m_computeProgram (DE_NULL) 1590{ 1591} 1592 1593ComputeShaderGeneratedCombinedCase::~ComputeShaderGeneratedCombinedCase (void) 1594{ 1595 deinit(); 1596} 1597 1598void ComputeShaderGeneratedCombinedCase::init (void) 1599{ 1600 // generate compute shader 1601 1602 m_computeProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource(m_computeCmd, m_computeData, m_computeIndices))); 1603 m_testCtx.getLog() << *m_computeProgram; 1604 1605 if (!m_computeProgram->isOk()) 1606 throw tcu::TestError("Failed to compile compute shader."); 1607 1608 // init parent 1609 ComputeShaderGeneratedCase::init(); 1610} 1611 1612void ComputeShaderGeneratedCombinedCase::deinit (void) 1613{ 1614 // deinit parent 1615 ComputeShaderGeneratedCase::deinit(); 1616 1617 if (m_computeProgram) 1618 { 1619 delete m_computeProgram; 1620 m_computeProgram = DE_NULL; 1621 } 1622} 1623 1624void ComputeShaderGeneratedCombinedCase::runComputeShader (void) 1625{ 1626 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1627 const bool indexed = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1628 const tcu::IVec3 nullSize (0, 0, 0); 1629 const tcu::IVec3 commandDispatchSize = (m_computeCmd) ? (tcu::IVec3(m_numDrawCmds, 1, 1)) : (nullSize); 1630 const tcu::IVec3 drawElementsDataBufferDispatchSize = (m_computeData) ? (tcu::IVec3(m_gridSize+1, m_gridSize+1, 1)) : (nullSize); 1631 const tcu::IVec3 drawArraysDataBufferDispatchSize = (m_computeData) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize); 1632 const tcu::IVec3 indexBufferDispatchSize = (m_computeIndices && indexed) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize); 1633 1634 const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize); 1635 const tcu::IVec3 dispatchSize = tcu::max(tcu::max(commandDispatchSize, dataBufferDispatchSize), indexBufferDispatchSize); 1636 1637 gl.useProgram(m_computeProgram->getProgram()); 1638 glu::checkError(gl.getError(), "use compute shader", __FILE__, __LINE__); 1639 1640 // setup buffers 1641 1642 if (m_computeCmd) 1643 { 1644 const int bindingPoint = 0; 1645 const int bufferSize = m_commandSize * m_numDrawCmds; 1646 1647 m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1648 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID); 1649 1650 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1651 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1652 } 1653 1654 if (m_computeData) 1655 { 1656 const int bindingPoint = (m_computeCmd) ? (1) : (0); 1657 const int bufferSize = (int)(calcDrawBufferSize()*sizeof(tcu::Vec4)); 1658 1659 m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1660 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID); 1661 1662 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1663 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1664 } 1665 1666 if (m_computeIndices) 1667 { 1668 const int bindingPoint = (m_computeCmd && m_computeData) ? (2) : (m_computeCmd || m_computeData) ? (1) : (0); 1669 const int bufferSize = (int)(calcIndexBufferSize()*sizeof(deUint32)); 1670 1671 m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1672 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID); 1673 1674 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1675 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1676 } 1677 1678 glu::checkError(gl.getError(), "setup buffers", __FILE__, __LINE__); 1679 1680 // calculate 1681 1682 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching compute, size = " << dispatchSize << tcu::TestLog::EndMessage; 1683 gl.dispatchCompute(dispatchSize.x(), dispatchSize.y(), dispatchSize.z()); 1684 1685 glu::checkError(gl.getError(), "calculate", __FILE__, __LINE__); 1686} 1687 1688class ComputeShaderGeneratedSeparateCase : public ComputeShaderGeneratedCase 1689{ 1690public: 1691 ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls); 1692 ~ComputeShaderGeneratedSeparateCase (void); 1693 1694 void init (void); 1695 void deinit (void); 1696 1697private: 1698 std::string genCmdComputeSource (void); 1699 std::string genDataComputeSource (void); 1700 std::string genIndexComputeSource (void); 1701 void runComputeShader (void); 1702 1703 glu::ShaderProgram* m_computeCmdProgram; 1704 glu::ShaderProgram* m_computeDataProgram; 1705 glu::ShaderProgram* m_computeIndicesProgram; 1706}; 1707 1708ComputeShaderGeneratedSeparateCase::ComputeShaderGeneratedSeparateCase (Context& context, const char* name, const char* desc, DrawMethod method, bool computeCmd, bool computeData, bool computeIndices, int gridSize, int numDrawCalls) 1709 : ComputeShaderGeneratedCase (context, name, desc, method, computeCmd, computeData, computeIndices, gridSize, numDrawCalls) 1710 , m_computeCmdProgram (DE_NULL) 1711 , m_computeDataProgram (DE_NULL) 1712 , m_computeIndicesProgram (DE_NULL) 1713{ 1714} 1715 1716ComputeShaderGeneratedSeparateCase::~ComputeShaderGeneratedSeparateCase (void) 1717{ 1718 deinit(); 1719} 1720 1721void ComputeShaderGeneratedSeparateCase::init (void) 1722{ 1723 // generate cmd compute shader 1724 1725 if (m_computeCmd) 1726 { 1727 m_computeCmdProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genCmdComputeSource())); 1728 m_testCtx.getLog() << *m_computeCmdProgram; 1729 1730 if (!m_computeCmdProgram->isOk()) 1731 throw tcu::TestError("Failed to compile command compute shader."); 1732 } 1733 1734 // generate data compute shader 1735 1736 if (m_computeData) 1737 { 1738 m_computeDataProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genDataComputeSource())); 1739 m_testCtx.getLog() << *m_computeDataProgram; 1740 1741 if (!m_computeDataProgram->isOk()) 1742 throw tcu::TestError("Failed to compile data compute shader."); 1743 } 1744 1745 // generate index compute shader 1746 1747 if (m_computeIndices) 1748 { 1749 m_computeIndicesProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genIndexComputeSource())); 1750 m_testCtx.getLog() << *m_computeIndicesProgram; 1751 1752 if (!m_computeIndicesProgram->isOk()) 1753 throw tcu::TestError("Failed to compile data compute shader."); 1754 } 1755 1756 // init parent 1757 ComputeShaderGeneratedCase::init(); 1758} 1759 1760void ComputeShaderGeneratedSeparateCase::deinit (void) 1761{ 1762 // deinit parent 1763 ComputeShaderGeneratedCase::deinit(); 1764 1765 if (m_computeCmdProgram) 1766 { 1767 delete m_computeCmdProgram; 1768 m_computeCmdProgram = DE_NULL; 1769 } 1770 if (m_computeDataProgram) 1771 { 1772 delete m_computeDataProgram; 1773 m_computeDataProgram = DE_NULL; 1774 } 1775 if (m_computeIndicesProgram) 1776 { 1777 delete m_computeIndicesProgram; 1778 m_computeIndicesProgram = DE_NULL; 1779 } 1780} 1781 1782std::string ComputeShaderGeneratedSeparateCase::genCmdComputeSource (void) 1783{ 1784 return ComputeShaderGeneratedCase::genComputeSource(true, false, false); 1785} 1786 1787std::string ComputeShaderGeneratedSeparateCase::genDataComputeSource (void) 1788{ 1789 return ComputeShaderGeneratedCase::genComputeSource(false, true, false); 1790} 1791 1792std::string ComputeShaderGeneratedSeparateCase::genIndexComputeSource (void) 1793{ 1794 return ComputeShaderGeneratedCase::genComputeSource(false, false, true); 1795} 1796 1797void ComputeShaderGeneratedSeparateCase::runComputeShader (void) 1798{ 1799 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1800 1801 // Compute command 1802 1803 if (m_computeCmd) 1804 { 1805 const int bindingPoint = 0; 1806 const tcu::IVec3 commandDispatchSize (m_numDrawCmds, 1, 1); 1807 const int bufferSize = m_commandSize * m_numDrawCmds; 1808 1809 gl.useProgram(m_computeCmdProgram->getProgram()); 1810 1811 // setup buffers 1812 1813 m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1814 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID); 1815 1816 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1817 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1818 1819 // calculate 1820 1821 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching command compute, size = " << commandDispatchSize << tcu::TestLog::EndMessage; 1822 gl.dispatchCompute(commandDispatchSize.x(), commandDispatchSize.y(), commandDispatchSize.z()); 1823 1824 glu::checkError(gl.getError(), "calculate cmd", __FILE__, __LINE__); 1825 } 1826 1827 // Compute data 1828 1829 if (m_computeData) 1830 { 1831 const int bindingPoint = 0; 1832 const tcu::IVec3 drawElementsDataBufferDispatchSize (m_gridSize+1, m_gridSize+1, 1); 1833 const tcu::IVec3 drawArraysDataBufferDispatchSize (m_gridSize, m_gridSize, 1); 1834 const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ? (drawElementsDataBufferDispatchSize) : (drawArraysDataBufferDispatchSize); 1835 const int bufferSize = (int)(calcDrawBufferSize()*sizeof(tcu::Vec4)); 1836 1837 gl.useProgram(m_computeDataProgram->getProgram()); 1838 1839 // setup buffers 1840 1841 m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1842 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID); 1843 1844 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1845 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1846 1847 // calculate 1848 1849 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching data compute, size = " << dataBufferDispatchSize << tcu::TestLog::EndMessage; 1850 gl.dispatchCompute(dataBufferDispatchSize.x(), dataBufferDispatchSize.y(), dataBufferDispatchSize.z()); 1851 1852 glu::checkError(gl.getError(), "calculate data", __FILE__, __LINE__); 1853 } 1854 1855 // Compute indices 1856 1857 if (m_computeIndices) 1858 { 1859 const int bindingPoint = 0; 1860 const tcu::IVec3 indexBufferDispatchSize (m_gridSize, m_gridSize, 1); 1861 const int bufferSize = (int)(calcIndexBufferSize()*sizeof(deUint32)); 1862 1863 DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS); 1864 1865 gl.useProgram(m_computeIndicesProgram->getProgram()); 1866 1867 // setup buffers 1868 1869 m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint << tcu::TestLog::EndMessage; 1870 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID); 1871 1872 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size " << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage; 1873 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW); 1874 1875 // calculate 1876 1877 m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching index compute, size = " << indexBufferDispatchSize << tcu::TestLog::EndMessage; 1878 gl.dispatchCompute(indexBufferDispatchSize.x(), indexBufferDispatchSize.y(), indexBufferDispatchSize.z()); 1879 1880 glu::checkError(gl.getError(), "calculate indices", __FILE__, __LINE__); 1881 } 1882 1883 glu::checkError(gl.getError(), "post dispatch", __FILE__, __LINE__); 1884} 1885 1886class ComputeShaderGeneratedGroup : public TestCaseGroup 1887{ 1888public: 1889 ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr); 1890 ~ComputeShaderGeneratedGroup (void); 1891 1892 void init (void); 1893}; 1894 1895ComputeShaderGeneratedGroup::ComputeShaderGeneratedGroup (Context& context, const char* name, const char* descr) 1896 : TestCaseGroup (context, name, descr) 1897{ 1898} 1899 1900ComputeShaderGeneratedGroup::~ComputeShaderGeneratedGroup (void) 1901{ 1902} 1903 1904void ComputeShaderGeneratedGroup::init (void) 1905{ 1906 const int gridSize = 8; 1907 tcu::TestCaseGroup* const separateGroup = new tcu::TestCaseGroup(m_testCtx, "separate", "Use separate compute shaders for each buffer"); 1908 tcu::TestCaseGroup* const combinedGroup = new tcu::TestCaseGroup(m_testCtx, "combined", "Use combined compute shader for all buffers"); 1909 tcu::TestCaseGroup* const largeGroup = new tcu::TestCaseGroup(m_testCtx, "large", "Draw shapes with large buffers"); 1910 1911 this->addChild(separateGroup); 1912 this->addChild(combinedGroup); 1913 this->addChild(largeGroup); 1914 1915 // .separate 1916 { 1917 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd", "Command from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, false, false, gridSize, 1)); 1918 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_data", "Data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false, true, false, gridSize, 1)); 1919 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1)); 1920 1921 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd", "Command from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, false, gridSize, 1)); 1922 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data", "Data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, false, gridSize, 1)); 1923 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_indices", "Indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, false, true, gridSize, 1)); 1924 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1)); 1925 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1)); 1926 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1)); 1927 separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1)); 1928 } 1929 1930 // .combined 1931 { 1932 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1)); 1933 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1)); 1934 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1)); 1935 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1)); 1936 combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader", ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1)); 1937 } 1938 1939 // .large 1940 { 1941 struct TestSpec 1942 { 1943 int gridSize; 1944 int numDrawCommands; 1945 }; 1946 struct TestMethod 1947 { 1948 ComputeShaderGeneratedCase::DrawMethod method; 1949 bool separateCompute; 1950 }; 1951 1952 static const TestSpec specs[] = 1953 { 1954 { 100, 1 }, // !< drawArrays array size ~ 1.9 MB 1955 { 200, 1 }, // !< drawArrays array size ~ 7.7 MB 1956 { 500, 1 }, // !< drawArrays array size ~ 48 MB 1957 { 1000, 1 }, // !< drawArrays array size ~ 192 MB 1958 { 1200, 1 }, // !< drawArrays array size ~ 277 MB 1959 { 1500, 1 }, // !< drawArrays array size ~ 430 MB 1960 1961 { 100, 8 }, // !< drawArrays array size ~ 1.9 MB 1962 { 200, 8 }, // !< drawArrays array size ~ 7.7 MB 1963 { 500, 8 }, // !< drawArrays array size ~ 48 MB 1964 { 1000, 8 }, // !< drawArrays array size ~ 192 MB 1965 { 1200, 8 }, // !< drawArrays array size ~ 277 MB 1966 { 1500, 8 }, // !< drawArrays array size ~ 430 MB 1967 1968 { 100, 200 }, // !< 50 cells per draw call 1969 { 200, 800 }, // !< 50 cells per draw call 1970 { 500, 2500 }, // !< 100 cells per draw call 1971 { 1000, 5000 }, // !< 250 cells per draw call 1972 }; 1973 static const TestMethod methods[] = 1974 { 1975 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true }, 1976 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false }, 1977 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true }, 1978 { ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false }, 1979 }; 1980 1981 for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(methods); ++methodNdx) 1982 for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); ++specNdx) 1983 { 1984 const std::string name = std::string("") 1985 + ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays") : ("drawelements")) 1986 + ((methods[methodNdx].separateCompute) ? ("_separate") : ("_combined")) 1987 + "_grid_" + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize) 1988 + "_drawcount_" + de::toString(specs[specNdx].numDrawCommands); 1989 1990 const std::string desc = std::string("Draw grid with ") 1991 + ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ? ("drawarrays indirect") : ("drawelements indirect")) 1992 + " calculating buffers in " + ((methods[methodNdx].separateCompute) ? ("separate") : ("combined")) + " compute shader." 1993 + " Grid size is " + de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize) 1994 + ", draw count is " + de::toString(specs[specNdx].numDrawCommands); 1995 1996 const bool computeIndices = (methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS); 1997 1998 if (methods[methodNdx].separateCompute) 1999 largeGroup->addChild(new ComputeShaderGeneratedSeparateCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands)); 2000 else 2001 largeGroup->addChild(new ComputeShaderGeneratedCombinedCase(m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices, specs[specNdx].gridSize, specs[specNdx].numDrawCommands)); 2002 } 2003 } 2004} 2005 2006class RandomGroup : public TestCaseGroup 2007{ 2008public: 2009 RandomGroup (Context& context, const char* name, const char* descr); 2010 ~RandomGroup (void); 2011 2012 void init (void); 2013}; 2014 2015template <int SIZE> 2016struct UniformWeightArray 2017{ 2018 float weights[SIZE]; 2019 2020 UniformWeightArray (void) 2021 { 2022 for (int i=0; i<SIZE; ++i) 2023 weights[i] = 1.0f; 2024 } 2025}; 2026 2027RandomGroup::RandomGroup (Context& context, const char* name, const char* descr) 2028 : TestCaseGroup (context, name, descr) 2029{ 2030} 2031 2032RandomGroup::~RandomGroup (void) 2033{ 2034} 2035 2036void RandomGroup::init (void) 2037{ 2038 const int numAttempts = 100; 2039 2040 const int attribCounts[] = { 1, 2, 5 }; 2041 const float attribWeights[] = { 30, 10, 1 }; 2042 const int primitiveCounts[] = { 1, 5, 64 }; 2043 const float primitiveCountWeights[] = { 20, 10, 1 }; 2044 const int indexOffsets[] = { 0, 7, 13 }; 2045 const float indexOffsetWeights[] = { 20, 20, 1 }; 2046 const int firsts[] = { 0, 7, 13 }; 2047 const float firstWeights[] = { 20, 20, 1 }; 2048 2049 const int instanceCounts[] = { 1, 2, 16, 17 }; 2050 const float instanceWeights[] = { 20, 10, 5, 1 }; 2051 const int indexMins[] = { 0, 1, 3, 8 }; 2052 const int indexMaxs[] = { 4, 8, 128, 257 }; 2053 const float indexWeights[] = { 50, 50, 50, 50 }; 2054 const int offsets[] = { 0, 1, 5, 12 }; 2055 const float offsetWeights[] = { 50, 10, 10, 10 }; 2056 const int strides[] = { 0, 7, 16, 17 }; 2057 const float strideWeights[] = { 50, 10, 10, 10 }; 2058 const int instanceDivisors[] = { 0, 1, 3, 129 }; 2059 const float instanceDivisorWeights[]= { 70, 30, 10, 10 }; 2060 2061 const int indirectOffsets[] = { 0, 1, 2 }; 2062 const float indirectOffsetWeigths[] = { 2, 1, 1 }; 2063 const int baseVertices[] = { 0, 1, -2, 4, 3 }; 2064 const float baseVertexWeigths[] = { 4, 1, 1, 1, 1 }; 2065 2066 gls::DrawTestSpec::Primitive primitives[] = 2067 { 2068 gls::DrawTestSpec::PRIMITIVE_POINTS, 2069 gls::DrawTestSpec::PRIMITIVE_TRIANGLES, 2070 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, 2071 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP, 2072 gls::DrawTestSpec::PRIMITIVE_LINES, 2073 gls::DrawTestSpec::PRIMITIVE_LINE_STRIP, 2074 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP 2075 }; 2076 const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights; 2077 2078 gls::DrawTestSpec::DrawMethod drawMethods[] = 2079 { 2080 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT, 2081 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT, 2082 }; 2083 const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights; 2084 2085 gls::DrawTestSpec::IndexType indexTypes[] = 2086 { 2087 gls::DrawTestSpec::INDEXTYPE_BYTE, 2088 gls::DrawTestSpec::INDEXTYPE_SHORT, 2089 gls::DrawTestSpec::INDEXTYPE_INT, 2090 }; 2091 const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights; 2092 2093 gls::DrawTestSpec::InputType inputTypes[] = 2094 { 2095 gls::DrawTestSpec::INPUTTYPE_FLOAT, 2096 gls::DrawTestSpec::INPUTTYPE_FIXED, 2097 gls::DrawTestSpec::INPUTTYPE_BYTE, 2098 gls::DrawTestSpec::INPUTTYPE_SHORT, 2099 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE, 2100 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT, 2101 gls::DrawTestSpec::INPUTTYPE_INT, 2102 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, 2103 gls::DrawTestSpec::INPUTTYPE_HALF, 2104 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2105 gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10, 2106 }; 2107 const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights; 2108 2109 gls::DrawTestSpec::OutputType outputTypes[] = 2110 { 2111 gls::DrawTestSpec::OUTPUTTYPE_FLOAT, 2112 gls::DrawTestSpec::OUTPUTTYPE_VEC2, 2113 gls::DrawTestSpec::OUTPUTTYPE_VEC3, 2114 gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2115 gls::DrawTestSpec::OUTPUTTYPE_INT, 2116 gls::DrawTestSpec::OUTPUTTYPE_UINT, 2117 gls::DrawTestSpec::OUTPUTTYPE_IVEC2, 2118 gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 2119 gls::DrawTestSpec::OUTPUTTYPE_IVEC4, 2120 gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 2121 gls::DrawTestSpec::OUTPUTTYPE_UVEC3, 2122 gls::DrawTestSpec::OUTPUTTYPE_UVEC4, 2123 }; 2124 const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights; 2125 2126 gls::DrawTestSpec::Usage usages[] = 2127 { 2128 gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, 2129 gls::DrawTestSpec::USAGE_STATIC_DRAW, 2130 gls::DrawTestSpec::USAGE_STREAM_DRAW, 2131 gls::DrawTestSpec::USAGE_STREAM_READ, 2132 gls::DrawTestSpec::USAGE_STREAM_COPY, 2133 gls::DrawTestSpec::USAGE_STATIC_READ, 2134 gls::DrawTestSpec::USAGE_STATIC_COPY, 2135 gls::DrawTestSpec::USAGE_DYNAMIC_READ, 2136 gls::DrawTestSpec::USAGE_DYNAMIC_COPY, 2137 }; 2138 const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights; 2139 2140 std::set<deUint32> insertedHashes; 2141 size_t insertedCount = 0; 2142 2143 for (int ndx = 0; ndx < numAttempts; ++ndx) 2144 { 2145 de::Random random(0xc551393 + ndx); // random does not depend on previous cases 2146 2147 int attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights); 2148 int drawCommandSize; 2149 gls::DrawTestSpec spec; 2150 2151 spec.apiType = glu::ApiType::es(3,1); 2152 spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive> (DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights); 2153 spec.primitiveCount = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights); 2154 spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod> (DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights); 2155 2156 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT) 2157 drawCommandSize = sizeof(deUint32[4]); 2158 else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2159 drawCommandSize = sizeof(deUint32[5]); 2160 else 2161 { 2162 DE_ASSERT(DE_FALSE); 2163 return; 2164 } 2165 2166 spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType> (DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights); 2167 spec.indexPointerOffset = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights); 2168 spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; 2169 spec.first = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(firsts), DE_ARRAY_END(firsts), firstWeights); 2170 spec.indexMin = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexMins), DE_ARRAY_END(indexMins), indexWeights); 2171 spec.indexMax = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexMaxs), DE_ARRAY_END(indexMaxs), indexWeights); 2172 spec.instanceCount = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(instanceCounts), DE_ARRAY_END(instanceCounts), instanceWeights); 2173 spec.indirectOffset = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indirectOffsets), DE_ARRAY_END(indirectOffsets), indirectOffsetWeigths) * drawCommandSize; 2174 spec.baseVertex = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(baseVertices), DE_ARRAY_END(baseVertices), baseVertexWeigths); 2175 2176 // check spec is legal 2177 if (!spec.valid()) 2178 continue; 2179 2180 for (int attrNdx = 0; attrNdx < attributeCount;) 2181 { 2182 bool valid; 2183 gls::DrawTestSpec::AttributeSpec attribSpec; 2184 2185 attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType> (DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights); 2186 attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType> (DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights); 2187 attribSpec.storage = gls::DrawTestSpec::STORAGE_BUFFER; 2188 attribSpec.usage = random.chooseWeighted<gls::DrawTestSpec::Usage> (DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights); 2189 attribSpec.componentCount = random.getInt(1, 4); 2190 attribSpec.offset = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights); 2191 attribSpec.stride = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights); 2192 attribSpec.normalize = random.getBool(); 2193 attribSpec.instanceDivisor = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights); 2194 attribSpec.useDefaultAttribute = random.getBool(); 2195 2196 // check spec is legal 2197 valid = attribSpec.valid(spec.apiType); 2198 2199 // we do not want interleaved elements. (Might result in some weird floating point values) 2200 if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride) 2201 valid = false; 2202 2203 // try again if not valid 2204 if (valid) 2205 { 2206 spec.attribs.push_back(attribSpec); 2207 ++attrNdx; 2208 } 2209 } 2210 2211 // Do not collapse all vertex positions to a single positions 2212 if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2213 spec.attribs[0].instanceDivisor = 0; 2214 2215 // Is render result meaningful? 2216 { 2217 // Only one vertex 2218 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2219 continue; 2220 if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 2221 continue; 2222 2223 // Triangle only on one axis 2224 if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP) 2225 { 2226 if (spec.attribs[0].componentCount == 1) 2227 continue; 2228 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT) 2229 continue; 2230 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2) 2231 continue; 2232 } 2233 } 2234 2235 // Add case 2236 { 2237 deUint32 hash = spec.hash(); 2238 for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx) 2239 hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash(); 2240 2241 if (insertedHashes.find(hash) == insertedHashes.end()) 2242 { 2243 // Only aligned cases 2244 if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET && 2245 spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 2246 this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str())); 2247 insertedHashes.insert(hash); 2248 2249 ++insertedCount; 2250 } 2251 } 2252 } 2253} 2254 2255class BadCommandBufferCase : public TestCase 2256{ 2257public: 2258 enum 2259 { 2260 CommandSize = 20 2261 }; 2262 2263 BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 m_expectedError); 2264 ~BadCommandBufferCase (void); 2265 2266 IterateResult iterate (void); 2267 2268private: 2269 const deUint32 m_alignment; 2270 const deUint32 m_bufferSize; 2271 const bool m_writeCommandToBuffer; 2272 const deUint32 m_expectedError; 2273}; 2274 2275BadCommandBufferCase::BadCommandBufferCase (Context& context, const char* name, const char* desc, deUint32 alignment, deUint32 bufferSize, bool writeCommandToBuffer, deUint32 expectedError) 2276 : TestCase (context, name, desc) 2277 , m_alignment (alignment) 2278 , m_bufferSize (bufferSize) 2279 , m_writeCommandToBuffer (writeCommandToBuffer) 2280 , m_expectedError (expectedError) 2281{ 2282} 2283 2284BadCommandBufferCase::~BadCommandBufferCase (void) 2285{ 2286} 2287 2288BadCommandBufferCase::IterateResult BadCommandBufferCase::iterate (void) 2289{ 2290 const tcu::Vec4 vertexPositions[] = 2291 { 2292 tcu::Vec4(0, 0, 0, 1), 2293 tcu::Vec4(1, 0, 0, 1), 2294 tcu::Vec4(0, 1, 0, 1), 2295 }; 2296 2297 const deUint16 indices[] = 2298 { 2299 0, 2, 1, 2300 }; 2301 2302 DE_STATIC_ASSERT(CommandSize == sizeof(DrawElementsCommand)); 2303 2304 sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2305 2306 deUint32 vaoID = 0; 2307 deUint32 positionBuf = 0; 2308 deUint32 indexBuf = 0; 2309 deUint32 drawIndirectBuf= 0; 2310 deUint32 error; 2311 2312 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2313 deUint32 programID = program.getProgram(); 2314 deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2315 2316 DrawElementsCommand drawCommand; 2317 drawCommand.count = 3; 2318 drawCommand.primCount = 1; 2319 drawCommand.firstIndex = 0; 2320 drawCommand.baseVertex = 0; 2321 drawCommand.reservedMustBeZero = 0; 2322 2323 std::vector<deInt8> drawCommandBuffer; 2324 drawCommandBuffer.resize(m_bufferSize); 2325 2326 deMemset(&drawCommandBuffer[0], 0, (int)drawCommandBuffer.size()); 2327 2328 if (m_writeCommandToBuffer) 2329 { 2330 DE_ASSERT(drawCommandBuffer.size() >= sizeof(drawCommand) + m_alignment); 2331 deMemcpy(&drawCommandBuffer[m_alignment], &drawCommand, sizeof(drawCommand)); 2332 } 2333 2334 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2335 gl.genVertexArrays(1, &vaoID); 2336 gl.bindVertexArray(vaoID); 2337 2338 gl.genBuffers(1, &positionBuf); 2339 gl.bindBuffer(GL_ARRAY_BUFFER, positionBuf); 2340 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2341 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2342 gl.vertexAttribDivisor(posLocation, 0); 2343 gl.enableVertexAttribArray(posLocation); 2344 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2345 2346 gl.genBuffers(1, &indexBuf); 2347 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf); 2348 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2349 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2350 2351 gl.genBuffers(1, &drawIndirectBuf); 2352 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf); 2353 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, drawCommandBuffer.size(), &drawCommandBuffer[0], GL_STATIC_DRAW); 2354 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2355 2356 gl.viewport(0, 0, 1, 1); 2357 2358 gl.useProgram(programID); 2359 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(deUintptr)m_alignment); 2360 2361 error = gl.getError(); 2362 2363 gl.useProgram(0); 2364 2365 gl.deleteBuffers(1, &drawIndirectBuf); 2366 gl.deleteBuffers(1, &indexBuf); 2367 gl.deleteBuffers(1, &positionBuf); 2368 gl.deleteVertexArrays(1, &vaoID); 2369 2370 m_testCtx.getLog() << tcu::TestLog::Message << "drawElementsIndirect generated " << glu::getErrorStr(error) << ", expecting " << glu::getErrorStr(m_expectedError) << "." << tcu::TestLog::EndMessage; 2371 2372 if (error == m_expectedError) 2373 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2374 else 2375 { 2376 m_testCtx.getLog() << tcu::TestLog::Message << "\tUnexpected error." << tcu::TestLog::EndMessage; 2377 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2378 } 2379 2380 return STOP; 2381} 2382 2383class BadAlignmentCase : public BadCommandBufferCase 2384{ 2385public: 2386 BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment); 2387 ~BadAlignmentCase (void); 2388}; 2389 2390BadAlignmentCase::BadAlignmentCase (Context& context, const char* name, const char* desc, deUint32 alignment) 2391 : BadCommandBufferCase(context, name, desc, alignment, CommandSize+alignment, true, GL_INVALID_VALUE) 2392{ 2393} 2394 2395BadAlignmentCase::~BadAlignmentCase (void) 2396{ 2397} 2398 2399class BadBufferRangeCase : public BadCommandBufferCase 2400{ 2401public: 2402 BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset); 2403 ~BadBufferRangeCase (void); 2404}; 2405 2406BadBufferRangeCase::BadBufferRangeCase (Context& context, const char* name, const char* desc, deUint32 offset) 2407 : BadCommandBufferCase(context, name, desc, offset, CommandSize, false, GL_INVALID_OPERATION) 2408{ 2409} 2410 2411BadBufferRangeCase::~BadBufferRangeCase (void) 2412{ 2413} 2414 2415class BadStateCase : public TestCase 2416{ 2417public: 2418 enum CaseType 2419 { 2420 CASE_CLIENT_BUFFER_VERTEXATTR = 0, 2421 CASE_CLIENT_BUFFER_COMMAND, 2422 CASE_DEFAULT_VAO, 2423 2424 CASE_CLIENT_LAST 2425 }; 2426 2427 BadStateCase (Context& context, const char* name, const char* desc, CaseType type); 2428 ~BadStateCase (void); 2429 2430 void init (void); 2431 void deinit (void); 2432 IterateResult iterate (void); 2433 2434private: 2435 const CaseType m_caseType; 2436}; 2437 2438BadStateCase::BadStateCase (Context& context, const char* name, const char* desc, CaseType type) 2439 : TestCase (context, name, desc) 2440 , m_caseType (type) 2441{ 2442 DE_ASSERT(type < CASE_CLIENT_LAST); 2443} 2444 2445BadStateCase::~BadStateCase (void) 2446{ 2447 deinit(); 2448} 2449 2450void BadStateCase::init (void) 2451{ 2452} 2453 2454void BadStateCase::deinit (void) 2455{ 2456} 2457 2458BadStateCase::IterateResult BadStateCase::iterate (void) 2459{ 2460 const tcu::Vec4 vertexPositions[] = 2461 { 2462 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), 2463 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 2464 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 2465 }; 2466 2467 const deUint16 indices[] = 2468 { 2469 0, 2, 1, 2470 }; 2471 2472 sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2473 2474 deUint32 error; 2475 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2476 deUint32 vaoID = 0; 2477 deUint32 dataBufferID = 0; 2478 deUint32 indexBufferID = 0; 2479 deUint32 cmdBufferID = 0; 2480 2481 const deUint32 programID = program.getProgram(); 2482 const deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2483 2484 DrawElementsCommand drawCommand; 2485 drawCommand.count = 3; 2486 drawCommand.primCount = 1; 2487 drawCommand.firstIndex = 0; 2488 drawCommand.baseVertex = 0; 2489 drawCommand.reservedMustBeZero = 0; 2490 2491 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2492 2493 if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR) 2494 { 2495 // \note We use default VAO since we use client pointers. Trying indirect draw with default VAO is also an error. => This test does two illegal operations 2496 2497 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, vertexPositions); 2498 gl.enableVertexAttribArray(posLocation); 2499 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2500 } 2501 else if (m_caseType == CASE_CLIENT_BUFFER_COMMAND) 2502 { 2503 gl.genVertexArrays(1, &vaoID); 2504 gl.bindVertexArray(vaoID); 2505 2506 gl.genBuffers(1, &dataBufferID); 2507 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2508 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2509 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2510 gl.enableVertexAttribArray(posLocation); 2511 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2512 } 2513 else if (m_caseType == CASE_DEFAULT_VAO) 2514 { 2515 gl.genBuffers(1, &dataBufferID); 2516 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2517 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2518 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2519 gl.enableVertexAttribArray(posLocation); 2520 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2521 } 2522 else 2523 DE_ASSERT(DE_FALSE); 2524 2525 gl.genBuffers(1, &indexBufferID); 2526 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); 2527 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2528 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2529 2530 if (m_caseType != CASE_CLIENT_BUFFER_COMMAND) 2531 { 2532 gl.genBuffers(1, &cmdBufferID); 2533 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID); 2534 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2535 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2536 } 2537 2538 gl.viewport(0, 0, 1, 1); 2539 2540 gl.useProgram(programID); 2541 gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (m_caseType != CASE_CLIENT_BUFFER_COMMAND) ? (DE_NULL) : (&drawCommand)); 2542 2543 error = gl.getError(); 2544 2545 gl.bindVertexArray(0); 2546 gl.useProgram(0); 2547 2548 if (error == GL_INVALID_OPERATION) 2549 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2550 else 2551 { 2552 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 2553 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2554 } 2555 2556 return STOP; 2557} 2558 2559class BadDrawModeCase : public TestCase 2560{ 2561public: 2562 enum DrawType 2563 { 2564 DRAW_ARRAYS = 0, 2565 DRAW_ELEMENTS, 2566 DRAW_ELEMENTS_BAD_INDEX, 2567 2568 DRAW_LAST 2569 }; 2570 2571 BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type); 2572 ~BadDrawModeCase(void); 2573 2574 void init (void); 2575 void deinit (void); 2576 IterateResult iterate (void); 2577 2578private: 2579 const DrawType m_drawType; 2580}; 2581 2582BadDrawModeCase::BadDrawModeCase (Context& context, const char* name, const char* desc, DrawType type) 2583 : TestCase (context, name, desc) 2584 , m_drawType (type) 2585{ 2586 DE_ASSERT(type < DRAW_LAST); 2587} 2588 2589BadDrawModeCase::~BadDrawModeCase (void) 2590{ 2591 deinit(); 2592} 2593 2594void BadDrawModeCase::init (void) 2595{ 2596} 2597 2598void BadDrawModeCase::deinit (void) 2599{ 2600} 2601 2602BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void) 2603{ 2604 const tcu::Vec4 vertexPositions[] = 2605 { 2606 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), 2607 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 2608 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 2609 }; 2610 2611 const deUint16 indices[] = 2612 { 2613 0, 2, 1, 2614 }; 2615 2616 sglr::GLContext gl (m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1)); 2617 2618 deUint32 error; 2619 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource)); 2620 deUint32 vaoID = 0; 2621 deUint32 dataBufferID = 0; 2622 deUint32 indexBufferID = 0; 2623 deUint32 cmdBufferID = 0; 2624 2625 const deUint32 programID = program.getProgram(); 2626 const deInt32 posLocation = gl.getAttribLocation(programID, "a_position"); 2627 const glw::GLenum mode = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (GL_TRIANGLES) : (0x123); 2628 const glw::GLenum indexType = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (0x123) : (GL_UNSIGNED_SHORT); 2629 2630 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2631 2632 // vao 2633 2634 gl.genVertexArrays(1, &vaoID); 2635 gl.bindVertexArray(vaoID); 2636 2637 // va 2638 2639 gl.genBuffers(1, &dataBufferID); 2640 gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID); 2641 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW); 2642 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 2643 gl.enableVertexAttribArray(posLocation); 2644 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2645 2646 // index 2647 2648 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2649 { 2650 gl.genBuffers(1, &indexBufferID); 2651 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); 2652 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 2653 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2654 } 2655 2656 // cmd 2657 2658 gl.genBuffers(1, &cmdBufferID); 2659 gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID); 2660 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2661 { 2662 DrawElementsCommand drawCommand; 2663 drawCommand.count = 3; 2664 drawCommand.primCount = 1; 2665 drawCommand.firstIndex = 0; 2666 drawCommand.baseVertex = 0; 2667 drawCommand.reservedMustBeZero = 0; 2668 2669 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2670 } 2671 else if (m_drawType == DRAW_ARRAYS) 2672 { 2673 DrawArraysCommand drawCommand; 2674 drawCommand.count = 3; 2675 drawCommand.primCount = 1; 2676 drawCommand.first = 0; 2677 drawCommand.reservedMustBeZero = 0; 2678 2679 gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW); 2680 } 2681 else 2682 DE_ASSERT(DE_FALSE); 2683 glu::checkError(gl.getError(), "", __FILE__, __LINE__); 2684 2685 gl.viewport(0, 0, 1, 1); 2686 gl.useProgram(programID); 2687 if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX) 2688 gl.drawElementsIndirect(mode, indexType, DE_NULL); 2689 else if (m_drawType == DRAW_ARRAYS) 2690 gl.drawArraysIndirect(mode, DE_NULL); 2691 else 2692 DE_ASSERT(DE_FALSE); 2693 2694 error = gl.getError(); 2695 gl.useProgram(0); 2696 2697 if (error == GL_INVALID_ENUM) 2698 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2699 else 2700 { 2701 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_ENUM, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 2702 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error."); 2703 } 2704 2705 return STOP; 2706} 2707 2708class NegativeGroup : public TestCaseGroup 2709{ 2710public: 2711 NegativeGroup (Context& context, const char* name, const char* descr); 2712 ~NegativeGroup (void); 2713 2714 void init (void); 2715}; 2716 2717NegativeGroup::NegativeGroup (Context& context, const char* name, const char* descr) 2718 : TestCaseGroup (context, name, descr) 2719{ 2720} 2721 2722NegativeGroup::~NegativeGroup (void) 2723{ 2724} 2725 2726void NegativeGroup::init (void) 2727{ 2728 // invalid alignment 2729 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_1", "Bad command alignment", 1)); 2730 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_2", "Bad command alignment", 2)); 2731 addChild(new BadAlignmentCase (m_context, "command_bad_alignment_3", "Bad command alignment", 3)); 2732 2733 // command only partially or not at all in the buffer 2734 addChild(new BadBufferRangeCase (m_context, "command_offset_partially_in_buffer", "Command not fully in the buffer range", BadBufferRangeCase::CommandSize - 16)); 2735 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer", "Command not in the buffer range", BadBufferRangeCase::CommandSize)); 2736 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer_unsigned32_wrap", "Command not in the buffer range", 0xFFFFFFFC)); 2737 addChild(new BadBufferRangeCase (m_context, "command_offset_not_in_buffer_signed32_wrap", "Command not in the buffer range", 0x7FFFFFFC)); 2738 2739 // use with client data and default vao 2740 addChild(new BadStateCase (m_context, "client_vertex_attrib_array", "Vertex attrib array in the client memory", BadStateCase::CASE_CLIENT_BUFFER_VERTEXATTR)); 2741 addChild(new BadStateCase (m_context, "client_command_array", "Command array in the client memory", BadStateCase::CASE_CLIENT_BUFFER_COMMAND)); 2742 addChild(new BadStateCase (m_context, "default_vao", "Use with default vao", BadStateCase::CASE_DEFAULT_VAO)); 2743 2744 // invalid mode & type 2745 addChild(new BadDrawModeCase (m_context, "invalid_mode_draw_arrays", "Call DrawArraysIndirect with bad mode", BadDrawModeCase::DRAW_ARRAYS)); 2746 addChild(new BadDrawModeCase (m_context, "invalid_mode_draw_elements", "Call DrawelementsIndirect with bad mode", BadDrawModeCase::DRAW_ELEMENTS)); 2747 addChild(new BadDrawModeCase (m_context, "invalid_type_draw_elements", "Call DrawelementsIndirect with bad type", BadDrawModeCase::DRAW_ELEMENTS_BAD_INDEX)); 2748} 2749 2750} // anonymous 2751 2752DrawTests::DrawTests (Context& context) 2753 : TestCaseGroup(context, "draw_indirect", "Indirect drawing tests") 2754{ 2755} 2756 2757DrawTests::~DrawTests (void) 2758{ 2759} 2760 2761void DrawTests::init (void) 2762{ 2763 // Basic 2764 { 2765 const gls::DrawTestSpec::DrawMethod basicMethods[] = 2766 { 2767 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT, 2768 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT, 2769 }; 2770 2771 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx) 2772 { 2773 const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 2774 const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 2775 2776 this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx])); 2777 } 2778 } 2779 2780 // extreme instancing 2781 2782 this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count.")); 2783 2784 // compute shader generated commands 2785 2786 this->addChild(new ComputeShaderGeneratedGroup(m_context, "compute_interop", "draw tests with a draw command generated in compute shader.")); 2787 2788 // Random 2789 2790 this->addChild(new RandomGroup(m_context, "random", "random draw commands.")); 2791 2792 // negative 2793 2794 this->addChild(new NegativeGroup(m_context, "negative", "invalid draw commands with defined error codes.")); 2795} 2796 2797} // Functional 2798} // gles31 2799} // deqp 2800