1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 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 Buffer test utilities. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es2fBufferTestUtil.hpp" 25#include "tcuRandomValueIterator.hpp" 26#include "tcuSurface.hpp" 27#include "tcuImageCompare.hpp" 28#include "tcuVector.hpp" 29#include "tcuFormatUtil.hpp" 30#include "tcuTextureUtil.hpp" 31#include "tcuRenderTarget.hpp" 32#include "gluPixelTransfer.hpp" 33#include "gluRenderContext.hpp" 34#include "gluStrUtil.hpp" 35#include "gluShaderProgram.hpp" 36#include "deMemory.h" 37#include "deStringUtil.hpp" 38 39#include <algorithm> 40 41#include "glwEnums.hpp" 42#include "glwFunctions.hpp" 43 44namespace deqp 45{ 46namespace gles2 47{ 48namespace Functional 49{ 50namespace BufferTestUtil 51{ 52 53enum 54{ 55 VERIFY_QUAD_SIZE = 8, //!< Quad size in VertexArrayVerifier 56 MAX_LINES_PER_INDEX_ARRAY_DRAW = 128, //!< Maximum number of lines per one draw in IndexArrayVerifier 57 INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128, 58 INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128 59}; 60 61static const bool LOG_VERIFIER_CALLS = false; //! \note Especially array verifier generates a lot of calls. 62 63using tcu::TestLog; 64using std::vector; 65using std::string; 66using std::set; 67 68// Helper functions. 69 70void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed) 71{ 72 std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr); 73} 74 75bool compareByteArrays (tcu::TestLog& log, const deUint8* resPtr, const deUint8* refPtr, int numBytes) 76{ 77 bool isOk = true; 78 const int maxSpanLen = 8; 79 const int maxDiffSpans = 4; 80 int numDiffSpans = 0; 81 int diffSpanStart = -1; 82 int ndx = 0; 83 84 log << TestLog::Section("Verify", "Verification result"); 85 86 for (;ndx < numBytes; ndx++) 87 { 88 if (resPtr[ndx] != refPtr[ndx]) 89 { 90 if (diffSpanStart < 0) 91 diffSpanStart = ndx; 92 93 isOk = false; 94 } 95 else if (diffSpanStart >= 0) 96 { 97 if (numDiffSpans < maxDiffSpans) 98 { 99 int len = ndx-diffSpanStart; 100 int printLen = de::min(len, maxSpanLen); 101 102 log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n" 103 << " expected " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n" 104 << " got " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen)) 105 << TestLog::EndMessage; 106 } 107 else 108 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage; 109 110 numDiffSpans += 1; 111 diffSpanStart = -1; 112 } 113 } 114 115 if (diffSpanStart >= 0) 116 { 117 if (numDiffSpans < maxDiffSpans) 118 { 119 int len = ndx-diffSpanStart; 120 int printLen = de::min(len, maxSpanLen); 121 122 log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n" 123 << " expected " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n" 124 << " got " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen)) 125 << TestLog::EndMessage; 126 } 127 else 128 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage; 129 } 130 131 log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage; 132 log << TestLog::EndSection; 133 134 return isOk; 135} 136 137const char* getBufferTargetName (deUint32 target) 138{ 139 switch (target) 140 { 141 case GL_ARRAY_BUFFER: return "array"; 142 case GL_ELEMENT_ARRAY_BUFFER: return "element_array"; 143 default: 144 DE_ASSERT(false); 145 return DE_NULL; 146 } 147} 148 149const char* getUsageHintName (deUint32 hint) 150{ 151 switch (hint) 152 { 153 case GL_STREAM_DRAW: return "stream_draw"; 154 case GL_STATIC_DRAW: return "static_draw"; 155 case GL_DYNAMIC_DRAW: return "dynamic_draw"; 156 default: 157 DE_ASSERT(false); 158 return DE_NULL; 159 } 160} 161 162// BufferCase 163 164BufferCase::BufferCase (Context& context, const char* name, const char* description) 165 : TestCase (context, name, description) 166 , CallLogWrapper (context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()) 167{ 168} 169 170BufferCase::~BufferCase (void) 171{ 172 enableLogging(false); 173 BufferCase::deinit(); 174} 175 176void BufferCase::init (void) 177{ 178 enableLogging(true); 179} 180 181void BufferCase::deinit (void) 182{ 183 for (set<deUint32>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end(); bufIter++) 184 glDeleteBuffers(1, &(*bufIter)); 185} 186 187deUint32 BufferCase::genBuffer (void) 188{ 189 deUint32 buf = 0; 190 glGenBuffers(1, &buf); 191 if (buf != 0) 192 { 193 try 194 { 195 m_allocatedBuffers.insert(buf); 196 } 197 catch (const std::exception&) 198 { 199 glDeleteBuffers(1, &buf); 200 throw; 201 } 202 } 203 return buf; 204} 205 206void BufferCase::deleteBuffer (deUint32 buffer) 207{ 208 glDeleteBuffers(1, &buffer); 209 m_allocatedBuffers.erase(buffer); 210} 211 212void BufferCase::checkError (void) 213{ 214 glw::GLenum err = glGetError(); 215 if (err != GL_NO_ERROR) 216 throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString()); 217} 218 219// ReferenceBuffer 220 221void ReferenceBuffer::setSize (int numBytes) 222{ 223 m_data.resize(numBytes); 224} 225 226void ReferenceBuffer::setData (int numBytes, const deUint8* bytes) 227{ 228 m_data.resize(numBytes); 229 std::copy(bytes, bytes+numBytes, m_data.begin()); 230} 231 232void ReferenceBuffer::setSubData (int offset, int numBytes, const deUint8* bytes) 233{ 234 DE_ASSERT(de::inBounds(offset, 0, (int)m_data.size()) && de::inRange(offset+numBytes, offset, (int)m_data.size())); 235 std::copy(bytes, bytes+numBytes, m_data.begin()+offset); 236} 237 238// BufferVerifierBase 239 240BufferVerifierBase::BufferVerifierBase (Context& context) 241 : CallLogWrapper (context.getRenderContext().getFunctions(), context.getTestContext().getLog()) 242 , m_context (context) 243{ 244 enableLogging(LOG_VERIFIER_CALLS); 245} 246 247// BufferVerifier 248 249BufferVerifier::BufferVerifier (Context& context, VerifyType verifyType) 250 : m_verifier(DE_NULL) 251{ 252 switch (verifyType) 253 { 254 case VERIFY_AS_VERTEX_ARRAY: m_verifier = new VertexArrayVerifier(context); break; 255 case VERIFY_AS_INDEX_ARRAY: m_verifier = new IndexArrayVerifier (context); break; 256 default: 257 TCU_FAIL("Unsupported verifier"); 258 } 259} 260 261BufferVerifier::~BufferVerifier (void) 262{ 263 delete m_verifier; 264} 265 266bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes) 267{ 268 DE_ASSERT(numBytes >= getMinSize()); 269 DE_ASSERT(offset%getAlignment() == 0); 270 DE_ASSERT((offset+numBytes)%getAlignment() == 0); 271 return m_verifier->verify(buffer, reference, offset, numBytes); 272} 273 274// VertexArrayVerifier 275 276VertexArrayVerifier::VertexArrayVerifier (Context& context) 277 : BufferVerifierBase (context) 278 , m_program (DE_NULL) 279 , m_posLoc (0) 280 , m_byteVecLoc (0) 281{ 282 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources( 283 "attribute highp vec2 a_position;\n" 284 "attribute mediump vec3 a_byteVec;\n" 285 "varying mediump vec3 v_byteVec;\n" 286 "void main (void)\n" 287 "{\n" 288 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 289 " v_byteVec = a_byteVec;\n" 290 "}\n", 291 292 "varying mediump vec3 v_byteVec;\n" 293 "void main (void)\n" 294 "{\n" 295 " gl_FragColor = vec4(v_byteVec, 1.0);\n" 296 "}\n")); 297 298 if (!m_program->isOk()) 299 { 300 m_context.getTestContext().getLog() << *m_program; 301 delete m_program; 302 TCU_FAIL("Compile failed"); 303 } 304 305 const glw::Functions& funcs = context.getRenderContext().getFunctions(); 306 m_posLoc = funcs.getAttribLocation(m_program->getProgram(), "a_position"); 307 m_byteVecLoc = funcs.getAttribLocation(m_program->getProgram(), "a_byteVec"); 308} 309 310VertexArrayVerifier::~VertexArrayVerifier (void) 311{ 312 delete m_program; 313} 314 315static void computePositions (vector<tcu::Vec2>& positions, int gridSizeX, int gridSizeY) 316{ 317 positions.resize(gridSizeX*gridSizeY*4); 318 319 for (int y = 0; y < gridSizeY; y++) 320 for (int x = 0; x < gridSizeX; x++) 321 { 322 float sx0 = (x+0) / (float)gridSizeX; 323 float sy0 = (y+0) / (float)gridSizeY; 324 float sx1 = (x+1) / (float)gridSizeX; 325 float sy1 = (y+1) / (float)gridSizeY; 326 float fx0 = 2.0f * sx0 - 1.0f; 327 float fy0 = 2.0f * sy0 - 1.0f; 328 float fx1 = 2.0f * sx1 - 1.0f; 329 float fy1 = 2.0f * sy1 - 1.0f; 330 int baseNdx = (y * gridSizeX + x)*4; 331 332 positions[baseNdx+0] = tcu::Vec2(fx0, fy0); 333 positions[baseNdx+1] = tcu::Vec2(fx0, fy1); 334 positions[baseNdx+2] = tcu::Vec2(fx1, fy0); 335 positions[baseNdx+3] = tcu::Vec2(fx1, fy1); 336 } 337} 338 339static void computeIndices (vector<deUint16>& indices, int gridSizeX, int gridSizeY) 340{ 341 indices.resize(3 * 2 * gridSizeX * gridSizeY); 342 343 for (int quadNdx = 0; quadNdx < gridSizeX*gridSizeY; quadNdx++) 344 { 345 int v00 = quadNdx*4 + 0; 346 int v01 = quadNdx*4 + 1; 347 int v10 = quadNdx*4 + 2; 348 int v11 = quadNdx*4 + 3; 349 350 DE_ASSERT(v11 < (1<<16)); 351 352 indices[quadNdx*6 + 0] = (deUint16)v10; 353 indices[quadNdx*6 + 1] = (deUint16)v00; 354 indices[quadNdx*6 + 2] = (deUint16)v01; 355 356 indices[quadNdx*6 + 3] = (deUint16)v10; 357 indices[quadNdx*6 + 4] = (deUint16)v01; 358 indices[quadNdx*6 + 5] = (deUint16)v11; 359 } 360} 361 362static inline tcu::Vec4 fetchVtxColor (const deUint8* ptr, int vtxNdx) 363{ 364 return tcu::RGBA(*(ptr + vtxNdx*3 + 0), 365 *(ptr + vtxNdx*3 + 1), 366 *(ptr + vtxNdx*3 + 2), 367 255).toVec(); 368} 369 370static void renderQuadGridReference (tcu::Surface& dst, int numQuads, int rowLength, const deUint8* inPtr) 371{ 372 using tcu::Vec4; 373 374 dst.setSize(rowLength*VERIFY_QUAD_SIZE, (numQuads/rowLength + (numQuads%rowLength != 0 ? 1 : 0))*VERIFY_QUAD_SIZE); 375 376 tcu::PixelBufferAccess dstAccess = dst.getAccess(); 377 tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff)); 378 379 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) 380 { 381 int x0 = (quadNdx%rowLength)*VERIFY_QUAD_SIZE; 382 int y0 = (quadNdx/rowLength)*VERIFY_QUAD_SIZE; 383 Vec4 v00 = fetchVtxColor(inPtr, quadNdx*4 + 0); 384 Vec4 v10 = fetchVtxColor(inPtr, quadNdx*4 + 1); 385 Vec4 v01 = fetchVtxColor(inPtr, quadNdx*4 + 2); 386 Vec4 v11 = fetchVtxColor(inPtr, quadNdx*4 + 3); 387 388 for (int y = 0; y < VERIFY_QUAD_SIZE; y++) 389 for (int x = 0; x < VERIFY_QUAD_SIZE; x++) 390 { 391 float fx = (float)(x+0.5f) / (float)VERIFY_QUAD_SIZE; 392 float fy = (float)(y+0.5f) / (float)VERIFY_QUAD_SIZE; 393 394 bool tri = fx + fy <= 1.0f; 395 float tx = tri ? fx : (1.0f-fx); 396 float ty = tri ? fy : (1.0f-fy); 397 const Vec4& t0 = tri ? v00 : v11; 398 const Vec4& t1 = tri ? v01 : v10; 399 const Vec4& t2 = tri ? v10 : v01; 400 Vec4 color = t0 + (t1-t0)*tx + (t2-t0)*ty; 401 402 dstAccess.setPixel(color, x0+x, y0+y); 403 } 404 } 405} 406 407bool VertexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes) 408{ 409 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 410 const int numBytesInVtx = 3; 411 const int numBytesInQuad = numBytesInVtx*4; 412 int maxQuadsX = de::min(128, renderTarget.getWidth() / VERIFY_QUAD_SIZE); 413 int maxQuadsY = de::min(128, renderTarget.getHeight() / VERIFY_QUAD_SIZE); 414 int maxQuadsPerBatch = maxQuadsX*maxQuadsY; 415 int numVerified = 0; 416 deUint32 program = m_program->getProgram(); 417 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3); 418 bool isOk = true; 419 420 vector<tcu::Vec2> positions; 421 vector<deUint16> indices; 422 423 tcu::Surface rendered; 424 tcu::Surface reference; 425 426 DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers. 427 428 computePositions(positions, maxQuadsX, maxQuadsY); 429 computeIndices(indices, maxQuadsX, maxQuadsY); 430 431 // Reset buffer bindings. 432 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); 433 glBindBuffer (GL_ARRAY_BUFFER, 0); 434 435 // Setup rendering state. 436 glViewport (0, 0, maxQuadsX*VERIFY_QUAD_SIZE, maxQuadsY*VERIFY_QUAD_SIZE); 437 glClearColor (0.0f, 0.0f, 0.0f, 1.0f); 438 glUseProgram (program); 439 glEnableVertexAttribArray (m_posLoc); 440 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]); 441 glEnableVertexAttribArray (m_byteVecLoc); 442 glBindBuffer (GL_ARRAY_BUFFER, buffer); 443 444 while (numVerified < numBytes) 445 { 446 int numRemaining = numBytes-numVerified; 447 bool isLeftoverBatch = numRemaining < numBytesInQuad; 448 int numBytesToVerify = isLeftoverBatch ? numBytesInQuad : de::min(maxQuadsPerBatch*numBytesInQuad, numRemaining - numRemaining%numBytesInQuad); 449 int curOffset = isLeftoverBatch ? (numBytes-numBytesInQuad) : numVerified; 450 int numQuads = numBytesToVerify/numBytesInQuad; 451 int numCols = de::min(maxQuadsX, numQuads); 452 int numRows = numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0); 453 string imageSetDesc = string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1); 454 455 DE_ASSERT(numBytesToVerify > 0 && numBytesToVerify%numBytesInQuad == 0); 456 DE_ASSERT(de::inBounds(curOffset, 0, numBytes)); 457 DE_ASSERT(de::inRange(curOffset+numBytesToVerify, curOffset, numBytes)); 458 459 // Render batch. 460 glClear (GL_COLOR_BUFFER_BIT); 461 glVertexAttribPointer (m_byteVecLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const glw::GLvoid*)(deUintptr)(offset + curOffset)); 462 glDrawElements (GL_TRIANGLES, numQuads*6, GL_UNSIGNED_SHORT, &indices[0]); 463 464 renderQuadGridReference(reference, numQuads, numCols, refPtr + offset + curOffset); 465 466 rendered.setSize(numCols*VERIFY_QUAD_SIZE, numRows*VERIFY_QUAD_SIZE); 467 glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess()); 468 469 if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT)) 470 { 471 isOk = false; 472 break; 473 } 474 475 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 476 } 477 478 glDisableVertexAttribArray (m_posLoc); 479 glDisableVertexAttribArray (m_byteVecLoc); 480 481 return isOk; 482} 483 484// IndexArrayVerifier 485 486IndexArrayVerifier::IndexArrayVerifier (Context& context) 487 : BufferVerifierBase (context) 488 , m_program (DE_NULL) 489 , m_posLoc (0) 490 , m_colorLoc (0) 491{ 492 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources( 493 "attribute highp vec2 a_position;\n" 494 "attribute mediump vec3 a_color;\n" 495 "varying mediump vec3 v_color;\n" 496 "void main (void)\n" 497 "{\n" 498 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 499 " v_color = a_color;\n" 500 "}\n", 501 502 "varying mediump vec3 v_color;\n" 503 "void main (void)\n" 504 "{\n" 505 " gl_FragColor = vec4(v_color, 1.0);\n" 506 "}\n")); 507 508 if (!m_program->isOk()) 509 { 510 m_context.getTestContext().getLog() << *m_program; 511 delete m_program; 512 TCU_FAIL("Compile failed"); 513 } 514 515 const glw::Functions& funcs = context.getRenderContext().getFunctions(); 516 m_posLoc = funcs.getAttribLocation(m_program->getProgram(), "a_position"); 517 m_colorLoc = funcs.getAttribLocation(m_program->getProgram(), "a_color"); 518} 519 520IndexArrayVerifier::~IndexArrayVerifier (void) 521{ 522 delete m_program; 523} 524 525static void computeIndexVerifierPositions (std::vector<tcu::Vec2>& dst) 526{ 527 const int numPosX = 16; 528 const int numPosY = 16; 529 530 dst.resize(numPosX*numPosY); 531 532 for (int y = 0; y < numPosY; y++) 533 { 534 for (int x = 0; x < numPosX; x++) 535 { 536 float xf = float(x) / float(numPosX-1); 537 float yf = float(y) / float(numPosY-1); 538 539 dst[y*numPosX + x] = tcu::Vec2(2.0f*xf - 1.0f, 2.0f*yf - 1.0f); 540 } 541 } 542} 543 544static void computeIndexVerifierColors (std::vector<tcu::Vec3>& dst) 545{ 546 const int numColors = 256; 547 const float minVal = 0.1f; 548 const float maxVal = 0.5f; 549 de::Random rnd (0xabc231); 550 551 dst.resize(numColors); 552 553 for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i) 554 { 555 i->x() = rnd.getFloat(minVal, maxVal); 556 i->y() = rnd.getFloat(minVal, maxVal); 557 i->z() = rnd.getFloat(minVal, maxVal); 558 } 559} 560 561template<typename T> 562static void execVertexFetch (T* dst, const T* src, const deUint8* indices, int numIndices) 563{ 564 for (int i = 0; i < numIndices; ++i) 565 dst[i] = src[indices[i]]; 566} 567 568bool IndexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes) 569{ 570 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 571 const int viewportW = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, renderTarget.getWidth()); 572 const int viewportH = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, renderTarget.getHeight()); 573 const int minBytesPerBatch = 2; 574 const tcu::RGBA threshold (0,0,0,0); 575 576 std::vector<tcu::Vec2> positions; 577 std::vector<tcu::Vec3> colors; 578 579 std::vector<tcu::Vec2> fetchedPos (MAX_LINES_PER_INDEX_ARRAY_DRAW+1); 580 std::vector<tcu::Vec3> fetchedColor (MAX_LINES_PER_INDEX_ARRAY_DRAW+1); 581 582 tcu::Surface indexBufferImg (viewportW, viewportH); 583 tcu::Surface referenceImg (viewportW, viewportH); 584 585 int numVerified = 0; 586 bool isOk = true; 587 588 DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float)*2); 589 DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float)*3); 590 591 computeIndexVerifierPositions(positions); 592 computeIndexVerifierColors(colors); 593 594 // Reset buffer bindings. 595 glBindBuffer (GL_ARRAY_BUFFER, 0); 596 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer); 597 598 // Setup rendering state. 599 glViewport (0, 0, viewportW, viewportH); 600 glClearColor (0.0f, 0.0f, 0.0f, 1.0f); 601 glUseProgram (m_program->getProgram()); 602 glEnableVertexAttribArray (m_posLoc); 603 glEnableVertexAttribArray (m_colorLoc); 604 glEnable (GL_BLEND); 605 glBlendFunc (GL_ONE, GL_ONE); 606 glBlendEquation (GL_FUNC_ADD); 607 608 while (numVerified < numBytes) 609 { 610 int numRemaining = numBytes-numVerified; 611 bool isLeftoverBatch = numRemaining < minBytesPerBatch; 612 int numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : de::min(MAX_LINES_PER_INDEX_ARRAY_DRAW+1, numRemaining); 613 int curOffset = isLeftoverBatch ? (numBytes-minBytesPerBatch) : numVerified; 614 string imageSetDesc = string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1); 615 616 // Step 1: Render using index buffer. 617 glClear (GL_COLOR_BUFFER_BIT); 618 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]); 619 glVertexAttribPointer (m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &colors[0]); 620 glDrawElements (GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void*)(deUintptr)(offset+curOffset)); 621 glu::readPixels (m_context.getRenderContext(), 0, 0, indexBufferImg.getAccess()); 622 623 // Step 2: Do manual fetch and render without index buffer. 624 execVertexFetch(&fetchedPos[0], &positions[0], refPtr+offset+curOffset, numBytesToVerify); 625 execVertexFetch(&fetchedColor[0], &colors[0], refPtr+offset+curOffset, numBytesToVerify); 626 627 glClear (GL_COLOR_BUFFER_BIT); 628 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &fetchedPos[0]); 629 glVertexAttribPointer (m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &fetchedColor[0]); 630 glDrawArrays (GL_LINE_STRIP, 0, numBytesToVerify); 631 glu::readPixels (m_context.getRenderContext(), 0, 0, referenceImg.getAccess()); 632 633 if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(), referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT)) 634 { 635 isOk = false; 636 break; 637 } 638 639 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 640 } 641 642 return isOk; 643} 644 645} // BufferTestUtil 646} // Functional 647} // gles2 648} // deqp 649