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