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 stress tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31sVertexAttributeBindingTests.hpp" 25 #include "tcuVector.hpp" 26 #include "tcuTestLog.hpp" 27 #include "tcuRenderTarget.hpp" 28 #include "tcuSurface.hpp" 29 #include "gluCallLogWrapper.hpp" 30 #include "gluObjectWrapper.hpp" 31 #include "gluPixelTransfer.hpp" 32 #include "gluRenderContext.hpp" 33 #include "gluShaderProgram.hpp" 34 #include "gluStrUtil.hpp" 35 #include "glwFunctions.hpp" 36 #include "glwEnums.hpp" 37 #include "deStringUtil.hpp" 38 39 namespace deqp 40 { 41 namespace gles31 42 { 43 namespace Stress 44 { 45 namespace 46 { 47 48 static const char* const s_vertexSource = "#version 310 es\n" 49 "in highp vec4 a_position;\n" 50 "void main (void)\n" 51 "{\n" 52 " gl_Position = a_position;\n" 53 "}\n"; 54 55 static const char* const s_fragmentSource = "#version 310 es\n" 56 "layout(location = 0) out mediump vec4 fragColor;\n" 57 "void main (void)\n" 58 "{\n" 59 " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" 60 "}\n"; 61 62 static const char* const s_colorFragmentShader = "#version 310 es\n" 63 "in mediump vec4 v_color;\n" 64 "layout(location = 0) out mediump vec4 fragColor;\n" 65 "void main (void)\n" 66 "{\n" 67 " fragColor = v_color;\n" 68 "}\n"; 69 70 // Verifies image contains only yellow or greeen, or a linear combination 71 // of these colors. 72 static bool verifyImageYellowGreen (const tcu::Surface& image, tcu::TestLog& log, bool logImageOnSuccess) 73 { 74 using tcu::TestLog; 75 76 const tcu::RGBA green (0, 255, 0, 255); 77 const tcu::RGBA yellow (255, 255, 0, 255); 78 const int colorThreshold = 20; 79 80 tcu::Surface error (image.getWidth(), image.getHeight()); 81 bool isOk = true; 82 83 log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage; 84 85 for (int y = 0; y < image.getHeight(); y++) 86 for (int x = 0; x < image.getWidth(); x++) 87 { 88 const tcu::RGBA pixel = image.getPixel(x, y); 89 bool pixelOk = true; 90 91 // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow) 92 if (de::abs(pixel.getGreen() - 255) > colorThreshold) 93 pixelOk = false; 94 95 // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow) 96 if (de::abs(pixel.getBlue() - 0) > colorThreshold) 97 pixelOk = false; 98 99 error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255))); 100 isOk = isOk && pixelOk; 101 } 102 103 if (!isOk) 104 { 105 log << TestLog::Message << "Image verification failed." << TestLog::EndMessage; 106 log << TestLog::ImageSet("Verfication result", "Result of rendering") 107 << TestLog::Image("Result", "Result", image) 108 << TestLog::Image("ErrorMask", "Error mask", error) 109 << TestLog::EndImageSet; 110 } 111 else 112 { 113 log << TestLog::Message << "Image verification passed." << TestLog::EndMessage; 114 115 if (logImageOnSuccess) 116 log << TestLog::ImageSet("Verfication result", "Result of rendering") 117 << TestLog::Image("Result", "Result", image) 118 << TestLog::EndImageSet; 119 } 120 121 return isOk; 122 } 123 124 class BindingRenderCase : public TestCase 125 { 126 public: 127 enum 128 { 129 TEST_RENDER_SIZE = 64 130 }; 131 132 BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData); 133 virtual ~BindingRenderCase (void); 134 135 virtual void init (void); 136 virtual void deinit (void); 137 IterateResult iterate (void); 138 139 private: 140 virtual void renderTo (tcu::Surface& dst) = 0; 141 virtual void createBuffers (void) = 0; 142 virtual void createShader (void) = 0; 143 144 protected: 145 const bool m_unalignedData; 146 glw::GLuint m_vao; 147 glu::ShaderProgram* m_program; 148 }; 149 150 BindingRenderCase::BindingRenderCase (Context& ctx, const char* name, const char* desc, bool unalignedData) 151 : TestCase (ctx, name, desc) 152 , m_unalignedData (unalignedData) 153 , m_vao (0) 154 , m_program (DE_NULL) 155 { 156 } 157 158 BindingRenderCase::~BindingRenderCase (void) 159 { 160 deinit(); 161 } 162 163 void BindingRenderCase::init (void) 164 { 165 // check requirements 166 if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE || m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE) 167 throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" + de::toString<int>(TEST_RENDER_SIZE) + " render target"); 168 169 // resources 170 m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao); 171 if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR) 172 throw tcu::TestError("could not gen vao"); 173 174 createBuffers(); 175 createShader(); 176 } 177 178 void BindingRenderCase::deinit (void) 179 { 180 if (m_vao) 181 { 182 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao); 183 m_vao = 0; 184 } 185 186 delete m_program; 187 m_program = DE_NULL; 188 } 189 190 BindingRenderCase::IterateResult BindingRenderCase::iterate (void) 191 { 192 tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE); 193 194 // draw pattern 195 196 renderTo(surface); 197 198 // verify results 199 200 if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false)) 201 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 202 else if (m_unalignedData) 203 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data"); 204 else 205 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 206 207 return STOP; 208 } 209 210 class SingleBindingCase : public BindingRenderCase 211 { 212 public: 213 214 enum CaseFlag 215 { 216 FLAG_ATTRIB_UNALIGNED = (1<<0), // !< unalign attributes with relativeOffset 217 FLAG_ATTRIB_ALIGNED = (1<<1), // !< align attributes with relativeOffset to the buffer begin (and not buffer offset) 218 FLAG_ATTRIBS_MULTIPLE_ELEMS = (1<<2), // !< use multiple attribute elements 219 FLAG_ATTRIBS_SHARED_ELEMS = (1<<3), // !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a) 220 221 FLAG_BUF_ALIGNED_OFFSET = (1<<4), // !< use aligned offset to the buffer object 222 FLAG_BUF_UNALIGNED_OFFSET = (1<<5), // !< use unaligned offset to the buffer object 223 FLAG_BUF_UNALIGNED_STRIDE = (1<<6), // !< unalign buffer elements 224 }; 225 SingleBindingCase (Context& ctx, const char* name, int flags); 226 ~SingleBindingCase (void); 227 228 void init (void); 229 void deinit (void); 230 231 private: 232 struct TestSpec 233 { 234 int bufferOffset; 235 int bufferStride; 236 int positionAttrOffset; 237 int colorAttrOffset; 238 bool hasColorAttr; 239 }; 240 241 enum 242 { 243 GRID_SIZE = 20 244 }; 245 246 void renderTo (tcu::Surface& dst); 247 248 static TestSpec genTestSpec (int flags); 249 static std::string genTestDescription (int flags); 250 static bool isDataUnaligned (int flags); 251 252 void createBuffers (void); 253 void createShader (void); 254 std::string genVertexSource (void); 255 256 const TestSpec m_spec; 257 glw::GLuint m_buf; 258 }; 259 260 SingleBindingCase::SingleBindingCase (Context& ctx, const char* name, int flags) 261 : BindingRenderCase (ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags)) 262 , m_spec (genTestSpec(flags)) 263 , m_buf (0) 264 { 265 DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED))); 266 DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE))); 267 268 DE_ASSERT(isDataUnaligned(flags)); 269 } 270 271 SingleBindingCase::~SingleBindingCase (void) 272 { 273 deinit(); 274 } 275 276 void SingleBindingCase::init (void) 277 { 278 // log what we are trying to do 279 280 m_testCtx.getLog() << tcu::TestLog::Message 281 << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n" 282 << "Buffer format:\n" 283 << " bufferOffset: " << m_spec.bufferOffset << "\n" 284 << " bufferStride: " << m_spec.bufferStride << "\n" 285 << "Vertex position format:\n" 286 << " type: float4\n" 287 << " offset: " << m_spec.positionAttrOffset << "\n" 288 << " total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n" 289 << tcu::TestLog::EndMessage; 290 291 if (m_spec.hasColorAttr) 292 m_testCtx.getLog() << tcu::TestLog::Message 293 << "Color:\n" 294 << " type: float4\n" 295 << " offset: " << m_spec.colorAttrOffset << "\n" 296 << " total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n" 297 << tcu::TestLog::EndMessage; 298 // init 299 300 BindingRenderCase::init(); 301 } 302 303 void SingleBindingCase::deinit (void) 304 { 305 if (m_buf) 306 { 307 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf); 308 m_buf = 0; 309 } 310 311 BindingRenderCase::deinit(); 312 } 313 314 void SingleBindingCase::renderTo (tcu::Surface& dst) 315 { 316 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 317 const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 318 const int colorLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_color"); 319 const int colorUniformLoc = gl.glGetUniformLocation(m_program->getProgram(), "u_color"); 320 321 gl.enableLogging(true); 322 323 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 324 gl.glClear(GL_COLOR_BUFFER_BIT); 325 gl.glViewport(0, 0, dst.getWidth(), dst.getHeight()); 326 gl.glBindVertexArray(m_vao); 327 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao"); 328 329 gl.glUseProgram(m_program->getProgram()); 330 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 331 332 if (m_spec.hasColorAttr) 333 { 334 gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride); 335 336 gl.glVertexAttribBinding(positionLoc, 3); 337 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset); 338 gl.glEnableVertexAttribArray(positionLoc); 339 340 gl.glVertexAttribBinding(colorLoc, 3); 341 gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset); 342 gl.glEnableVertexAttribArray(colorLoc); 343 344 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 345 346 gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6); 347 GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw"); 348 } 349 else 350 { 351 gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride); 352 gl.glVertexAttribBinding(positionLoc, 3); 353 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset); 354 gl.glEnableVertexAttribArray(positionLoc); 355 356 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va"); 357 gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f); 358 359 gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE*GRID_SIZE*6); 360 GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw"); 361 } 362 363 gl.glFinish(); 364 gl.glBindVertexArray(0); 365 gl.glUseProgram(0); 366 GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean"); 367 368 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 369 } 370 371 SingleBindingCase::TestSpec SingleBindingCase::genTestSpec (int flags) 372 { 373 const int datumSize = 4; 374 const int bufferOffset = (flags & FLAG_BUF_ALIGNED_OFFSET) ? (32) : (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) : (0); 375 const int attrBufAlignment = ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize)); 376 const int positionAttrOffset = (flags & FLAG_ATTRIB_UNALIGNED) ? (3) : (flags & FLAG_ATTRIB_ALIGNED) ? (attrBufAlignment) : (0); 377 const bool hasColorAttr = (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS); 378 const int colorAttrOffset = (flags & FLAG_ATTRIBS_SHARED_ELEMS) ? (2 * datumSize) : (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) : (-1); 379 380 const int bufferStrideBase = de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize); 381 const int bufferStrideAlignment = ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize)); 382 const int bufferStridePadding = ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) : (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ? (bufferStrideAlignment) : (0); 383 384 TestSpec spec; 385 386 spec.bufferOffset = bufferOffset; 387 spec.bufferStride = bufferStrideBase + bufferStridePadding; 388 spec.positionAttrOffset = positionAttrOffset; 389 spec.colorAttrOffset = colorAttrOffset; 390 spec.hasColorAttr = hasColorAttr; 391 392 if (flags & FLAG_ATTRIB_UNALIGNED) 393 DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize)); 394 else if (flags & FLAG_ATTRIB_ALIGNED) 395 DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize)); 396 397 if (flags & FLAG_BUF_UNALIGNED_STRIDE) 398 DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize)); 399 else 400 DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize)); 401 402 return spec; 403 } 404 405 std::string SingleBindingCase::genTestDescription (int flags) 406 { 407 std::ostringstream buf; 408 buf << "draw test pattern"; 409 410 if (flags & FLAG_ATTRIB_UNALIGNED) 411 buf << ", attribute offset (unaligned)"; 412 if (flags & FLAG_ATTRIB_ALIGNED) 413 buf << ", attribute offset (aligned)"; 414 415 if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) 416 buf << ", 2 attributes"; 417 if (flags & FLAG_ATTRIBS_SHARED_ELEMS) 418 buf << ", 2 attributes (some components shared)"; 419 420 if (flags & FLAG_BUF_ALIGNED_OFFSET) 421 buf << ", buffer offset aligned"; 422 if (flags & FLAG_BUF_UNALIGNED_OFFSET) 423 buf << ", buffer offset unaligned"; 424 if (flags & FLAG_BUF_UNALIGNED_STRIDE) 425 buf << ", buffer stride unaligned"; 426 427 return buf.str(); 428 } 429 430 bool SingleBindingCase::isDataUnaligned (int flags) 431 { 432 if (flags & FLAG_ATTRIB_UNALIGNED) 433 return true; 434 if (flags & FLAG_ATTRIB_ALIGNED) 435 return false; 436 437 return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE); 438 } 439 440 void SingleBindingCase::createBuffers (void) 441 { 442 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 443 std::vector<deUint8> dataBuf (m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6); 444 445 // In interleaved mode color rg and position zw are the same. Select "good" values for r and g 446 const tcu::Vec4 colorA (0.0f, 1.0f, 0.0f, 1.0f); 447 const tcu::Vec4 colorB (0.5f, 1.0f, 0.0f, 1.0f); 448 449 for (int y = 0; y < GRID_SIZE; ++y) 450 for (int x = 0; x < GRID_SIZE; ++x) 451 { 452 const tcu::Vec4& color = ((x + y) % 2 == 0) ? (colorA) : (colorB); 453 const tcu::Vec4 positions[6] = 454 { 455 tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 456 tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 457 tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 458 tcu::Vec4((x+0) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 459 tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 460 tcu::Vec4((x+1) / float(GRID_SIZE) * 2.0f - 1.0f, (y+0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f), 461 }; 462 463 // copy cell vertices to the buffer. 464 for (int v = 0; v < 6; ++v) 465 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], positions[v].getPtr(), sizeof(positions[v])); 466 467 // copy color to buffer 468 if (m_spec.hasColorAttr) 469 for (int v = 0; v < 6; ++v) 470 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset + m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)], color.getPtr(), sizeof(color)); 471 } 472 473 gl.genBuffers(1, &m_buf); 474 gl.bindBuffer(GL_ARRAY_BUFFER, m_buf); 475 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW); 476 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 477 478 if (gl.getError() != GL_NO_ERROR) 479 throw tcu::TestError("could not init buffer"); 480 } 481 482 void SingleBindingCase::createShader (void) 483 { 484 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(s_colorFragmentShader)); 485 m_testCtx.getLog() << *m_program; 486 487 if (!m_program->isOk()) 488 throw tcu::TestError("could not build shader"); 489 } 490 491 std::string SingleBindingCase::genVertexSource (void) 492 { 493 const bool useUniformColor = !m_spec.hasColorAttr; 494 std::ostringstream buf; 495 496 buf << "#version 310 es\n" 497 "in highp vec4 a_position;\n"; 498 499 if (!useUniformColor) 500 buf << "in highp vec4 a_color;\n"; 501 else 502 buf << "uniform highp vec4 u_color;\n"; 503 504 buf << "out highp vec4 v_color;\n" 505 "void main (void)\n" 506 "{\n" 507 " gl_Position = a_position;\n" 508 " v_color = " << ((useUniformColor) ? ("u_color") : ("a_color")) << ";\n" 509 "}\n"; 510 511 return buf.str(); 512 } 513 514 class BindVertexBufferCase : public TestCase 515 { 516 public: 517 BindVertexBufferCase (Context& ctx, const char* name, const char* desc, int offset, int drawCount); 518 ~BindVertexBufferCase (void); 519 520 void init (void); 521 void deinit (void); 522 IterateResult iterate (void); 523 524 private: 525 const int m_offset; 526 const int m_drawCount; 527 deUint32 m_buffer; 528 glu::ShaderProgram* m_program; 529 }; 530 531 BindVertexBufferCase::BindVertexBufferCase (Context& ctx, const char* name, const char* desc, int offset, int drawCount) 532 : TestCase (ctx, name, desc) 533 , m_offset (offset) 534 , m_drawCount (drawCount) 535 , m_buffer (0) 536 , m_program (DE_NULL) 537 { 538 } 539 540 BindVertexBufferCase::~BindVertexBufferCase (void) 541 { 542 deinit(); 543 } 544 545 void BindVertexBufferCase::init (void) 546 { 547 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 548 std::vector<tcu::Vec4> data (m_drawCount); // !< some junk data to make sure buffer is really allocated 549 550 gl.genBuffers(1, &m_buffer); 551 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); 552 gl.bufferData(GL_ARRAY_BUFFER, int(m_drawCount * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW); 553 GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen"); 554 555 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_vertexSource) << glu::FragmentSource(s_fragmentSource)); 556 if (!m_program->isOk()) 557 { 558 m_testCtx.getLog() << *m_program; 559 throw tcu::TestError("could not build program"); 560 } 561 } 562 563 void BindVertexBufferCase::deinit (void) 564 { 565 if (m_buffer) 566 { 567 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer); 568 m_buffer = 0; 569 } 570 571 delete m_program; 572 m_program = DE_NULL; 573 } 574 575 BindVertexBufferCase::IterateResult BindVertexBufferCase::iterate (void) 576 { 577 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 578 const deInt32 positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position"); 579 tcu::Surface dst (m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()); 580 glu::VertexArray vao (m_context.getRenderContext()); 581 582 gl.enableLogging(true); 583 584 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 585 gl.glClear(GL_COLOR_BUFFER_BIT); 586 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup"); 587 588 gl.glUseProgram(m_program->getProgram()); 589 GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program"); 590 591 gl.glBindVertexArray(*vao); 592 gl.glEnableVertexAttribArray(positionLoc); 593 gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0); 594 gl.glVertexAttribBinding(positionLoc, 0); 595 gl.glBindVertexBuffer(0, m_buffer, m_offset, int(sizeof(tcu::Vec4))); 596 GLU_EXPECT_NO_ERROR(gl.glGetError(), "set buffer"); 597 598 gl.glDrawArrays(GL_POINTS, 0, m_drawCount); 599 600 // allow errors after attempted out-of-bounds memory access 601 { 602 const deUint32 error = gl.glGetError(); 603 604 if (error != GL_NO_ERROR) 605 m_testCtx.getLog() << tcu::TestLog::Message << "Got error: " << glu::getErrorStr(error) << ", ignoring..." << tcu::TestLog::EndMessage; 606 } 607 608 // read pixels to wait for rendering 609 gl.glFinish(); 610 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 611 612 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 613 return STOP; 614 } 615 616 } // anonymous 617 618 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context) 619 : TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding stress tests") 620 { 621 } 622 623 VertexAttributeBindingTests::~VertexAttributeBindingTests (void) 624 { 625 } 626 627 void VertexAttributeBindingTests::init (void) 628 { 629 tcu::TestCaseGroup* const unalignedGroup = new tcu::TestCaseGroup(m_testCtx, "unaligned", "Unaligned access"); 630 tcu::TestCaseGroup* const bufferRangeGroup = new tcu::TestCaseGroup(m_testCtx, "buffer_bounds", "Source data over buffer bounds"); 631 632 addChild(unalignedGroup); 633 addChild(bufferRangeGroup); 634 635 // .unaligned 636 { 637 unalignedGroup->addChild(new SingleBindingCase(m_context, "elements_1_unaligned", SingleBindingCase::FLAG_ATTRIB_UNALIGNED)); 638 unalignedGroup->addChild(new SingleBindingCase(m_context, "offset_elements_1_unaligned", SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIB_UNALIGNED)); 639 640 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1", SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | 0)); 641 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1_unaligned", SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIB_UNALIGNED)); 642 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2", SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS)); 643 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2_share_elements", SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS)); 644 645 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_1", SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE | 0)); 646 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2", SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE | SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS)); 647 unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2_share_elements", SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE | SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS)); 648 } 649 650 // .buffer_bounds 651 { 652 // bind buffer offset cases 653 bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_10", "Offset over buffer bounds", 0x00210000, 10)); 654 bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_1000", "Offset over buffer bounds", 0x00210000, 1000)); 655 bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_10", "Offset over buffer bounds, near wrapping", 0x7FFFFFF0, 10)); 656 bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_1000", "Offset over buffer bounds, near wrapping", 0x7FFFFFF0, 1000)); 657 } 658 } 659 660 } // Stress 661 } // gles31 662 } // deqp 663