Merge "Allow alternative form for refract()." into nyc-dev am: f492a25
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsBufferTestUtil.cpp
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
46 namespace deqp
47 {
48 namespace gls
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 using tcu::TestLog;
62 using std::vector;
63 using std::string;
64 using std::set;
65
66 // Helper functions.
67
68 void fillWithRandomBytes (deUint8* ptr, int numBytes, deUint32 seed)
69 {
70         std::copy(tcu::RandomValueIterator<deUint8>::begin(seed, numBytes), tcu::RandomValueIterator<deUint8>::end(), ptr);
71 }
72
73 bool 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
135 const 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
154 const 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
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)
179 {
180 }
181
182 BufferCase::~BufferCase (void)
183 {
184         enableLogging(false);
185         BufferCase::deinit();
186 }
187
188 void BufferCase::init (void)
189 {
190         enableLogging(true);
191 }
192
193 void 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
199 deUint32 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
218 void BufferCase::deleteBuffer (deUint32 buffer)
219 {
220         glDeleteBuffers(1, &buffer);
221         m_allocatedBuffers.erase(buffer);
222 }
223
224 void 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
233 void ReferenceBuffer::setSize (int numBytes)
234 {
235         m_data.resize(numBytes);
236 }
237
238 void ReferenceBuffer::setData (int numBytes, const deUint8* bytes)
239 {
240         m_data.resize(numBytes);
241         std::copy(bytes, bytes+numBytes, m_data.begin());
242 }
243
244 void 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
252 BufferWriterBase::BufferWriterBase (glu::RenderContext& renderCtx, tcu::TestLog& log)
253         : CallLogWrapper        (renderCtx.getFunctions(), log)
254         , m_renderCtx           (renderCtx)
255 {
256         enableLogging(true);
257 }
258
259 void 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
267 BufferWriter::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
279 BufferWriter::~BufferWriter (void)
280 {
281         delete m_writer;
282 }
283
284 void 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
292 void 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
302 void BufferSubDataWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
303 {
304         write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
305 }
306
307 void 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
317 void BufferWriteMapWriter::write (deUint32 buffer, int offset, int numBytes, const deUint8* bytes)
318 {
319         write(buffer, offset, numBytes, bytes, GL_ARRAY_BUFFER);
320 }
321
322 void 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
338 BufferVerifierBase::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
346 bool 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
354 BufferVerifier::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
367 BufferVerifier::~BufferVerifier (void)
368 {
369         delete m_verifier;
370 }
371
372 bool 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
380 bool 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
390 bool BufferMapVerifier::verify (deUint32 buffer, const deUint8* reference, int offset, int numBytes)
391 {
392         return verify(buffer, reference, offset, numBytes, GL_ARRAY_BUFFER);
393 }
394
395 bool 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
417 VertexArrayVerifier::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
465 VertexArrayVerifier::~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
476 static 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                     = (float)(x+0) / (float)gridSizeX;
484                 float   sy0                     = (float)(y+0) / (float)gridSizeY;
485                 float   sx1                     = (float)(x+1) / (float)gridSizeX;
486                 float   sy1                     = (float)(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
500 static 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
523 static 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
531 static 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
568 bool 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
655 IndexArrayVerifier::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
703 IndexArrayVerifier::~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
714 static 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
733 static 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
750 template<typename T>
751 static 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
757 bool 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
851 const 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
863 const 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