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