1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL (ES) 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 "glsBufferTestUtil.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 "tcuTestLog.hpp" 33#include "gluPixelTransfer.hpp" 34#include "gluRenderContext.hpp" 35#include "gluStrUtil.hpp" 36#include "gluShaderProgram.hpp" 37#include "deMemory.h" 38#include "deStringUtil.hpp" 39 40#include <algorithm> 41 42#include "glwEnums.hpp" 43#include "glwFunctions.hpp" 44 45namespace deqp 46{ 47namespace gls 48{ 49namespace BufferTestUtil 50{ 51 52enum 53{ 54 VERIFY_QUAD_SIZE = 8, //!< Quad size in VertexArrayVerifier 55 MAX_LINES_PER_INDEX_ARRAY_DRAW = 128, //!< Maximum number of lines per one draw in IndexArrayVerifier 56 INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128, 57 INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128 58}; 59 60using tcu::TestLog; 61using std::vector; 62using std::string; 63using std::set; 64 65// Helper functions. 66 67void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed) 68{ 69 std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr); 70} 71 72bool compareByteArrays (tcu::TestLog& log, const deUint8* resPtr, const deUint8* refPtr, int numBytes) 73{ 74 bool isOk = true; 75 const int maxSpanLen = 8; 76 const int maxDiffSpans = 4; 77 int numDiffSpans = 0; 78 int diffSpanStart = -1; 79 int ndx = 0; 80 81 log << TestLog::Section("Verify", "Verification result"); 82 83 for (;ndx < numBytes; ndx++) 84 { 85 if (resPtr[ndx] != refPtr[ndx]) 86 { 87 if (diffSpanStart < 0) 88 diffSpanStart = ndx; 89 90 isOk = false; 91 } 92 else if (diffSpanStart >= 0) 93 { 94 if (numDiffSpans < maxDiffSpans) 95 { 96 int len = ndx-diffSpanStart; 97 int printLen = de::min(len, maxSpanLen); 98 99 log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n" 100 << " expected " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n" 101 << " got " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen)) 102 << TestLog::EndMessage; 103 } 104 else 105 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage; 106 107 numDiffSpans += 1; 108 diffSpanStart = -1; 109 } 110 } 111 112 if (diffSpanStart >= 0) 113 { 114 if (numDiffSpans < maxDiffSpans) 115 { 116 int len = ndx-diffSpanStart; 117 int printLen = de::min(len, maxSpanLen); 118 119 log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n" 120 << " expected " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(refPtr+diffSpanStart+printLen)) << "\n" 121 << " got " << tcu::formatArray(tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart), tcu::Format::HexIterator<deUint8>(resPtr+diffSpanStart+printLen)) 122 << TestLog::EndMessage; 123 } 124 else 125 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage; 126 } 127 128 log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage; 129 log << TestLog::EndSection; 130 131 return isOk; 132} 133 134const char* getBufferTargetName (deUint32 target) 135{ 136 switch (target) 137 { 138 case GL_ARRAY_BUFFER: return "array"; 139 case GL_COPY_READ_BUFFER: return "copy_read"; 140 case GL_COPY_WRITE_BUFFER: return "copy_write"; 141 case GL_ELEMENT_ARRAY_BUFFER: return "element_array"; 142 case GL_PIXEL_PACK_BUFFER: return "pixel_pack"; 143 case GL_PIXEL_UNPACK_BUFFER: return "pixel_unpack"; 144 case GL_TEXTURE_BUFFER: return "texture"; 145 case GL_TRANSFORM_FEEDBACK_BUFFER: return "transform_feedback"; 146 case GL_UNIFORM_BUFFER: return "uniform"; 147 default: 148 DE_ASSERT(false); 149 return DE_NULL; 150 } 151} 152 153const char* getUsageHintName (deUint32 hint) 154{ 155 switch (hint) 156 { 157 case GL_STREAM_DRAW: return "stream_draw"; 158 case GL_STREAM_READ: return "stream_read"; 159 case GL_STREAM_COPY: return "stream_copy"; 160 case GL_STATIC_DRAW: return "static_draw"; 161 case GL_STATIC_READ: return "static_read"; 162 case GL_STATIC_COPY: return "static_copy"; 163 case GL_DYNAMIC_DRAW: return "dynamic_draw"; 164 case GL_DYNAMIC_READ: return "dynamic_read"; 165 case GL_DYNAMIC_COPY: return "dynamic_copy"; 166 default: 167 DE_ASSERT(false); 168 return DE_NULL; 169 } 170} 171 172// BufferCase 173 174BufferCase::BufferCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description) 175 : TestCase (testCtx, name, description) 176 , CallLogWrapper (renderCtx.getFunctions(), testCtx.getLog()) 177 , m_renderCtx (renderCtx) 178{ 179} 180 181BufferCase::~BufferCase (void) 182{ 183 enableLogging(false); 184 BufferCase::deinit(); 185} 186 187void BufferCase::init (void) 188{ 189 enableLogging(true); 190} 191 192void BufferCase::deinit (void) 193{ 194 for (set<deUint32>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end(); bufIter++) 195 glDeleteBuffers(1, &(*bufIter)); 196} 197 198deUint32 BufferCase::genBuffer (void) 199{ 200 deUint32 buf = 0; 201 glGenBuffers(1, &buf); 202 if (buf != 0) 203 { 204 try 205 { 206 m_allocatedBuffers.insert(buf); 207 } 208 catch (const std::exception&) 209 { 210 glDeleteBuffers(1, &buf); 211 throw; 212 } 213 } 214 return buf; 215} 216 217void BufferCase::deleteBuffer (deUint32 buffer) 218{ 219 glDeleteBuffers(1, &buffer); 220 m_allocatedBuffers.erase(buffer); 221} 222 223void BufferCase::checkError (void) 224{ 225 glw::GLenum err = glGetError(); 226 if (err != GL_NO_ERROR) 227 throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString()); 228} 229 230// ReferenceBuffer 231 232void ReferenceBuffer::setSize (int numBytes) 233{ 234 m_data.resize(numBytes); 235} 236 237void ReferenceBuffer::setData (int numBytes, const deUint8* bytes) 238{ 239 m_data.resize(numBytes); 240 std::copy(bytes, bytes+numBytes, m_data.begin()); 241} 242 243void ReferenceBuffer::setSubData (int offset, int numBytes, const deUint8* bytes) 244{ 245 DE_ASSERT(de::inBounds(offset, 0, (int)m_data.size()) && de::inRange(offset+numBytes, offset, (int)m_data.size())); 246 std::copy(bytes, bytes+numBytes, m_data.begin()+offset); 247} 248 249// BufferWriterBase 250 251BufferWriterBase::BufferWriterBase (glu::RenderContext& renderCtx, tcu::TestLog& log) 252 : CallLogWrapper (renderCtx.getFunctions(), log) 253 , m_renderCtx (renderCtx) 254{ 255 enableLogging(true); 256} 257 258void BufferWriterBase::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint) 259{ 260 DE_UNREF(targetHint); 261 write(buffer, offset, numBytes, bytes); 262} 263 264// BufferWriter 265 266BufferWriter::BufferWriter (glu::RenderContext& renderCtx, tcu::TestLog& log, WriteType writeType) 267 : m_writer(DE_NULL) 268{ 269 switch (writeType) 270 { 271 case WRITE_BUFFER_SUB_DATA: m_writer = new BufferSubDataWriter (renderCtx, log); break; 272 case WRITE_BUFFER_WRITE_MAP: m_writer = new BufferWriteMapWriter (renderCtx, log); break; 273 default: 274 TCU_FAIL("Unsupported writer"); 275 } 276} 277 278BufferWriter::~BufferWriter (void) 279{ 280 delete m_writer; 281} 282 283void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes) 284{ 285 DE_ASSERT(numBytes >= getMinSize()); 286 DE_ASSERT(offset%getAlignment() == 0); 287 DE_ASSERT((offset+numBytes)%getAlignment() == 0); 288 return m_writer->write(buffer, offset, numBytes, bytes); 289} 290 291void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint) 292{ 293 DE_ASSERT(numBytes >= getMinSize()); 294 DE_ASSERT(offset%getAlignment() == 0); 295 DE_ASSERT((offset+numBytes)%getAlignment() == 0); 296 return m_writer->write(buffer, offset, numBytes, bytes, targetHint); 297} 298 299// BufferSubDataWriter 300 301void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes) 302{ 303 write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER); 304} 305 306void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target) 307{ 308 glBindBuffer(target, buffer); 309 glBufferSubData(target, offset, numBytes, bytes); 310 glBindBuffer(target, 0); 311 GLU_CHECK(); 312} 313 314// BufferWriteMapWriter 315 316void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes) 317{ 318 write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER); 319} 320 321void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target) 322{ 323 glBindBuffer(target, buffer); 324 325 void* ptr = glMapBufferRange(target, offset, numBytes, GL_MAP_WRITE_BIT); 326 GLU_CHECK_MSG("glMapBufferRange"); 327 328 deMemcpy(ptr, bytes, numBytes); 329 330 glUnmapBuffer(target); 331 glBindBuffer(target, 0); 332 GLU_CHECK(); 333} 334 335// BufferVerifierBase 336 337BufferVerifierBase::BufferVerifierBase (glu::RenderContext& renderCtx, tcu::TestLog& log) 338 : CallLogWrapper (renderCtx.getFunctions(), log) 339 , m_renderCtx (renderCtx) 340 , m_log (log) 341{ 342 enableLogging(true); 343} 344 345bool BufferVerifierBase::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint) 346{ 347 DE_UNREF(targetHint); 348 return verify(buffer, reference, offset, numBytes); 349} 350 351// BufferVerifier 352 353BufferVerifier::BufferVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log, VerifyType verifyType) 354 : m_verifier(DE_NULL) 355{ 356 switch (verifyType) 357 { 358 case VERIFY_AS_VERTEX_ARRAY: m_verifier = new VertexArrayVerifier(renderCtx, log); break; 359 case VERIFY_AS_INDEX_ARRAY: m_verifier = new IndexArrayVerifier (renderCtx, log); break; 360 case VERIFY_BUFFER_READ_MAP: m_verifier = new BufferMapVerifier (renderCtx, log); break; 361 default: 362 TCU_FAIL("Unsupported verifier"); 363 } 364} 365 366BufferVerifier::~BufferVerifier (void) 367{ 368 delete m_verifier; 369} 370 371bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes) 372{ 373 DE_ASSERT(numBytes >= getMinSize()); 374 DE_ASSERT(offset%getAlignment() == 0); 375 DE_ASSERT((offset+numBytes)%getAlignment() == 0); 376 return m_verifier->verify(buffer, reference, offset, numBytes); 377} 378 379bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint) 380{ 381 DE_ASSERT(numBytes >= getMinSize()); 382 DE_ASSERT(offset%getAlignment() == 0); 383 DE_ASSERT((offset+numBytes)%getAlignment() == 0); 384 return m_verifier->verify(buffer, reference, offset, numBytes, targetHint); 385} 386 387// BufferMapVerifier 388 389bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes) 390{ 391 return verify(buffer, reference, offset, numBytes, GL_ARRAY_BUFFER); 392} 393 394bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 target) 395{ 396 const deUint8* mapPtr = DE_NULL; 397 bool isOk = false; 398 399 glBindBuffer(target, buffer); 400 mapPtr = (const deUint8*)glMapBufferRange(target, offset, numBytes, GL_MAP_READ_BIT); 401 GLU_CHECK_MSG("glMapBufferRange"); 402 TCU_CHECK(mapPtr); 403 404 isOk = compareByteArrays(m_log, mapPtr, reference+offset, numBytes); 405 406 glUnmapBuffer(target); 407 GLU_CHECK_MSG("glUnmapBuffer"); 408 409 glBindBuffer(target, 0); 410 411 return isOk; 412} 413 414// VertexArrayVerifier 415 416VertexArrayVerifier::VertexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log) 417 : BufferVerifierBase (renderCtx, log) 418 , m_program (DE_NULL) 419 , m_posLoc (0) 420 , m_byteVecLoc (0) 421 , m_vao (0) 422{ 423 const glu::ContextType ctxType = renderCtx.getType(); 424 const glu::GLSLVersion glslVersion = glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330; 425 426 DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion)); 427 428 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources( 429 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n" 430 "in highp vec2 a_position;\n" 431 "in mediump vec3 a_byteVec;\n" 432 "out mediump vec3 v_byteVec;\n" 433 "void main (void)\n" 434 "{\n" 435 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 436 " v_byteVec = a_byteVec;\n" 437 "}\n", 438 439 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n" 440 "in mediump vec3 v_byteVec;\n" 441 "layout(location = 0) out mediump vec4 o_color;\n" 442 "void main (void)\n" 443 "{\n" 444 " o_color = vec4(v_byteVec, 1.0);\n" 445 "}\n")); 446 447 if (!m_program->isOk()) 448 { 449 m_log << *m_program; 450 delete m_program; 451 TCU_FAIL("Compile failed"); 452 } 453 454 const glw::Functions& gl = m_renderCtx.getFunctions(); 455 m_posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position"); 456 m_byteVecLoc = gl.getAttribLocation(m_program->getProgram(), "a_byteVec"); 457 458 gl.genVertexArrays(1, &m_vao); 459 gl.genBuffers(1, &m_positionBuf); 460 gl.genBuffers(1, &m_indexBuf); 461 GLU_EXPECT_NO_ERROR(gl.getError(), "Initialization failed"); 462} 463 464VertexArrayVerifier::~VertexArrayVerifier (void) 465{ 466 const glw::Functions& gl = m_renderCtx.getFunctions(); 467 468 if (m_vao) gl.deleteVertexArrays(1, &m_vao); 469 if (m_positionBuf) gl.deleteBuffers(1, &m_positionBuf); 470 if (m_indexBuf) gl.deleteBuffers(1, &m_indexBuf); 471 472 delete m_program; 473} 474 475static void computePositions (vector<tcu::Vec2>& positions, int gridSizeX, int gridSizeY) 476{ 477 positions.resize(gridSizeX*gridSizeY*4); 478 479 for (int y = 0; y < gridSizeY; y++) 480 for (int x = 0; x < gridSizeX; x++) 481 { 482 float sx0 = (x+0) / (float)gridSizeX; 483 float sy0 = (y+0) / (float)gridSizeY; 484 float sx1 = (x+1) / (float)gridSizeX; 485 float sy1 = (y+1) / (float)gridSizeY; 486 float fx0 = 2.0f * sx0 - 1.0f; 487 float fy0 = 2.0f * sy0 - 1.0f; 488 float fx1 = 2.0f * sx1 - 1.0f; 489 float fy1 = 2.0f * sy1 - 1.0f; 490 int baseNdx = (y * gridSizeX + x)*4; 491 492 positions[baseNdx+0] = tcu::Vec2(fx0, fy0); 493 positions[baseNdx+1] = tcu::Vec2(fx0, fy1); 494 positions[baseNdx+2] = tcu::Vec2(fx1, fy0); 495 positions[baseNdx+3] = tcu::Vec2(fx1, fy1); 496 } 497} 498 499static void computeIndices (vector<deUint16>& indices, int gridSizeX, int gridSizeY) 500{ 501 indices.resize(3 * 2 * gridSizeX * gridSizeY); 502 503 for (int quadNdx = 0; quadNdx < gridSizeX*gridSizeY; quadNdx++) 504 { 505 int v00 = quadNdx*4 + 0; 506 int v01 = quadNdx*4 + 1; 507 int v10 = quadNdx*4 + 2; 508 int v11 = quadNdx*4 + 3; 509 510 DE_ASSERT(v11 < (1<<16)); 511 512 indices[quadNdx*6 + 0] = (deUint16)v10; 513 indices[quadNdx*6 + 1] = (deUint16)v00; 514 indices[quadNdx*6 + 2] = (deUint16)v01; 515 516 indices[quadNdx*6 + 3] = (deUint16)v10; 517 indices[quadNdx*6 + 4] = (deUint16)v01; 518 indices[quadNdx*6 + 5] = (deUint16)v11; 519 } 520} 521 522static inline tcu::Vec4 fetchVtxColor (const deUint8* ptr, int vtxNdx) 523{ 524 return tcu::RGBA(*(ptr + vtxNdx*3 + 0), 525 *(ptr + vtxNdx*3 + 1), 526 *(ptr + vtxNdx*3 + 2), 527 255).toVec(); 528} 529 530static void renderQuadGridReference (tcu::Surface& dst, int numQuads, int rowLength, const deUint8* inPtr) 531{ 532 using tcu::Vec4; 533 534 dst.setSize(rowLength*VERIFY_QUAD_SIZE, (numQuads/rowLength + (numQuads%rowLength != 0 ? 1 : 0))*VERIFY_QUAD_SIZE); 535 536 tcu::PixelBufferAccess dstAccess = dst.getAccess(); 537 tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff)); 538 539 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) 540 { 541 int x0 = (quadNdx%rowLength)*VERIFY_QUAD_SIZE; 542 int y0 = (quadNdx/rowLength)*VERIFY_QUAD_SIZE; 543 Vec4 v00 = fetchVtxColor(inPtr, quadNdx*4 + 0); 544 Vec4 v10 = fetchVtxColor(inPtr, quadNdx*4 + 1); 545 Vec4 v01 = fetchVtxColor(inPtr, quadNdx*4 + 2); 546 Vec4 v11 = fetchVtxColor(inPtr, quadNdx*4 + 3); 547 548 for (int y = 0; y < VERIFY_QUAD_SIZE; y++) 549 for (int x = 0; x < VERIFY_QUAD_SIZE; x++) 550 { 551 float fx = (float)(x+0.5f) / (float)VERIFY_QUAD_SIZE; 552 float fy = (float)(y+0.5f) / (float)VERIFY_QUAD_SIZE; 553 554 bool tri = fx + fy <= 1.0f; 555 float tx = tri ? fx : (1.0f-fx); 556 float ty = tri ? fy : (1.0f-fy); 557 const Vec4& t0 = tri ? v00 : v11; 558 const Vec4& t1 = tri ? v01 : v10; 559 const Vec4& t2 = tri ? v10 : v01; 560 Vec4 color = t0 + (t1-t0)*tx + (t2-t0)*ty; 561 562 dstAccess.setPixel(color, x0+x, y0+y); 563 } 564 } 565} 566 567bool VertexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes) 568{ 569 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget(); 570 const int numBytesInVtx = 3; 571 const int numBytesInQuad = numBytesInVtx*4; 572 int maxQuadsX = de::min(128, renderTarget.getWidth() / VERIFY_QUAD_SIZE); 573 int maxQuadsY = de::min(128, renderTarget.getHeight() / VERIFY_QUAD_SIZE); 574 int maxQuadsPerBatch = maxQuadsX*maxQuadsY; 575 int numVerified = 0; 576 deUint32 program = m_program->getProgram(); 577 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3); 578 bool isOk = true; 579 580 vector<tcu::Vec2> positions; 581 vector<deUint16> indices; 582 583 tcu::Surface rendered; 584 tcu::Surface reference; 585 586 DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers. 587 588 computePositions(positions, maxQuadsX, maxQuadsY); 589 computeIndices(indices, maxQuadsX, maxQuadsY); 590 591 // Reset buffer bindings. 592 glBindBuffer (GL_PIXEL_PACK_BUFFER, 0); 593 594 // Setup rendering state. 595 glViewport (0, 0, maxQuadsX*VERIFY_QUAD_SIZE, maxQuadsY*VERIFY_QUAD_SIZE); 596 glClearColor (0.0f, 0.0f, 0.0f, 1.0f); 597 glUseProgram (program); 598 glBindVertexArray (m_vao); 599 600 // Upload positions 601 glBindBuffer (GL_ARRAY_BUFFER, m_positionBuf); 602 glBufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW); 603 glEnableVertexAttribArray (m_posLoc); 604 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL); 605 606 // Upload indices 607 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, m_indexBuf); 608 glBufferData (GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW); 609 610 glEnableVertexAttribArray (m_byteVecLoc); 611 glBindBuffer (GL_ARRAY_BUFFER, buffer); 612 613 while (numVerified < numBytes) 614 { 615 int numRemaining = numBytes-numVerified; 616 bool isLeftoverBatch = numRemaining < numBytesInQuad; 617 int numBytesToVerify = isLeftoverBatch ? numBytesInQuad : de::min(maxQuadsPerBatch*numBytesInQuad, numRemaining - numRemaining%numBytesInQuad); 618 int curOffset = isLeftoverBatch ? (numBytes-numBytesInQuad) : numVerified; 619 int numQuads = numBytesToVerify/numBytesInQuad; 620 int numCols = de::min(maxQuadsX, numQuads); 621 int numRows = numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0); 622 string imageSetDesc = string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1); 623 624 DE_ASSERT(numBytesToVerify > 0 && numBytesToVerify%numBytesInQuad == 0); 625 DE_ASSERT(de::inBounds(curOffset, 0, numBytes)); 626 DE_ASSERT(de::inRange(curOffset+numBytesToVerify, curOffset, numBytes)); 627 628 // Render batch. 629 glClear (GL_COLOR_BUFFER_BIT); 630 glVertexAttribPointer (m_byteVecLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const glw::GLvoid*)(deUintptr)(offset + curOffset)); 631 glDrawElements (GL_TRIANGLES, numQuads*6, GL_UNSIGNED_SHORT, DE_NULL); 632 633 renderQuadGridReference(reference, numQuads, numCols, refPtr + offset + curOffset); 634 635 rendered.setSize(numCols*VERIFY_QUAD_SIZE, numRows*VERIFY_QUAD_SIZE); 636 glu::readPixels(m_renderCtx, 0, 0, rendered.getAccess()); 637 638 if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT)) 639 { 640 isOk = false; 641 break; 642 } 643 644 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 645 } 646 647 glBindVertexArray(0); 648 649 return isOk; 650} 651 652// IndexArrayVerifier 653 654IndexArrayVerifier::IndexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log) 655 : BufferVerifierBase (renderCtx, log) 656 , m_program (DE_NULL) 657 , m_posLoc (0) 658 , m_colorLoc (0) 659{ 660 661 const glu::ContextType ctxType = renderCtx.getType(); 662 const glu::GLSLVersion glslVersion = glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330; 663 664 DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion)); 665 666 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources( 667 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n" 668 "in highp vec2 a_position;\n" 669 "in mediump vec3 a_color;\n" 670 "out mediump vec3 v_color;\n" 671 "void main (void)\n" 672 "{\n" 673 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 674 " v_color = a_color;\n" 675 "}\n", 676 677 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n" 678 "in mediump vec3 v_color;\n" 679 "layout(location = 0) out mediump vec4 o_color;\n" 680 "void main (void)\n" 681 "{\n" 682 " o_color = vec4(v_color, 1.0);\n" 683 "}\n")); 684 685 if (!m_program->isOk()) 686 { 687 m_log << *m_program; 688 delete m_program; 689 TCU_FAIL("Compile failed"); 690 } 691 692 const glw::Functions& gl = m_renderCtx.getFunctions(); 693 m_posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position"); 694 m_colorLoc = gl.getAttribLocation(m_program->getProgram(), "a_color"); 695 696 gl.genVertexArrays(1, &m_vao); 697 gl.genBuffers(1, &m_positionBuf); 698 gl.genBuffers(1, &m_colorBuf); 699 GLU_EXPECT_NO_ERROR(gl.getError(), "Initialization failed"); 700} 701 702IndexArrayVerifier::~IndexArrayVerifier (void) 703{ 704 const glw::Functions& gl = m_renderCtx.getFunctions(); 705 706 if (m_vao) gl.deleteVertexArrays(1, &m_vao); 707 if (m_positionBuf) gl.deleteBuffers(1, &m_positionBuf); 708 if (m_colorBuf) gl.deleteBuffers(1, &m_colorBuf); 709 710 delete m_program; 711} 712 713static void computeIndexVerifierPositions (std::vector<tcu::Vec2>& dst) 714{ 715 const int numPosX = 16; 716 const int numPosY = 16; 717 718 dst.resize(numPosX*numPosY); 719 720 for (int y = 0; y < numPosY; y++) 721 { 722 for (int x = 0; x < numPosX; x++) 723 { 724 float xf = float(x) / float(numPosX-1); 725 float yf = float(y) / float(numPosY-1); 726 727 dst[y*numPosX + x] = tcu::Vec2(2.0f*xf - 1.0f, 2.0f*yf - 1.0f); 728 } 729 } 730} 731 732static void computeIndexVerifierColors (std::vector<tcu::Vec3>& dst) 733{ 734 const int numColors = 256; 735 const float minVal = 0.1f; 736 const float maxVal = 0.5f; 737 de::Random rnd (0xabc231); 738 739 dst.resize(numColors); 740 741 for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i) 742 { 743 i->x() = rnd.getFloat(minVal, maxVal); 744 i->y() = rnd.getFloat(minVal, maxVal); 745 i->z() = rnd.getFloat(minVal, maxVal); 746 } 747} 748 749template<typename T> 750static void execVertexFetch (T* dst, const T* src, const deUint8* indices, int numIndices) 751{ 752 for (int i = 0; i < numIndices; ++i) 753 dst[i] = src[indices[i]]; 754} 755 756bool IndexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes) 757{ 758 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget(); 759 const int viewportW = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, renderTarget.getWidth()); 760 const int viewportH = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, renderTarget.getHeight()); 761 const int minBytesPerBatch = 2; 762 const tcu::RGBA threshold (0,0,0,0); 763 764 std::vector<tcu::Vec2> positions; 765 std::vector<tcu::Vec3> colors; 766 767 std::vector<tcu::Vec2> fetchedPos (MAX_LINES_PER_INDEX_ARRAY_DRAW+1); 768 std::vector<tcu::Vec3> fetchedColor (MAX_LINES_PER_INDEX_ARRAY_DRAW+1); 769 770 tcu::Surface indexBufferImg (viewportW, viewportH); 771 tcu::Surface referenceImg (viewportW, viewportH); 772 773 int numVerified = 0; 774 bool isOk = true; 775 776 DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float)*2); 777 DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float)*3); 778 779 computeIndexVerifierPositions(positions); 780 computeIndexVerifierColors(colors); 781 782 // Reset buffer bindings. 783 glBindVertexArray (m_vao); 784 glBindBuffer (GL_PIXEL_PACK_BUFFER, 0); 785 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer); 786 787 // Setup rendering state. 788 glViewport (0, 0, viewportW, viewportH); 789 glClearColor (0.0f, 0.0f, 0.0f, 1.0f); 790 glUseProgram (m_program->getProgram()); 791 glEnableVertexAttribArray (m_posLoc); 792 glEnableVertexAttribArray (m_colorLoc); 793 glEnable (GL_BLEND); 794 glBlendFunc (GL_ONE, GL_ONE); 795 glBlendEquation (GL_FUNC_ADD); 796 797 while (numVerified < numBytes) 798 { 799 int numRemaining = numBytes-numVerified; 800 bool isLeftoverBatch = numRemaining < minBytesPerBatch; 801 int numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : de::min(MAX_LINES_PER_INDEX_ARRAY_DRAW+1, numRemaining); 802 int curOffset = isLeftoverBatch ? (numBytes-minBytesPerBatch) : numVerified; 803 string imageSetDesc = string("Bytes ") + de::toString(offset+curOffset) + " to " + de::toString(offset+curOffset+numBytesToVerify-1); 804 805 // Step 1: Render using index buffer. 806 glClear (GL_COLOR_BUFFER_BIT); 807 808 glBindBuffer (GL_ARRAY_BUFFER, m_positionBuf); 809 glBufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STREAM_DRAW); 810 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL); 811 812 glBindBuffer (GL_ARRAY_BUFFER, m_colorBuf); 813 glBufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STREAM_DRAW); 814 glVertexAttribPointer (m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); 815 816 glDrawElements (GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void*)(deUintptr)(offset+curOffset)); 817 glu::readPixels (m_renderCtx, 0, 0, indexBufferImg.getAccess()); 818 819 // Step 2: Do manual fetch and render without index buffer. 820 execVertexFetch(&fetchedPos[0], &positions[0], refPtr+offset+curOffset, numBytesToVerify); 821 execVertexFetch(&fetchedColor[0], &colors[0], refPtr+offset+curOffset, numBytesToVerify); 822 823 glClear (GL_COLOR_BUFFER_BIT); 824 825 glBindBuffer (GL_ARRAY_BUFFER, m_positionBuf); 826 glBufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(fetchedPos.size()*sizeof(fetchedPos[0])), &fetchedPos[0], GL_STREAM_DRAW); 827 glVertexAttribPointer (m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL); 828 829 glBindBuffer (GL_ARRAY_BUFFER, m_colorBuf); 830 glBufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(fetchedColor.size()*sizeof(fetchedColor[0])), &fetchedColor[0], GL_STREAM_DRAW); 831 glVertexAttribPointer (m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); 832 833 glDrawArrays (GL_LINE_STRIP, 0, numBytesToVerify); 834 glu::readPixels (m_renderCtx, 0, 0, referenceImg.getAccess()); 835 836 if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT)) 837 { 838 isOk = false; 839 break; 840 } 841 842 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 843 } 844 845 glBindVertexArray(0); 846 847 return isOk; 848} 849 850const char* getWriteTypeDescription (WriteType write) 851{ 852 static const char* s_desc[] = 853 { 854 "glBufferSubData()", 855 "glMapBufferRange()", 856 "transform feedback", 857 "glReadPixels() into PBO binding" 858 }; 859 return de::getSizedArrayElement<WRITE_LAST>(s_desc, write); 860} 861 862const char* getVerifyTypeDescription (VerifyType verify) 863{ 864 static const char* s_desc[] = 865 { 866 "rendering as vertex data", 867 "rendering as index data", 868 "reading in shader as uniform buffer data", 869 "using as PBO and uploading to texture", 870 "reading back using glMapBufferRange()" 871 }; 872 return de::getSizedArrayElement<VERIFY_LAST>(s_desc, verify); 873} 874 875} // BufferTestUtil 876} // gls 877} // deqp 878