1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Buffer test utilities.
22 *//*--------------------------------------------------------------------*/
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"
38 #include "deStringUtil.hpp"
39 #include "deArrayUtil.hpp"
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
50 namespace BufferTestUtil
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
68 void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
70 std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
73 bool compareByteArrays (tcu::TestLog& log, const deUint8* resPtr, const deUint8* refPtr, int numBytes)
76 const int maxSpanLen = 8;
77 const int maxDiffSpans = 4;
79 int diffSpanStart = -1;
82 log << TestLog::Section("Verify", "Verification result");
84 for (;ndx < numBytes; ndx++)
86 if (resPtr[ndx] != refPtr[ndx])
88 if (diffSpanStart < 0)
93 else if (diffSpanStart >= 0)
95 if (numDiffSpans < maxDiffSpans)
97 int len = ndx-diffSpanStart;
98 int printLen = de::min(len, maxSpanLen);
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;
106 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
113 if (diffSpanStart >= 0)
115 if (numDiffSpans < maxDiffSpans)
117 int len = ndx-diffSpanStart;
118 int printLen = de::min(len, maxSpanLen);
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;
126 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
129 log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage;
130 log << TestLog::EndSection;
135 const char* getBufferTargetName (deUint32 target)
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";
154 const char* getUsageHintName (deUint32 hint)
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";
175 BufferCase::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)
182 BufferCase::~BufferCase (void)
184 enableLogging(false);
185 BufferCase::deinit();
188 void BufferCase::init (void)
193 void BufferCase::deinit (void)
195 for (set<deUint32>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end(); bufIter++)
196 glDeleteBuffers(1, &(*bufIter));
199 deUint32 BufferCase::genBuffer (void)
202 glGenBuffers(1, &buf);
207 m_allocatedBuffers.insert(buf);
209 catch (const std::exception&)
211 glDeleteBuffers(1, &buf);
218 void BufferCase::deleteBuffer (deUint32 buffer)
220 glDeleteBuffers(1, &buffer);
221 m_allocatedBuffers.erase(buffer);
224 void BufferCase::checkError (void)
226 glw::GLenum err = glGetError();
227 if (err != GL_NO_ERROR)
228 throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
233 void ReferenceBuffer::setSize (int numBytes)
235 m_data.resize(numBytes);
238 void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
240 m_data.resize(numBytes);
241 std::copy(bytes, bytes+numBytes, m_data.begin());
244 void ReferenceBuffer::setSubData (int offset, int numBytes, const deUint8* bytes)
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);
252 BufferWriterBase::BufferWriterBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
253 : CallLogWrapper (renderCtx.getFunctions(), log)
254 , m_renderCtx (renderCtx)
259 void BufferWriterBase::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint)
261 DE_UNREF(targetHint);
262 write(buffer, offset, numBytes, bytes);
267 BufferWriter::BufferWriter (glu::RenderContext& renderCtx, tcu::TestLog& log, WriteType writeType)
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;
275 TCU_FAIL("Unsupported writer");
279 BufferWriter::~BufferWriter (void)
284 void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
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);
292 void BufferWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 targetHint)
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);
300 // BufferSubDataWriter
302 void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
304 write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
307 void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target)
309 glBindBuffer(target, buffer);
310 glBufferSubData(target, offset, numBytes, bytes);
311 glBindBuffer(target, 0);
315 // BufferWriteMapWriter
317 void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
319 write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
322 void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes, deUint32 target)
324 glBindBuffer(target, buffer);
326 void* ptr = glMapBufferRange(target, offset, numBytes, GL_MAP_WRITE_BIT);
327 GLU_CHECK_MSG("glMapBufferRange");
329 deMemcpy(ptr, bytes, numBytes);
331 glUnmapBuffer(target);
332 glBindBuffer(target, 0);
336 // BufferVerifierBase
338 BufferVerifierBase::BufferVerifierBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
339 : CallLogWrapper (renderCtx.getFunctions(), log)
340 , m_renderCtx (renderCtx)
346 bool BufferVerifierBase::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint)
348 DE_UNREF(targetHint);
349 return verify(buffer, reference, offset, numBytes);
354 BufferVerifier::BufferVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log, VerifyType verifyType)
355 : m_verifier(DE_NULL)
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;
363 TCU_FAIL("Unsupported verifier");
367 BufferVerifier::~BufferVerifier (void)
372 bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
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);
380 bool BufferVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 targetHint)
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);
390 bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
392 return verify(buffer, reference, offset, numBytes, GL_ARRAY_BUFFER);
395 bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes, deUint32 target)
397 const deUint8* mapPtr = DE_NULL;
400 glBindBuffer(target, buffer);
401 mapPtr = (const deUint8*)glMapBufferRange(target, offset, numBytes, GL_MAP_READ_BIT);
402 GLU_CHECK_MSG("glMapBufferRange");
405 isOk = compareByteArrays(m_log, mapPtr, reference+offset, numBytes);
407 glUnmapBuffer(target);
408 GLU_CHECK_MSG("glUnmapBuffer");
410 glBindBuffer(target, 0);
415 // VertexArrayVerifier
417 VertexArrayVerifier::VertexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log)
418 : BufferVerifierBase (renderCtx, log)
419 , m_program (DE_NULL)
424 const glu::ContextType ctxType = renderCtx.getType();
425 const glu::GLSLVersion glslVersion = glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
427 DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion));
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"
436 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
437 " v_byteVec = a_byteVec;\n"
440 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
441 "in mediump vec3 v_byteVec;\n"
442 "layout(location = 0) out mediump vec4 o_color;\n"
445 " o_color = vec4(v_byteVec, 1.0);\n"
448 if (!m_program->isOk())
452 TCU_FAIL("Compile failed");
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");
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");
465 VertexArrayVerifier::~VertexArrayVerifier (void)
467 const glw::Functions& gl = m_renderCtx.getFunctions();
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);
476 static void computePositions (vector<tcu::Vec2>& positions, int gridSizeX, int gridSizeY)
478 positions.resize(gridSizeX*gridSizeY*4);
480 for (int y = 0; y < gridSizeY; y++)
481 for (int x = 0; x < gridSizeX; x++)
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;
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);
500 static void computeIndices (vector<deUint16>& indices, int gridSizeX, int gridSizeY)
502 indices.resize(3 * 2 * gridSizeX * gridSizeY);
504 for (int quadNdx = 0; quadNdx < gridSizeX*gridSizeY; quadNdx++)
506 int v00 = quadNdx*4 + 0;
507 int v01 = quadNdx*4 + 1;
508 int v10 = quadNdx*4 + 2;
509 int v11 = quadNdx*4 + 3;
511 DE_ASSERT(v11 < (1<<16));
513 indices[quadNdx*6 + 0] = (deUint16)v10;
514 indices[quadNdx*6 + 1] = (deUint16)v00;
515 indices[quadNdx*6 + 2] = (deUint16)v01;
517 indices[quadNdx*6 + 3] = (deUint16)v10;
518 indices[quadNdx*6 + 4] = (deUint16)v01;
519 indices[quadNdx*6 + 5] = (deUint16)v11;
523 static inline tcu::Vec4 fetchVtxColor (const deUint8* ptr, int vtxNdx)
525 return tcu::RGBA(*(ptr + vtxNdx*3 + 0),
526 *(ptr + vtxNdx*3 + 1),
527 *(ptr + vtxNdx*3 + 2),
531 static void renderQuadGridReference (tcu::Surface& dst, int numQuads, int rowLength, const deUint8* inPtr)
535 dst.setSize(rowLength*VERIFY_QUAD_SIZE, (numQuads/rowLength + (numQuads%rowLength != 0 ? 1 : 0))*VERIFY_QUAD_SIZE);
537 tcu::PixelBufferAccess dstAccess = dst.getAccess();
538 tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff));
540 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
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);
549 for (int y = 0; y < VERIFY_QUAD_SIZE; y++)
550 for (int x = 0; x < VERIFY_QUAD_SIZE; x++)
552 float fx = (float)(x+0.5f) / (float)VERIFY_QUAD_SIZE;
553 float fy = (float)(y+0.5f) / (float)VERIFY_QUAD_SIZE;
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;
563 dstAccess.setPixel(color, x0+x, y0+y);
568 bool VertexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
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;
577 deUint32 program = m_program->getProgram();
578 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);
581 vector<tcu::Vec2> positions;
582 vector<deUint16> indices;
584 tcu::Surface rendered;
585 tcu::Surface reference;
587 DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers.
589 computePositions(positions, maxQuadsX, maxQuadsY);
590 computeIndices(indices, maxQuadsX, maxQuadsY);
592 // Reset buffer bindings.
593 glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
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);
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);
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);
611 glEnableVertexAttribArray (m_byteVecLoc);
612 glBindBuffer (GL_ARRAY_BUFFER, buffer);
614 while (numVerified < numBytes)
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);
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));
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);
634 renderQuadGridReference(reference, numQuads, numCols, refPtr + offset + curOffset);
636 rendered.setSize(numCols*VERIFY_QUAD_SIZE, numRows*VERIFY_QUAD_SIZE);
637 glu::readPixels(m_renderCtx, 0, 0, rendered.getAccess());
639 if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT))
645 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
648 glBindVertexArray(0);
653 // IndexArrayVerifier
655 IndexArrayVerifier::IndexArrayVerifier (glu::RenderContext& renderCtx, tcu::TestLog& log)
656 : BufferVerifierBase (renderCtx, log)
657 , m_program (DE_NULL)
662 const glu::ContextType ctxType = renderCtx.getType();
663 const glu::GLSLVersion glslVersion = glu::isContextTypeES(ctxType) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
665 DE_ASSERT(glu::isGLSLVersionSupported(ctxType, glslVersion));
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"
674 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
675 " v_color = a_color;\n"
678 string(glu::getGLSLVersionDeclaration(glslVersion)) + "\n"
679 "in mediump vec3 v_color;\n"
680 "layout(location = 0) out mediump vec4 o_color;\n"
683 " o_color = vec4(v_color, 1.0);\n"
686 if (!m_program->isOk())
690 TCU_FAIL("Compile failed");
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");
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");
703 IndexArrayVerifier::~IndexArrayVerifier (void)
705 const glw::Functions& gl = m_renderCtx.getFunctions();
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);
714 static void computeIndexVerifierPositions (std::vector<tcu::Vec2>& dst)
716 const int numPosX = 16;
717 const int numPosY = 16;
719 dst.resize(numPosX*numPosY);
721 for (int y = 0; y < numPosY; y++)
723 for (int x = 0; x < numPosX; x++)
725 float xf = float(x) / float(numPosX-1);
726 float yf = float(y) / float(numPosY-1);
728 dst[y*numPosX + x] = tcu::Vec2(2.0f*xf - 1.0f, 2.0f*yf - 1.0f);
733 static void computeIndexVerifierColors (std::vector<tcu::Vec3>& dst)
735 const int numColors = 256;
736 const float minVal = 0.1f;
737 const float maxVal = 0.5f;
738 de::Random rnd (0xabc231);
740 dst.resize(numColors);
742 for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i)
744 i->x() = rnd.getFloat(minVal, maxVal);
745 i->y() = rnd.getFloat(minVal, maxVal);
746 i->z() = rnd.getFloat(minVal, maxVal);
751 static void execVertexFetch (T* dst, const T* src, const deUint8* indices, int numIndices)
753 for (int i = 0; i < numIndices; ++i)
754 dst[i] = src[indices[i]];
757 bool IndexArrayVerifier::verify (deUint32 buffer, const deUint8* refPtr, int offset, int numBytes)
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);
765 std::vector<tcu::Vec2> positions;
766 std::vector<tcu::Vec3> colors;
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);
771 tcu::Surface indexBufferImg (viewportW, viewportH);
772 tcu::Surface referenceImg (viewportW, viewportH);
777 DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float)*2);
778 DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float)*3);
780 computeIndexVerifierPositions(positions);
781 computeIndexVerifierColors(colors);
783 // Reset buffer bindings.
784 glBindVertexArray (m_vao);
785 glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
786 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer);
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);
795 glBlendFunc (GL_ONE, GL_ONE);
796 glBlendEquation (GL_FUNC_ADD);
798 while (numVerified < numBytes)
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);
806 // Step 1: Render using index buffer.
807 glClear (GL_COLOR_BUFFER_BIT);
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);
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);
817 glDrawElements (GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void*)(deUintptr)(offset+curOffset));
818 glu::readPixels (m_renderCtx, 0, 0, indexBufferImg.getAccess());
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);
824 glClear (GL_COLOR_BUFFER_BIT);
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);
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);
834 glDrawArrays (GL_LINE_STRIP, 0, numBytesToVerify);
835 glu::readPixels (m_renderCtx, 0, 0, referenceImg.getAccess());
837 if (!tcu::pixelThresholdCompare(m_log, "RenderResult", imageSetDesc.c_str(), referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT))
843 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
846 glBindVertexArray(0);
851 const char* getWriteTypeDescription (WriteType write)
853 static const char* s_desc[] =
856 "glMapBufferRange()",
857 "transform feedback",
858 "glReadPixels() into PBO binding"
860 return de::getSizedArrayElement<WRITE_LAST>(s_desc, write);
863 const char* getVerifyTypeDescription (VerifyType verify)
865 static const char* s_desc[] =
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()"
873 return de::getSizedArrayElement<VERIFY_LAST>(s_desc, verify);