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 Vertex attribute binding tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fVertexAttributeBindingTests.hpp" 25 #include "tcuRenderTarget.hpp" 26 #include "tcuSurface.hpp" 27 #include "gluCallLogWrapper.hpp" 28 #include "gluRenderContext.hpp" 29 #include "gluPixelTransfer.hpp" 30 #include "gluShaderProgram.hpp" 31 #include "gluObjectWrapper.hpp" 32 #include "gluStrUtil.hpp" 33 #include "glwFunctions.hpp" 34 #include "glwEnums.hpp" 35 #include "deStringUtil.hpp" 36 #include "deInt32.h" 37 38 namespace deqp 39 { 40 namespace gles31 41 { 42 namespace Functional 43 { 44 namespace 45 { 46 47 static const char* const s_colorFragmentShader = "#version 310 es\n" 48 "in mediump vec4 v_color;\n" 49 "layout(location = 0) out mediump vec4 fragColor;\n" 50 "void main (void)\n" 51 "{\n" 52 " fragColor = v_color;\n" 53 "}\n"; 54 55 static const char* const s_positionColorShader = "#version 310 es\n" 56 "in highp vec4 a_position;\n" 57 "in highp vec4 a_color;\n" 58 "out highp vec4 v_color;\n" 59 "void main (void)\n" 60 "{\n" 61 " gl_Position = a_position;\n" 62 " v_color = a_color;\n" 63 "}\n"; 64 65 static const char* const s_positionColorOffsetShader = "#version 310 es\n" 66 "in highp vec4 a_position;\n" 67 "in highp vec4 a_offset;\n" 68 "in highp vec4 a_color;\n" 69 "out highp vec4 v_color;\n" 70 "void main (void)\n" 71 "{\n" 72 " gl_Position = a_position + a_offset;\n" 73 " v_color = a_color;\n" 74 "}\n"; 75 76 // Verifies image contains only yellow or greeen, or a linear combination 77 // of these colors. 78 static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log, bool logImageOnSuccess) 79 { 80 using tcu::TestLog; 81 82 const int colorThreshold = 20; 83 84 tcu::Surface error (image.getWidth(), image.getHeight()); 85 bool isOk = true; 86 87 log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage; 88 89 for (int y = 0; y < image.getHeight(); y++) 90 for (int x = 0; x < image.getWidth(); x++) 91 { 92 const tcu::RGBA pixel = image.getPixel(x, y); 93 bool pixelOk = true; 94 95 // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow) 96 if (de::abs(pixel.getGreen() - 255) > colorThreshold) 97 pixelOk = false; 98 99 // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow) 100 if (de::abs(pixel.getBlue() - 0) > colorThreshold) 101 pixelOk = false; 102 103 error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255))); 104 isOk = isOk && pixelOk; 105 } 106 107 if (!isOk) 108 { 109 log << TestLog::Message << "Image verification failed." << TestLog::EndMessage; 110 log << TestLog::ImageSet("Verfication result", "Result of rendering") 111 << TestLog::Image("Result", "Result", image) 112 << TestLog::Image("ErrorMask", "Error mask", error) 113 << TestLog::EndImageSet; 114 } 115 else 116 { 117 log << TestLog::Message << "Image verification passed." << TestLog::EndMessage; 118 119 if (logImageOnSuccess) 120 log << TestLog::ImageSet("Verfication result", "Result of rendering") 121 << TestLog::Image("Result", "Result", image) 122 << TestLog::EndImageSet; 123 } 124 125 return isOk; 126 } 127 128 class BindingRenderCase : public TestCase 129 { 130 public: 131 enum 132 { 133 TEST_RENDER_SIZE = 64 134 }; 135 136 BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData); 137 virtual ~BindingRenderCase (void); 138 139 virtual void init (void); 140 virtual void deinit (void); 141 IterateResult iterate (void); 142 143 private: 144 virtual void renderTo (tcu::Surface& dst) = 0; 145 virtual void createBuffers (void) = 0; 146 virtual void createShader (void) = 0; 147 148 protected: 149 const bool m_unalignedData; 150 glw::GLuint m_vao; 151 glu::ShaderProgram* m_program; 152 }; 153 154 BindingRenderCase::BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData) 155 : TestCase (ctx, name, desc) 156 , m_unalignedData (unalignedData) 157 , m_vao (0) 158 , m_program (DE_NULL) 159 { 160 } 161 162 BindingRenderCase::~BindingRenderCase (void) 163 { 164 deinit(); 165 } 166 167 void BindingRenderCase::init (void) 168 { 169 // check requirements 170 if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE || m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE) 171 throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" + de::toString<int>(TEST_RENDER_SIZE) + " render target"); 172 173 // resources 174 m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao); 175 if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR) 176 throw tcu::TestError("could not gen vao"); 177 178 createBuffers(); 179 createShader(); 180 } 181 182 void BindingRenderCase::deinit (void) 183 { 184 if (m_vao) 185 { 186 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao); 187 m_vao = 0; 188 } 189 190 delete m_program; 191 m_program = DE_NULL; 192 } 193 194 BindingRenderCase::IterateResult BindingRenderCase::iterate (void) 195 { 196 tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE); 197 198 // draw pattern 199 200 renderTo(surface); 201 202 // verify results 203 204 if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false)) 205 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 206 else if (m_unalignedData) 207 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data"); 208 else 209 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 210 211 return STOP; 212 } 213 214 class SingleBindingCase : public BindingRenderCase 215 { 216 public: 217 218 enum CaseFlag 219 { 220 FLAG_ATTRIB_UNALIGNED = (1<<0), // !< unalign attributes with relativeOffset 221 FLAG_ATTRIB_ALIGNED = (1<<1), // !< align attributes with relativeOffset to the buffer begin (and not buffer offset) 222 FLAG_ATTRIBS_MULTIPLE_ELEMS = (1<<2), // !< use multiple attribute elements 223 FLAG_ATTRIBS_SHARED_ELEMS = (1<<3), // !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a) 224 225 FLAG_BUF_ALIGNED_OFFSET = (1<<4), // !< use aligned offset to the buffer object 226 FLAG_BUF_UNALIGNED_OFFSET = (1<<5), // !< use unaligned offset to the buffer object 227 FLAG_BUF_UNALIGNED_STRIDE = (1<<6), // !< unalign buffer elements 228 }; 229 SingleBindingCase (Context& ctx, const char* name, int flags); 230 ~SingleBindingCase (void); 231 232 void init (void); 233 void deinit (void); 234 235 private: 236 struct TestSpec 237 { 238 int bufferOffset; 239 int bufferStride; 240 int positionAttrOffset; 241 int colorAttrOffset; 242 bool hasColorAttr; 243 }; 244 245 enum 246 { 247 GRID_SIZE = 20 248 }; 249 250 void renderTo (tcu::Surface& dst); 251 252 static TestSpec genTestSpec (int flags); 253 static std::string genTestDescription (int flags); 254 static bool isDataUnaligned (int flags); 255 256 void createBuffers (void); 257 void createShader (void); 258 std::string genVertexSource (void); 259 260 const TestSpec m_spec; 261 glw::GLuint m_buf; 262 }; 263 264 SingleBindingCase::SingleBindingCase (Context& ctx, const char* name, int flags) 265 : BindingRenderCase (ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags)) 266 , m_spec (genTestSpec(flags)) 267 , m_buf (0) 268 { 269 DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED))); 270 DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE))); 271 272 DE_ASSERT(!isDataUnaligned(flags)); 273 } 274 275 SingleBindingCase::~SingleBindingCase (void) 276 { 277 deinit(); 278 } 279 280 void SingleBindingCase::init (void) 281 { 282 // log what we are trying to do 283 284 m_testCtx.getLog() << tcu::TestLog::Message 285 << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n" 286 << "Buffer format:\n" 287 << " bufferOffset: " << m_spec.bufferOffset << "\n" 288 << " bufferStride: " << m_spec.bufferStride << "\n" 289 << "Vertex position format:\n" 290 << " type: float4\n" 291 << " offset: " << m_spec.positionAttrOffset << "\n" 292 << " total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n" 293 << tcu::TestLog::EndMessage; 294 295 if (m_spec.hasColorAttr) 296 m_testCtx.getLog() << tcu::TestLog::Message 297 << "Color:\n" 298 << " type: float4\n" 299 << " offset: " << m_spec.colorAttrOffset << "\n" 300 << " total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n" 301 << tcu::TestLog::EndMessage; 302 // init 303 304 BindingRenderCase::init(); 305 } 306 307 void SingleBindingCase::deinit (void) 308 { 309 if (m_buf) 310 { 311 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf); 312 m_buf = 0; 313 } 314 315 BindingRenderCase::deinit(); 316 } 317 318 void SingleBindingCase::renderTo (tcu::Surface& dst) 319 { 320 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 321 const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 322 const int colorLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_color"); 323 const int colorUniformLoc = gl.glGetUniformLocation(m_program->getProgram(), "u_color"); 324 325 gl.enableLogging(true); 326 327 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 328 gl.glClear(GL_COLOR_BUFFER_BIT); 329 gl.glViewport(0, 0, dst.getWidth(), dst.getHeight()); 330 gl.glBindVertexArray(m_vao); 331 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao"); 332 333 gl.glUseProgram(m_program->getProgram()); 334 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 335 336 if (m_spec.hasColorAttr) 337 { 338 gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride); 339 340 gl.glVertexAttribBinding(positionLoc, 3); 341 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset); 342 gl.glEnableVertexAttribArray(positionLoc); 343 344 gl.glVertexAttribBinding(colorLoc, 3); 345 gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset); 346 gl.glEnableVertexAttribArray(colorLoc); 347 348 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 349 350 gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6); 351 GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw"); 352 } 353 else 354 { 355 gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride); 356 gl.glVertexAttribBinding(positionLoc, 3); 357 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset); 358 gl.glEnableVertexAttribArray(positionLoc); 359 360 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 361 gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f); 362 363 gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6); 364 GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw"); 365 } 366 367 gl.glFinish(); 368 gl.glBindVertexArray(0); 369 gl.glUseProgram(0); 370 GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean"); 371 372 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 373 } 374 375 SingleBindingCase::TestSpec SingleBindingCase::genTestSpec (int flags) 376 { 377 const int datumSize = 4; 378 const int bufferOffset = (flags & FLAG_BUF_ALIGNED_OFFSET) ? (32) : (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) : (0); 379 const int attrBufAlignment = ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize)); 380 const int positionAttrOffset = (flags & FLAG_ATTRIB_UNALIGNED) ? (3) : (flags & FLAG_ATTRIB_ALIGNED) ? (attrBufAlignment) : (0); 381 const bool hasColorAttr = (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS); 382 const int colorAttrOffset = (flags & FLAG_ATTRIBS_SHARED_ELEMS) ? (2 * datumSize) : (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) : (-1); 383 384 const int bufferStrideBase = de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize); 385 const int bufferStrideAlignment = ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize)); 386 const int bufferStridePadding = ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) : (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ? (bufferStrideAlignment) : (0); 387 388 TestSpec spec; 389 390 spec.bufferOffset = bufferOffset; 391 spec.bufferStride = bufferStrideBase + bufferStridePadding; 392 spec.positionAttrOffset = positionAttrOffset; 393 spec.colorAttrOffset = colorAttrOffset; 394 spec.hasColorAttr = hasColorAttr; 395 396 if (flags & FLAG_ATTRIB_UNALIGNED) 397 DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize)); 398 else if (flags & FLAG_ATTRIB_ALIGNED) 399 DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize)); 400 401 if (flags & FLAG_BUF_UNALIGNED_STRIDE) 402 DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize)); 403 else 404 DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize)); 405 406 return spec; 407 } 408 409 std::string SingleBindingCase::genTestDescription (int flags) 410 { 411 std::ostringstream buf; 412 buf << "draw test pattern"; 413 414 if (flags & FLAG_ATTRIB_UNALIGNED) 415 buf << ", attribute offset (unaligned)"; 416 if (flags & FLAG_ATTRIB_ALIGNED) 417 buf << ", attribute offset (aligned)"; 418 419 if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) 420 buf << ", 2 attributes"; 421 if (flags & FLAG_ATTRIBS_SHARED_ELEMS) 422 buf << ", 2 attributes (some components shared)"; 423 424 if (flags & FLAG_BUF_ALIGNED_OFFSET) 425 buf << ", buffer offset aligned"; 426 if (flags & FLAG_BUF_UNALIGNED_OFFSET) 427 buf << ", buffer offset unaligned"; 428 if (flags & FLAG_BUF_UNALIGNED_STRIDE) 429 buf << ", buffer stride unaligned"; 430 431 return buf.str(); 432 } 433 434 bool SingleBindingCase::isDataUnaligned (int flags) 435 { 436 if (flags & FLAG_ATTRIB_UNALIGNED) 437 return true; 438 if (flags & FLAG_ATTRIB_ALIGNED) 439 return false; 440 441 return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE); 442 } 443 444 void SingleBindingCase::createBuffers (void) 445 { 446 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 447 std::vector<deUint8> dataBuf (m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6); 448 449 // In interleaved mode color rg and position zw are the same. Select "good" values for r and g 450 const tcu::Vec4 colorA (0.0f, 1.0f, 0.0f, 1.0f); 451 const tcu::Vec4 colorB (0.5f, 1.0f, 0.0f, 1.0f); 452 453 for (int y = 0; y < GRID_SIZE; ++y) 454 for (int x = 0; x < GRID_SIZE; ++x) 455 { 456 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (colorA) : (colorB); 457 const tcu::Vec4 positions[6] = 458 { 459 tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 460 tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 461 tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 462 tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 463 tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 464 tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 465 }; 466 467 // copy cell vertices to the buffer. 468 for (int v = 0; v < 6; ++v) 469 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], positions[v].getPtr(), sizeof(positions[v])); 470 471 // copy color to buffer 472 if (m_spec.hasColorAttr) 473 for (int v = 0; v < 6; ++v) 474 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], color.getPtr(), sizeof(color)); 475 } 476 477 gl.genBuffers(1, &m_buf); 478 gl.bindBuffer(GL_ARRAY_BUFFER, m_buf); 479 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW); 480 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 481 482 if (gl.getError() != GL_NO_ERROR) 483 throw tcu::TestError("could not init buffer"); 484 } 485 486 void SingleBindingCase::createShader (void) 487 { 488 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(s_colorFragmentShader)); 489 m_testCtx.getLog() << *m_program; 490 491 if (!m_program->isOk()) 492 throw tcu::TestError("could not build shader"); 493 } 494 495 std::string SingleBindingCase::genVertexSource (void) 496 { 497 const bool useUniformColor = !m_spec.hasColorAttr; 498 std::ostringstream buf; 499 500 buf << "#version 310 es\n" 501 "in highp vec4 a_position;\n"; 502 503 if (!useUniformColor) 504 buf << "in highp vec4 a_color;\n"; 505 else 506 buf << "uniform highp vec4 u_color;\n"; 507 508 buf << "out highp vec4 v_color;\n" 509 "void main (void)\n" 510 "{\n" 511 " gl_Position = a_position;\n" 512 " v_color = " << ((useUniformColor) ? ("u_color") : ("a_color")) << ";\n" 513 "}\n"; 514 515 return buf.str(); 516 } 517 518 class MultipleBindingCase : public BindingRenderCase 519 { 520 public: 521 522 enum CaseFlag 523 { 524 FLAG_ZERO_STRIDE = (1<<0), // !< set a buffer stride to zero 525 FLAG_INSTANCED = (1<<1), // !< set a buffer instance divisor to non-zero 526 FLAG_ALIASING_BUFFERS = (1<<2), // !< bind buffer to multiple binding points 527 }; 528 529 MultipleBindingCase (Context& ctx, const char* name, int flags); 530 ~MultipleBindingCase (void); 531 532 void init (void); 533 void deinit (void); 534 535 private: 536 struct TestSpec 537 { 538 bool zeroStride; 539 bool instanced; 540 bool aliasingBuffers; 541 }; 542 543 enum 544 { 545 GRID_SIZE = 20 546 }; 547 548 void renderTo (tcu::Surface& dst); 549 550 TestSpec genTestSpec (int flags) const; 551 std::string genTestDescription (int flags) const; 552 void createBuffers (void); 553 void createShader (void); 554 555 const TestSpec m_spec; 556 glw::GLuint m_primitiveBuf; 557 glw::GLuint m_colorOffsetBuf; 558 }; 559 560 MultipleBindingCase::MultipleBindingCase (Context& ctx, const char* name, int flags) 561 : BindingRenderCase (ctx, name, genTestDescription(flags).c_str(), false) 562 , m_spec (genTestSpec(flags)) 563 , m_primitiveBuf (0) 564 , m_colorOffsetBuf (0) 565 { 566 DE_ASSERT(!(m_spec.instanced && m_spec.zeroStride)); 567 } 568 569 MultipleBindingCase::~MultipleBindingCase (void) 570 { 571 deinit(); 572 } 573 574 void MultipleBindingCase::init (void) 575 { 576 BindingRenderCase::init(); 577 578 // log what we are trying to do 579 580 m_testCtx.getLog() << tcu::TestLog::Message 581 << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n" 582 << "Vertex positions:\n" 583 << " binding point: 1\n" 584 << "Vertex offsets:\n" 585 << " binding point: 2\n" 586 << "Vertex colors:\n" 587 << " binding point: 2\n" 588 << "Binding point 1:\n" 589 << " buffer object: " << m_primitiveBuf << "\n" 590 << "Binding point 2:\n" 591 << " buffer object: " << ((m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf)) << "\n" 592 << " instance divisor: " << ((m_spec.instanced) ? (1) : (0)) << "\n" 593 << " stride: " << ((m_spec.zeroStride) ? (0) : (4*4*2)) << "\n" 594 << tcu::TestLog::EndMessage; 595 } 596 597 void MultipleBindingCase::deinit (void) 598 { 599 if (m_primitiveBuf) 600 { 601 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_primitiveBuf); 602 m_primitiveBuf = DE_NULL; 603 } 604 605 if (m_colorOffsetBuf) 606 { 607 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuf); 608 m_colorOffsetBuf = DE_NULL; 609 } 610 611 BindingRenderCase::deinit(); 612 } 613 614 void MultipleBindingCase::renderTo (tcu::Surface& dst) 615 { 616 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 617 const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 618 const int colorLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_color"); 619 const int offsetLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_offset"); 620 621 const int positionBinding = 1; 622 const int colorOffsetBinding = 2; 623 624 gl.enableLogging(true); 625 626 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 627 gl.glClear(GL_COLOR_BUFFER_BIT); 628 gl.glViewport(0, 0, dst.getWidth(), dst.getHeight()); 629 gl.glBindVertexArray(m_vao); 630 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao"); 631 632 gl.glUseProgram(m_program->getProgram()); 633 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 634 635 // Setup format & binding 636 637 gl.glEnableVertexAttribArray(positionLoc); 638 gl.glEnableVertexAttribArray(colorLoc); 639 gl.glEnableVertexAttribArray(offsetLoc); 640 641 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0); 642 gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0); 643 gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4)); 644 645 gl.glVertexAttribBinding(positionLoc, positionBinding); 646 gl.glVertexAttribBinding(colorLoc, colorOffsetBinding); 647 gl.glVertexAttribBinding(offsetLoc, colorOffsetBinding); 648 649 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attribs"); 650 651 // setup binding points 652 653 gl.glVertexBindingDivisor(positionBinding, 0); 654 gl.glBindVertexBuffer(positionBinding, m_primitiveBuf, 0, sizeof(tcu::Vec4)); 655 656 { 657 const int stride = (m_spec.zeroStride) ? (0) : (2 * (int)sizeof(tcu::Vec4)); 658 const int offset = (!m_spec.aliasingBuffers) ? (0) : (m_spec.instanced) ? (6 * (int)sizeof(tcu::Vec4)) : (6 * GRID_SIZE * GRID_SIZE * (int)sizeof(tcu::Vec4)); 659 const glw::GLuint buffer = (m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf); 660 const int divisor = (m_spec.instanced) ? (1) : (0); 661 662 gl.glVertexBindingDivisor(colorOffsetBinding, divisor); 663 gl.glBindVertexBuffer(colorOffsetBinding, buffer, offset, (glw::GLsizei)stride); 664 } 665 666 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding points"); 667 668 if (m_spec.instanced) 669 gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE); 670 else 671 gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6); 672 GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw"); 673 674 gl.glFinish(); 675 gl.glBindVertexArray(0); 676 gl.glUseProgram(0); 677 GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean"); 678 679 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 680 } 681 682 MultipleBindingCase::TestSpec MultipleBindingCase::genTestSpec (int flags) const 683 { 684 MultipleBindingCase::TestSpec spec; 685 686 spec.zeroStride = !!(flags & FLAG_ZERO_STRIDE); 687 spec.instanced = !!(flags & FLAG_INSTANCED); 688 spec.aliasingBuffers = !!(flags & FLAG_ALIASING_BUFFERS); 689 690 return spec; 691 } 692 693 std::string MultipleBindingCase::genTestDescription (int flags) const 694 { 695 std::ostringstream buf; 696 buf << "draw test pattern"; 697 698 if (flags & FLAG_ZERO_STRIDE) 699 buf << ", zero stride"; 700 if (flags & FLAG_INSTANCED) 701 buf << ", instanced binding point"; 702 if (flags & FLAG_ALIASING_BUFFERS) 703 buf << ", binding points share buffer object"; 704 705 return buf.str(); 706 } 707 708 void MultipleBindingCase::createBuffers (void) 709 { 710 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 711 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); 712 const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f); 713 714 const int vertexDataSize = (m_spec.instanced) ? (6) : (6 * GRID_SIZE * GRID_SIZE); 715 const int offsetColorSize = (m_spec.zeroStride) ? (2) : (m_spec.instanced) ? (2 * GRID_SIZE * GRID_SIZE) : (2 * 6 * GRID_SIZE * GRID_SIZE); 716 const int primitiveBufSize = (m_spec.aliasingBuffers) ? (vertexDataSize + offsetColorSize) : (vertexDataSize); 717 const int colorOffsetBufSize = (m_spec.aliasingBuffers) ? (0) : (offsetColorSize); 718 719 std::vector<tcu::Vec4> primitiveData (primitiveBufSize); 720 std::vector<tcu::Vec4> colorOffsetData (colorOffsetBufSize); 721 tcu::Vec4* colorOffsetWritePtr = DE_NULL; 722 723 if (m_spec.aliasingBuffers) 724 { 725 if (m_spec.instanced) 726 colorOffsetWritePtr = &primitiveData[6]; 727 else 728 colorOffsetWritePtr = &primitiveData[GRID_SIZE*GRID_SIZE*6]; 729 } 730 else 731 colorOffsetWritePtr = &colorOffsetData[0]; 732 733 // write vertex position 734 735 if (m_spec.instanced) 736 { 737 // store single basic primitive 738 primitiveData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 739 primitiveData[1] = tcu::Vec4(0.0f, 2.0f / GRID_SIZE, 0.0f, 1.0f); 740 primitiveData[2] = tcu::Vec4(2.0f / GRID_SIZE, 2.0f / GRID_SIZE, 0.0f, 1.0f); 741 primitiveData[3] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 742 primitiveData[4] = tcu::Vec4(2.0f / GRID_SIZE, 2.0f / GRID_SIZE, 0.0f, 1.0f); 743 primitiveData[5] = tcu::Vec4(2.0f / GRID_SIZE, 0.0f, 0.0f, 1.0f); 744 } 745 else 746 { 747 // store whole grid 748 for (int y = 0; y < GRID_SIZE; ++y) 749 for (int x = 0; x < GRID_SIZE; ++x) 750 { 751 primitiveData[(y * GRID_SIZE + x) * 6 + 0] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 752 primitiveData[(y * GRID_SIZE + x) * 6 + 1] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 753 primitiveData[(y * GRID_SIZE + x) * 6 + 2] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 754 primitiveData[(y * GRID_SIZE + x) * 6 + 3] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 755 primitiveData[(y * GRID_SIZE + x) * 6 + 4] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 756 primitiveData[(y * GRID_SIZE + x) * 6 + 5] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 757 } 758 } 759 760 // store color&offset 761 762 if (m_spec.zeroStride) 763 { 764 colorOffsetWritePtr[0] = green; 765 colorOffsetWritePtr[1] = tcu::Vec4(0.0f); 766 } 767 else if (m_spec.instanced) 768 { 769 for (int y = 0; y < GRID_SIZE; ++y) 770 for (int x = 0; x < GRID_SIZE; ++x) 771 { 772 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow); 773 774 colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 0] = color; 775 colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 1] = tcu::Vec4(float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f); 776 } 777 } 778 else 779 { 780 for (int y = 0; y < GRID_SIZE; ++y) 781 for (int x = 0; x < GRID_SIZE; ++x) 782 for (int v = 0; v < 6; ++v) 783 { 784 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow); 785 786 colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 0] = color; 787 colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 1] = tcu::Vec4(0.0f); 788 } 789 } 790 791 // upload vertex data 792 793 gl.genBuffers(1, &m_primitiveBuf); 794 gl.bindBuffer(GL_ARRAY_BUFFER, m_primitiveBuf); 795 gl.bufferData(GL_ARRAY_BUFFER, (int)(primitiveData.size() * sizeof(tcu::Vec4)), primitiveData[0].getPtr(), GL_STATIC_DRAW); 796 GLU_EXPECT_NO_ERROR(gl.getError(), "upload data"); 797 798 if (!m_spec.aliasingBuffers) 799 { 800 // upload color & offset data 801 802 gl.genBuffers(1, &m_colorOffsetBuf); 803 gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuf); 804 gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(), GL_STATIC_DRAW); 805 GLU_EXPECT_NO_ERROR(gl.getError(), "upload colordata"); 806 } 807 } 808 809 void MultipleBindingCase::createShader (void) 810 { 811 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader) << glu::FragmentSource(s_colorFragmentShader)); 812 m_testCtx.getLog() << *m_program; 813 814 if (!m_program->isOk()) 815 throw tcu::TestError("could not build shader"); 816 } 817 818 class MixedBindingCase : public BindingRenderCase 819 { 820 public: 821 822 enum CaseType 823 { 824 CASE_BASIC = 0, 825 CASE_INSTANCED_BINDING, 826 CASE_INSTANCED_ATTRIB, 827 828 CASE_LAST 829 }; 830 831 MixedBindingCase (Context& ctx, const char* name, const char* desc, CaseType caseType); 832 ~MixedBindingCase (void); 833 834 void init (void); 835 void deinit (void); 836 837 private: 838 enum 839 { 840 GRID_SIZE = 20 841 }; 842 843 void renderTo (tcu::Surface& dst); 844 void createBuffers (void); 845 void createShader (void); 846 847 const CaseType m_case; 848 glw::GLuint m_posBuffer; 849 glw::GLuint m_colorOffsetBuffer; 850 }; 851 852 MixedBindingCase::MixedBindingCase (Context& ctx, const char* name, const char* desc, CaseType caseType) 853 : BindingRenderCase (ctx, name, desc, false) 854 , m_case (caseType) 855 , m_posBuffer (0) 856 , m_colorOffsetBuffer (0) 857 { 858 DE_ASSERT(caseType < CASE_LAST); 859 } 860 861 MixedBindingCase::~MixedBindingCase (void) 862 { 863 deinit(); 864 } 865 866 void MixedBindingCase::init (void) 867 { 868 BindingRenderCase::init(); 869 } 870 871 void MixedBindingCase::deinit (void) 872 { 873 if (m_posBuffer) 874 { 875 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_posBuffer); 876 m_posBuffer = DE_NULL; 877 } 878 879 if (m_colorOffsetBuffer) 880 { 881 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuffer); 882 m_colorOffsetBuffer = DE_NULL; 883 } 884 885 BindingRenderCase::deinit(); 886 } 887 888 void MixedBindingCase::renderTo (tcu::Surface& dst) 889 { 890 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 891 const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 892 const int colorLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_color"); 893 const int offsetLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_offset"); 894 895 gl.enableLogging(true); 896 897 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 898 gl.glClear(GL_COLOR_BUFFER_BIT); 899 gl.glViewport(0, 0, dst.getWidth(), dst.getHeight()); 900 gl.glBindVertexArray(m_vao); 901 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao"); 902 903 gl.glUseProgram(m_program->getProgram()); 904 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 905 906 switch (m_case) 907 { 908 case CASE_BASIC: 909 { 910 // bind position using vertex_attrib_binding api 911 912 gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4)); 913 gl.glVertexAttribBinding(positionLoc, positionLoc); 914 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0); 915 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding"); 916 917 // bind color using old api 918 919 gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer); 920 gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL); 921 gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4))); 922 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 923 924 // draw 925 gl.glEnableVertexAttribArray(positionLoc); 926 gl.glEnableVertexAttribArray(colorLoc); 927 gl.glEnableVertexAttribArray(offsetLoc); 928 gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE); 929 break; 930 } 931 932 case CASE_INSTANCED_BINDING: 933 { 934 // bind position using old api 935 gl.glBindBuffer(GL_ARRAY_BUFFER, m_posBuffer); 936 gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 937 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 938 939 // bind color using vertex_attrib_binding api 940 gl.glBindVertexBuffer(colorLoc, m_colorOffsetBuffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 941 gl.glVertexBindingDivisor(colorLoc, 1); 942 943 gl.glVertexAttribBinding(colorLoc, colorLoc); 944 gl.glVertexAttribBinding(offsetLoc, colorLoc); 945 946 gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0); 947 gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4)); 948 949 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding"); 950 951 // draw 952 gl.glEnableVertexAttribArray(positionLoc); 953 gl.glEnableVertexAttribArray(colorLoc); 954 gl.glEnableVertexAttribArray(offsetLoc); 955 gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE); 956 break; 957 } 958 959 case CASE_INSTANCED_ATTRIB: 960 { 961 // bind position using vertex_attrib_binding api 962 gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4)); 963 gl.glVertexAttribBinding(positionLoc, positionLoc); 964 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0); 965 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding"); 966 967 // bind color using old api 968 gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer); 969 gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL); 970 gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4))); 971 gl.glVertexAttribDivisor(colorLoc, 1); 972 gl.glVertexAttribDivisor(offsetLoc, 1); 973 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 974 975 // draw 976 gl.glEnableVertexAttribArray(positionLoc); 977 gl.glEnableVertexAttribArray(colorLoc); 978 gl.glEnableVertexAttribArray(offsetLoc); 979 gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE*GRID_SIZE); 980 break; 981 } 982 983 default: 984 DE_ASSERT(DE_FALSE); 985 } 986 987 gl.glFinish(); 988 gl.glBindVertexArray(0); 989 gl.glUseProgram(0); 990 GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean"); 991 992 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 993 } 994 995 void MixedBindingCase::createBuffers (void) 996 { 997 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 998 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); 999 const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f); 1000 1001 // draw grid. In instanced mode, each cell is an instance 1002 const bool instanced = (m_case == CASE_INSTANCED_BINDING) || (m_case == CASE_INSTANCED_ATTRIB); 1003 const int numCells = GRID_SIZE*GRID_SIZE; 1004 const int numPositionCells = (instanced) ? (1) : (numCells); 1005 const int numPositionElements = 6 * numPositionCells; 1006 const int numInstanceElementsPerCell = (instanced) ? (1) : (6); 1007 const int numColorOffsetElements = numInstanceElementsPerCell * numCells; 1008 1009 std::vector<tcu::Vec4> positionData (numPositionElements); 1010 std::vector<tcu::Vec4> colorOffsetData (2 * numColorOffsetElements); 1011 1012 // positions 1013 1014 for (int primNdx = 0; primNdx < numPositionCells; ++primNdx) 1015 { 1016 positionData[primNdx*6 + 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 1017 positionData[primNdx*6 + 1] = tcu::Vec4(0.0f, 2.0f / GRID_SIZE, 0.0f, 1.0f); 1018 positionData[primNdx*6 + 2] = tcu::Vec4(2.0f / GRID_SIZE, 2.0f / GRID_SIZE, 0.0f, 1.0f); 1019 positionData[primNdx*6 + 3] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 1020 positionData[primNdx*6 + 4] = tcu::Vec4(2.0f / GRID_SIZE, 2.0f / GRID_SIZE, 0.0f, 1.0f); 1021 positionData[primNdx*6 + 5] = tcu::Vec4(2.0f / GRID_SIZE, 0.0f, 0.0f, 1.0f); 1022 } 1023 1024 // color & offset 1025 1026 for (int y = 0; y < GRID_SIZE; ++y) 1027 for (int x = 0; x < GRID_SIZE; ++x) 1028 { 1029 for (int v = 0; v < numInstanceElementsPerCell; ++v) 1030 { 1031 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow); 1032 1033 colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 0] = color; 1034 colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 1] = tcu::Vec4(float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f); 1035 } 1036 } 1037 1038 // upload vertex data 1039 1040 gl.genBuffers(1, &m_posBuffer); 1041 gl.bindBuffer(GL_ARRAY_BUFFER, m_posBuffer); 1042 gl.bufferData(GL_ARRAY_BUFFER, (int)(positionData.size() * sizeof(tcu::Vec4)), positionData[0].getPtr(), GL_STATIC_DRAW); 1043 GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data"); 1044 1045 gl.genBuffers(1, &m_colorOffsetBuffer); 1046 gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer); 1047 gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(), GL_STATIC_DRAW); 1048 GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data"); 1049 } 1050 1051 void MixedBindingCase::createShader (void) 1052 { 1053 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader) << glu::FragmentSource(s_colorFragmentShader)); 1054 m_testCtx.getLog() << *m_program; 1055 1056 if (!m_program->isOk()) 1057 throw tcu::TestError("could not build shader"); 1058 } 1059 1060 class MixedApiCase : public BindingRenderCase 1061 { 1062 public: 1063 1064 enum CaseType 1065 { 1066 CASE_CHANGE_BUFFER = 0, 1067 CASE_CHANGE_BUFFER_OFFSET, 1068 CASE_CHANGE_BUFFER_STRIDE, 1069 CASE_CHANGE_BINDING_POINT, 1070 1071 CASE_LAST 1072 }; 1073 1074 MixedApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType); 1075 ~MixedApiCase (void); 1076 1077 void init (void); 1078 void deinit (void); 1079 1080 private: 1081 enum 1082 { 1083 GRID_SIZE = 20 1084 }; 1085 1086 void renderTo (tcu::Surface& dst); 1087 void createBuffers (void); 1088 void createShader (void); 1089 1090 const CaseType m_case; 1091 glw::GLuint m_buffer; 1092 }; 1093 1094 1095 MixedApiCase::MixedApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType) 1096 : BindingRenderCase (ctx, name, desc, false) 1097 , m_case (caseType) 1098 , m_buffer (0) 1099 { 1100 DE_ASSERT(caseType < CASE_LAST); 1101 } 1102 1103 MixedApiCase::~MixedApiCase (void) 1104 { 1105 deinit(); 1106 } 1107 1108 void MixedApiCase::init (void) 1109 { 1110 BindingRenderCase::init(); 1111 } 1112 1113 void MixedApiCase::deinit (void) 1114 { 1115 if (m_buffer) 1116 { 1117 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer); 1118 m_buffer = DE_NULL; 1119 } 1120 1121 BindingRenderCase::deinit(); 1122 } 1123 1124 void MixedApiCase::renderTo (tcu::Surface& dst) 1125 { 1126 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 1127 const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 1128 const int colorLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_color"); 1129 glu::Buffer dummyBuffer (m_context.getRenderContext()); 1130 1131 gl.enableLogging(true); 1132 1133 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 1134 gl.glClear(GL_COLOR_BUFFER_BIT); 1135 gl.glViewport(0, 0, dst.getWidth(), dst.getHeight()); 1136 gl.glBindVertexArray(m_vao); 1137 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao"); 1138 1139 gl.glUseProgram(m_program->getProgram()); 1140 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 1141 1142 switch (m_case) 1143 { 1144 case CASE_CHANGE_BUFFER: 1145 { 1146 // bind data using old api 1147 1148 gl.glBindBuffer(GL_ARRAY_BUFFER, *dummyBuffer); 1149 gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL); 1150 gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4))); 1151 1152 // change buffer with vertex_attrib_binding 1153 1154 gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1155 gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1156 1157 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1158 break; 1159 } 1160 1161 case CASE_CHANGE_BUFFER_OFFSET: 1162 { 1163 // bind data using old api 1164 1165 gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 1166 gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL); 1167 gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL); 1168 1169 // change buffer offset with vertex_attrib_binding 1170 1171 gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1172 gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1173 1174 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1175 break; 1176 } 1177 1178 case CASE_CHANGE_BUFFER_STRIDE: 1179 { 1180 // bind data using old api 1181 1182 gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 1183 gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8, (const deUint8*)DE_NULL); 1184 gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 4, (const deUint8*)DE_NULL); 1185 1186 // change buffer stride with vertex_attrib_binding 1187 1188 gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1189 gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4))); 1190 1191 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1192 break; 1193 } 1194 1195 case CASE_CHANGE_BINDING_POINT: 1196 { 1197 const int maxUsedLocation = de::max(positionLoc, colorLoc); 1198 const int bindingPoint1 = maxUsedLocation + 1; 1199 const int bindingPoint2 = maxUsedLocation + 2; 1200 1201 // bind data using old api 1202 1203 gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 1204 gl.glVertexAttribPointer(bindingPoint1, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), (const deUint8*)DE_NULL); 1205 gl.glVertexAttribPointer(bindingPoint2, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)), glu::BufferOffsetAsPointer(sizeof(tcu::Vec4))); 1206 1207 // change buffer binding point with vertex_attrib_binding 1208 1209 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0); 1210 gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0); 1211 1212 gl.glVertexAttribBinding(positionLoc, bindingPoint1); 1213 gl.glVertexAttribBinding(colorLoc, bindingPoint2); 1214 1215 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1216 break; 1217 } 1218 1219 default: 1220 DE_ASSERT(DE_FALSE); 1221 } 1222 1223 // draw 1224 gl.glEnableVertexAttribArray(positionLoc); 1225 gl.glEnableVertexAttribArray(colorLoc); 1226 gl.glDrawArrays(GL_TRIANGLES, 0, 6*GRID_SIZE*GRID_SIZE); 1227 1228 gl.glFinish(); 1229 gl.glBindVertexArray(0); 1230 gl.glUseProgram(0); 1231 GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean"); 1232 1233 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 1234 } 1235 1236 void MixedApiCase::createBuffers (void) 1237 { 1238 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); 1239 const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f); 1240 1241 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1242 std::vector<tcu::Vec4> vertexData (12 * GRID_SIZE * GRID_SIZE); 1243 1244 for (int y = 0; y < GRID_SIZE; ++y) 1245 for (int x = 0; x < GRID_SIZE; ++x) 1246 { 1247 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (green) : (yellow); 1248 1249 vertexData[(y * GRID_SIZE + x) * 12 + 0] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1250 vertexData[(y * GRID_SIZE + x) * 12 + 1] = color; 1251 vertexData[(y * GRID_SIZE + x) * 12 + 2] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1252 vertexData[(y * GRID_SIZE + x) * 12 + 3] = color; 1253 vertexData[(y * GRID_SIZE + x) * 12 + 4] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1254 vertexData[(y * GRID_SIZE + x) * 12 + 5] = color; 1255 vertexData[(y * GRID_SIZE + x) * 12 + 6] = tcu::Vec4(float(x+0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1256 vertexData[(y * GRID_SIZE + x) * 12 + 7] = color; 1257 vertexData[(y * GRID_SIZE + x) * 12 + 8] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1258 vertexData[(y * GRID_SIZE + x) * 12 + 9] = color; 1259 vertexData[(y * GRID_SIZE + x) * 12 + 10] = tcu::Vec4(float(x+1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f); 1260 vertexData[(y * GRID_SIZE + x) * 12 + 11] = color; 1261 } 1262 1263 // upload vertex data 1264 1265 gl.genBuffers(1, &m_buffer); 1266 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); 1267 gl.bufferData(GL_ARRAY_BUFFER, (int)(vertexData.size() * sizeof(tcu::Vec4)), vertexData[0].getPtr(), GL_STATIC_DRAW); 1268 GLU_EXPECT_NO_ERROR(gl.getError(), "upload data"); 1269 } 1270 1271 void MixedApiCase::createShader (void) 1272 { 1273 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionColorShader) << glu::FragmentSource(s_colorFragmentShader)); 1274 m_testCtx.getLog() << *m_program; 1275 1276 if (!m_program->isOk()) 1277 throw tcu::TestError("could not build shader"); 1278 } 1279 1280 class DefaultVAOCase : public TestCase 1281 { 1282 public: 1283 enum CaseType 1284 { 1285 CASE_BIND_VERTEX_BUFFER, 1286 CASE_VERTEX_ATTRIB_FORMAT, 1287 CASE_VERTEX_ATTRIB_I_FORMAT, 1288 CASE_VERTEX_ATTRIB_BINDING, 1289 CASE_VERTEX_BINDING_DIVISOR, 1290 1291 CASE_LAST 1292 }; 1293 1294 DefaultVAOCase (Context& ctx, const char* name, const char* desc, CaseType caseType); 1295 ~DefaultVAOCase (void); 1296 1297 IterateResult iterate (void); 1298 1299 private: 1300 const CaseType m_caseType; 1301 }; 1302 1303 DefaultVAOCase::DefaultVAOCase (Context& ctx, const char* name, const char* desc, CaseType caseType) 1304 : TestCase (ctx, name, desc) 1305 , m_caseType (caseType) 1306 { 1307 DE_ASSERT(caseType < CASE_LAST); 1308 } 1309 1310 DefaultVAOCase::~DefaultVAOCase (void) 1311 { 1312 } 1313 1314 DefaultVAOCase::IterateResult DefaultVAOCase::iterate (void) 1315 { 1316 glw::GLenum error = 0; 1317 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); 1318 1319 gl.enableLogging(true); 1320 1321 switch (m_caseType) 1322 { 1323 case CASE_BIND_VERTEX_BUFFER: 1324 { 1325 glu::Buffer buffer(m_context.getRenderContext()); 1326 gl.glBindVertexBuffer(0, *buffer, 0, 0); 1327 break; 1328 } 1329 1330 case CASE_VERTEX_ATTRIB_FORMAT: 1331 gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, 0); 1332 break; 1333 1334 case CASE_VERTEX_ATTRIB_I_FORMAT: 1335 gl.glVertexAttribIFormat(0, 4, GL_INT, 0); 1336 break; 1337 1338 case CASE_VERTEX_ATTRIB_BINDING: 1339 gl.glVertexAttribBinding(0, 0); 1340 break; 1341 1342 case CASE_VERTEX_BINDING_DIVISOR: 1343 gl.glVertexBindingDivisor(0, 1); 1344 break; 1345 1346 default: 1347 DE_ASSERT(false); 1348 } 1349 1350 error = gl.glGetError(); 1351 1352 if (error != GL_INVALID_OPERATION) 1353 { 1354 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 1355 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error"); 1356 } 1357 else 1358 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1359 1360 return STOP; 1361 } 1362 1363 class BindToCreateCase : public TestCase 1364 { 1365 public: 1366 BindToCreateCase (Context& ctx, const char* name, const char* desc); 1367 ~BindToCreateCase (void); 1368 1369 IterateResult iterate (void); 1370 }; 1371 1372 BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc) 1373 : TestCase(ctx, name, desc) 1374 { 1375 } 1376 1377 BindToCreateCase::~BindToCreateCase (void) 1378 { 1379 } 1380 1381 BindToCreateCase::IterateResult BindToCreateCase::iterate (void) 1382 { 1383 glw::GLuint buffer = 0; 1384 glw::GLenum error; 1385 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); 1386 glu::VertexArray vao (m_context.getRenderContext()); 1387 1388 gl.enableLogging(true); 1389 1390 gl.glGenBuffers(1, &buffer); 1391 gl.glDeleteBuffers(1, &buffer); 1392 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1393 1394 gl.glBindVertexArray(*vao); 1395 gl.glBindVertexBuffer(0, buffer, 0, 0); 1396 1397 error = gl.glGetError(); 1398 1399 if (error != GL_INVALID_OPERATION) 1400 { 1401 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 1402 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error"); 1403 } 1404 else 1405 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1406 1407 return STOP; 1408 } 1409 1410 class NegativeApiCase : public TestCase 1411 { 1412 public: 1413 enum CaseType 1414 { 1415 CASE_LARGE_OFFSET, 1416 CASE_LARGE_STRIDE, 1417 CASE_NEGATIVE_STRIDE, 1418 CASE_NEGATIVE_OFFSET, 1419 CASE_INVALID_ATTR, 1420 CASE_INVALID_BINDING, 1421 1422 CASE_LAST 1423 }; 1424 NegativeApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType); 1425 ~NegativeApiCase (void); 1426 1427 IterateResult iterate (void); 1428 1429 private: 1430 const CaseType m_caseType; 1431 }; 1432 1433 NegativeApiCase::NegativeApiCase (Context& ctx, const char* name, const char* desc, CaseType caseType) 1434 : TestCase (ctx, name, desc) 1435 , m_caseType (caseType) 1436 { 1437 } 1438 1439 NegativeApiCase::~NegativeApiCase (void) 1440 { 1441 } 1442 1443 NegativeApiCase::IterateResult NegativeApiCase::iterate (void) 1444 { 1445 glw::GLenum error; 1446 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); 1447 glu::VertexArray vao (m_context.getRenderContext()); 1448 1449 gl.enableLogging(true); 1450 gl.glBindVertexArray(*vao); 1451 1452 switch (m_caseType) 1453 { 1454 case CASE_LARGE_OFFSET: 1455 { 1456 glw::GLint maxOffset = -1; 1457 glw::GLint largeOffset; 1458 1459 gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxOffset); 1460 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1461 1462 largeOffset = maxOffset + 1; 1463 1464 // skip if maximum unsigned or signed values 1465 if (maxOffset == -1 || maxOffset == 0x7FFFFFFF) 1466 throw tcu::NotSupportedError("Implementation supports all offsets"); 1467 1468 gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, largeOffset); 1469 break; 1470 } 1471 1472 case CASE_LARGE_STRIDE: 1473 { 1474 glu::Buffer buffer (m_context.getRenderContext()); 1475 glw::GLint maxStride = -1; 1476 glw::GLint largeStride; 1477 1478 gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride); 1479 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1480 1481 largeStride = maxStride + 1; 1482 1483 // skip if maximum unsigned or signed values 1484 if (maxStride == -1 || maxStride == 0x7FFFFFFF) 1485 throw tcu::NotSupportedError("Implementation supports all strides"); 1486 1487 gl.glBindVertexBuffer(0, *buffer, 0, largeStride); 1488 break; 1489 } 1490 1491 case CASE_NEGATIVE_STRIDE: 1492 { 1493 glu::Buffer buffer(m_context.getRenderContext()); 1494 gl.glBindVertexBuffer(0, *buffer, 0, -20); 1495 break; 1496 } 1497 1498 case CASE_NEGATIVE_OFFSET: 1499 { 1500 glu::Buffer buffer(m_context.getRenderContext()); 1501 gl.glBindVertexBuffer(0, *buffer, -20, 0); 1502 break; 1503 } 1504 1505 case CASE_INVALID_ATTR: 1506 { 1507 glw::GLint maxIndex = -1; 1508 glw::GLint largeIndex; 1509 1510 gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxIndex); 1511 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1512 1513 largeIndex = maxIndex + 1; 1514 1515 // skip if maximum unsigned or signed values 1516 if (maxIndex == -1 || maxIndex == 0x7FFFFFFF) 1517 throw tcu::NotSupportedError("Implementation supports any attribute index"); 1518 1519 gl.glVertexAttribBinding(largeIndex, 0); 1520 break; 1521 } 1522 1523 case CASE_INVALID_BINDING: 1524 { 1525 glw::GLint maxBindings = -1; 1526 glw::GLint largeBinding; 1527 1528 gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &maxBindings); 1529 GLU_EXPECT_NO_ERROR(gl.glGetError(), ""); 1530 1531 largeBinding = maxBindings + 1; 1532 1533 // skip if maximum unsigned or signed values 1534 if (maxBindings == -1 || maxBindings == 0x7FFFFFFF) 1535 throw tcu::NotSupportedError("Implementation supports any binding"); 1536 1537 gl.glVertexAttribBinding(0, largeBinding); 1538 break; 1539 } 1540 1541 default: 1542 DE_ASSERT(false); 1543 } 1544 1545 error = gl.glGetError(); 1546 1547 if (error != GL_INVALID_VALUE) 1548 { 1549 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage; 1550 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error"); 1551 } 1552 else 1553 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1554 1555 return STOP; 1556 } 1557 1558 } // anonymous 1559 1560 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context) 1561 : TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding") 1562 { 1563 } 1564 1565 VertexAttributeBindingTests::~VertexAttributeBindingTests (void) 1566 { 1567 } 1568 1569 void VertexAttributeBindingTests::init (void) 1570 { 1571 tcu::TestCaseGroup* const usageGroup = new tcu::TestCaseGroup(m_testCtx, "usage", "Test using binding points"); 1572 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative test"); 1573 1574 addChild(usageGroup); 1575 addChild(negativeGroup); 1576 1577 // .usage 1578 { 1579 tcu::TestCaseGroup* const singleGroup = new tcu::TestCaseGroup(m_testCtx, "single_binding", "Test using single binding point"); 1580 tcu::TestCaseGroup* const multipleGroup = new tcu::TestCaseGroup(m_testCtx, "multiple_bindings", "Test using multiple binding points"); 1581 tcu::TestCaseGroup* const mixedGroup = new tcu::TestCaseGroup(m_testCtx, "mixed_usage", "Test using binding point and non binding point api variants"); 1582 1583 usageGroup->addChild(singleGroup); 1584 usageGroup->addChild(multipleGroup); 1585 usageGroup->addChild(mixedGroup); 1586 1587 // single binding 1588 1589 singleGroup->addChild(new SingleBindingCase(m_context, "elements_1", 0)); 1590 singleGroup->addChild(new SingleBindingCase(m_context, "elements_2", SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS)); 1591 singleGroup->addChild(new SingleBindingCase(m_context, "elements_2_share_elements", SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS)); 1592 singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_1", SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET | 0)); 1593 singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2", SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS)); 1594 singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2_share_elements", SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS)); 1595 singleGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1_aligned_elements", SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIB_ALIGNED)); // !< total offset is aligned 1596 1597 // multiple bindings 1598 1599 multipleGroup->addChild(new MultipleBindingCase(m_context, "basic", 0)); 1600 multipleGroup->addChild(new MultipleBindingCase(m_context, "zero_stride", MultipleBindingCase::FLAG_ZERO_STRIDE)); 1601 multipleGroup->addChild(new MultipleBindingCase(m_context, "instanced", MultipleBindingCase::FLAG_INSTANCED)); 1602 multipleGroup->addChild(new MultipleBindingCase(m_context, "aliasing_buffer_zero_stride", MultipleBindingCase::FLAG_ALIASING_BUFFERS | MultipleBindingCase::FLAG_ZERO_STRIDE)); 1603 multipleGroup->addChild(new MultipleBindingCase(m_context, "aliasing_buffer_instanced", MultipleBindingCase::FLAG_ALIASING_BUFFERS | MultipleBindingCase::FLAG_INSTANCED)); 1604 1605 // mixed cases 1606 mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_basic", "Use different api for different attributes", MixedBindingCase::CASE_BASIC)); 1607 mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_instanced_binding", "Use different api for different attributes", MixedBindingCase::CASE_INSTANCED_BINDING)); 1608 mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_instanced_attrib", "Use different api for different attributes", MixedBindingCase::CASE_INSTANCED_ATTRIB)); 1609 1610 mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer", "change buffer with vertex_attrib_binding api", MixedApiCase::CASE_CHANGE_BUFFER)); 1611 mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer_offset", "change buffer offset with vertex_attrib_binding api", MixedApiCase::CASE_CHANGE_BUFFER_OFFSET)); 1612 mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer_stride", "change buffer stride with vertex_attrib_binding api", MixedApiCase::CASE_CHANGE_BUFFER_STRIDE)); 1613 mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_binding_point", "change binding point with vertex_attrib_binding api", MixedApiCase::CASE_CHANGE_BINDING_POINT)); 1614 } 1615 1616 // negative 1617 { 1618 negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_bind_vertex_buffer", "use with default vao", DefaultVAOCase::CASE_BIND_VERTEX_BUFFER)); 1619 negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_format", "use with default vao", DefaultVAOCase::CASE_VERTEX_ATTRIB_FORMAT)); 1620 negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_i_format", "use with default vao", DefaultVAOCase::CASE_VERTEX_ATTRIB_I_FORMAT)); 1621 negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_binding", "use with default vao", DefaultVAOCase::CASE_VERTEX_ATTRIB_BINDING)); 1622 negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_binding_divisor", "use with default vao", DefaultVAOCase::CASE_VERTEX_BINDING_DIVISOR)); 1623 1624 negativeGroup->addChild(new BindToCreateCase(m_context, "bind_create_new_buffer", "bind not existing buffer")); 1625 1626 negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_format_large_offset", "large relative offset", NegativeApiCase::CASE_LARGE_OFFSET)); 1627 negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_large_stride", "large stride", NegativeApiCase::CASE_LARGE_STRIDE)); 1628 negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_stride", "negative stride", NegativeApiCase::CASE_NEGATIVE_STRIDE)); 1629 negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_offset", "negative offset", NegativeApiCase::CASE_NEGATIVE_OFFSET)); 1630 negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_attr", "bind invalid attr", NegativeApiCase::CASE_INVALID_ATTR)); 1631 negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_binding", "bind invalid binding", NegativeApiCase::CASE_INVALID_BINDING)); 1632 } 1633 } 1634 1635 } // Functional 1636 } // gles31 1637 } // deqp 1638