Increase threshold in ES2 frag op and buffer tests am: ce69f90677
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fBufferTestUtil.cpp
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
44 namespace deqp
45 {
46 namespace gles2
47 {
48 namespace Functional
49 {
50 namespace BufferTestUtil
51 {
52
53 enum
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
61 static const bool LOG_VERIFIER_CALLS = false; //! \note Especially array verifier generates a lot of calls.
62
63 using tcu::TestLog;
64 using std::vector;
65 using std::string;
66 using std::set;
67
68 // Helper functions.
69
70 void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
71 {
72         std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
73 }
74
75 bool 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
137 const 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
149 const 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
164 BufferCase::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
170 BufferCase::~BufferCase (void)
171 {
172         enableLogging(false);
173         BufferCase::deinit();
174 }
175
176 void BufferCase::init (void)
177 {
178         enableLogging(true);
179 }
180
181 void 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
187 deUint32 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
206 void BufferCase::deleteBuffer (deUint32 buffer)
207 {
208         glDeleteBuffers(1, &buffer);
209         m_allocatedBuffers.erase(buffer);
210 }
211
212 void 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
221 void ReferenceBuffer::setSize (int numBytes)
222 {
223         m_data.resize(numBytes);
224 }
225
226 void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
227 {
228         m_data.resize(numBytes);
229         std::copy(bytes, bytes+numBytes, m_data.begin());
230 }
231
232 void 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
240 BufferVerifierBase::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
249 BufferVerifier::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
261 BufferVerifier::~BufferVerifier (void)
262 {
263         delete m_verifier;
264 }
265
266 bool 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
276 VertexArrayVerifier::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
310 VertexArrayVerifier::~VertexArrayVerifier (void)
311 {
312         delete m_program;
313 }
314
315 static 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                     = (float)(x+0) / (float)gridSizeX;
323                 float   sy0                     = (float)(y+0) / (float)gridSizeY;
324                 float   sx1                     = (float)(x+1) / (float)gridSizeX;
325                 float   sy1                     = (float)(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
339 static 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
362 static 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
370 static 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
407 bool 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(4,4,4,4);
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
486 IndexArrayVerifier::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
520 IndexArrayVerifier::~IndexArrayVerifier (void)
521 {
522         delete m_program;
523 }
524
525 static 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
544 static 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
561 template<typename T>
562 static 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
568 bool 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