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