xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fBufferTestUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 std::set;
64 using std::string;
65 using std::vector;
66 using tcu::TestLog;
67 
68 // Helper functions.
69 
fillWithRandomBytes(uint8_t * ptr,int numBytes,uint32_t seed)70 void fillWithRandomBytes(uint8_t *ptr, int numBytes, uint32_t seed)
71 {
72     std::copy(tcu::RandomValueIterator<uint8_t>::begin(seed, numBytes), tcu::RandomValueIterator<uint8_t>::end(), ptr);
73 }
74 
compareByteArrays(tcu::TestLog & log,const uint8_t * resPtr,const uint8_t * refPtr,int numBytes)75 bool compareByteArrays(tcu::TestLog &log, const uint8_t *resPtr, const uint8_t *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 "
104                     << tcu::formatArray(tcu::Format::HexIterator<uint8_t>(refPtr + diffSpanStart),
105                                         tcu::Format::HexIterator<uint8_t>(refPtr + diffSpanStart + printLen))
106                     << "\n"
107                     << "  got "
108                     << tcu::formatArray(tcu::Format::HexIterator<uint8_t>(resPtr + diffSpanStart),
109                                         tcu::Format::HexIterator<uint8_t>(resPtr + diffSpanStart + printLen))
110                     << TestLog::EndMessage;
111             }
112             else
113                 log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
114 
115             numDiffSpans += 1;
116             diffSpanStart = -1;
117         }
118     }
119 
120     if (diffSpanStart >= 0)
121     {
122         if (numDiffSpans < maxDiffSpans)
123         {
124             int len      = ndx - diffSpanStart;
125             int printLen = de::min(len, maxSpanLen);
126 
127             log << TestLog::Message << len << " byte difference at offset " << diffSpanStart << "\n"
128                 << "  expected "
129                 << tcu::formatArray(tcu::Format::HexIterator<uint8_t>(refPtr + diffSpanStart),
130                                     tcu::Format::HexIterator<uint8_t>(refPtr + diffSpanStart + printLen))
131                 << "\n"
132                 << "  got "
133                 << tcu::formatArray(tcu::Format::HexIterator<uint8_t>(resPtr + diffSpanStart),
134                                     tcu::Format::HexIterator<uint8_t>(resPtr + diffSpanStart + printLen))
135                 << TestLog::EndMessage;
136         }
137         else
138             log << TestLog::Message << "(output too long, truncated)" << TestLog::EndMessage;
139     }
140 
141     log << TestLog::Message << (isOk ? "Verification passed." : "Verification FAILED!") << TestLog::EndMessage;
142     log << TestLog::EndSection;
143 
144     return isOk;
145 }
146 
getBufferTargetName(uint32_t target)147 const char *getBufferTargetName(uint32_t target)
148 {
149     switch (target)
150     {
151     case GL_ARRAY_BUFFER:
152         return "array";
153     case GL_ELEMENT_ARRAY_BUFFER:
154         return "element_array";
155     default:
156         DE_ASSERT(false);
157         return DE_NULL;
158     }
159 }
160 
getUsageHintName(uint32_t hint)161 const char *getUsageHintName(uint32_t hint)
162 {
163     switch (hint)
164     {
165     case GL_STREAM_DRAW:
166         return "stream_draw";
167     case GL_STATIC_DRAW:
168         return "static_draw";
169     case GL_DYNAMIC_DRAW:
170         return "dynamic_draw";
171     default:
172         DE_ASSERT(false);
173         return DE_NULL;
174     }
175 }
176 
177 // BufferCase
178 
BufferCase(Context & context,const char * name,const char * description)179 BufferCase::BufferCase(Context &context, const char *name, const char *description)
180     : TestCase(context, name, description)
181     , CallLogWrapper(context.getRenderContext().getFunctions(), m_context.getTestContext().getLog())
182 {
183 }
184 
~BufferCase(void)185 BufferCase::~BufferCase(void)
186 {
187     enableLogging(false);
188     BufferCase::deinit();
189 }
190 
init(void)191 void BufferCase::init(void)
192 {
193     enableLogging(true);
194 }
195 
deinit(void)196 void BufferCase::deinit(void)
197 {
198     for (set<uint32_t>::const_iterator bufIter = m_allocatedBuffers.begin(); bufIter != m_allocatedBuffers.end();
199          bufIter++)
200         glDeleteBuffers(1, &(*bufIter));
201 }
202 
genBuffer(void)203 uint32_t BufferCase::genBuffer(void)
204 {
205     uint32_t buf = 0;
206     glGenBuffers(1, &buf);
207     if (buf != 0)
208     {
209         try
210         {
211             m_allocatedBuffers.insert(buf);
212         }
213         catch (const std::exception &)
214         {
215             glDeleteBuffers(1, &buf);
216             throw;
217         }
218     }
219     return buf;
220 }
221 
deleteBuffer(uint32_t buffer)222 void BufferCase::deleteBuffer(uint32_t buffer)
223 {
224     glDeleteBuffers(1, &buffer);
225     m_allocatedBuffers.erase(buffer);
226 }
227 
checkError(void)228 void BufferCase::checkError(void)
229 {
230     glw::GLenum err = glGetError();
231     if (err != GL_NO_ERROR)
232         throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
233 }
234 
235 // ReferenceBuffer
236 
setSize(int numBytes)237 void ReferenceBuffer::setSize(int numBytes)
238 {
239     m_data.resize(numBytes);
240 }
241 
setData(int numBytes,const uint8_t * bytes)242 void ReferenceBuffer::setData(int numBytes, const uint8_t *bytes)
243 {
244     m_data.resize(numBytes);
245     std::copy(bytes, bytes + numBytes, m_data.begin());
246 }
247 
setSubData(int offset,int numBytes,const uint8_t * bytes)248 void ReferenceBuffer::setSubData(int offset, int numBytes, const uint8_t *bytes)
249 {
250     DE_ASSERT(de::inBounds(offset, 0, (int)m_data.size()) &&
251               de::inRange(offset + numBytes, offset, (int)m_data.size()));
252     std::copy(bytes, bytes + numBytes, m_data.begin() + offset);
253 }
254 
255 // BufferVerifierBase
256 
BufferVerifierBase(Context & context)257 BufferVerifierBase::BufferVerifierBase(Context &context)
258     : CallLogWrapper(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
259     , m_context(context)
260 {
261     enableLogging(LOG_VERIFIER_CALLS);
262 }
263 
264 // BufferVerifier
265 
BufferVerifier(Context & context,VerifyType verifyType)266 BufferVerifier::BufferVerifier(Context &context, VerifyType verifyType) : m_verifier(DE_NULL)
267 {
268     switch (verifyType)
269     {
270     case VERIFY_AS_VERTEX_ARRAY:
271         m_verifier = new VertexArrayVerifier(context);
272         break;
273     case VERIFY_AS_INDEX_ARRAY:
274         m_verifier = new IndexArrayVerifier(context);
275         break;
276     default:
277         TCU_FAIL("Unsupported verifier");
278     }
279 }
280 
~BufferVerifier(void)281 BufferVerifier::~BufferVerifier(void)
282 {
283     delete m_verifier;
284 }
285 
verify(uint32_t buffer,const uint8_t * reference,int offset,int numBytes)286 bool BufferVerifier::verify(uint32_t buffer, const uint8_t *reference, int offset, int numBytes)
287 {
288     DE_ASSERT(numBytes >= getMinSize());
289     DE_ASSERT(offset % getAlignment() == 0);
290     DE_ASSERT((offset + numBytes) % getAlignment() == 0);
291     return m_verifier->verify(buffer, reference, offset, numBytes);
292 }
293 
294 // VertexArrayVerifier
295 
VertexArrayVerifier(Context & context)296 VertexArrayVerifier::VertexArrayVerifier(Context &context)
297     : BufferVerifierBase(context)
298     , m_program(DE_NULL)
299     , m_posLoc(0)
300     , m_byteVecLoc(0)
301 {
302     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
303                                        glu::makeVtxFragSources("attribute highp vec2 a_position;\n"
304                                                                "attribute mediump vec3 a_byteVec;\n"
305                                                                "varying mediump vec3 v_byteVec;\n"
306                                                                "void main (void)\n"
307                                                                "{\n"
308                                                                "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
309                                                                "    v_byteVec = a_byteVec;\n"
310                                                                "}\n",
311 
312                                                                "varying mediump vec3 v_byteVec;\n"
313                                                                "void main (void)\n"
314                                                                "{\n"
315                                                                "    gl_FragColor = vec4(v_byteVec, 1.0);\n"
316                                                                "}\n"));
317 
318     if (!m_program->isOk())
319     {
320         m_context.getTestContext().getLog() << *m_program;
321         delete m_program;
322         TCU_FAIL("Compile failed");
323     }
324 
325     const glw::Functions &funcs = context.getRenderContext().getFunctions();
326     m_posLoc                    = funcs.getAttribLocation(m_program->getProgram(), "a_position");
327     m_byteVecLoc                = funcs.getAttribLocation(m_program->getProgram(), "a_byteVec");
328 }
329 
~VertexArrayVerifier(void)330 VertexArrayVerifier::~VertexArrayVerifier(void)
331 {
332     delete m_program;
333 }
334 
computePositions(vector<tcu::Vec2> & positions,int gridSizeX,int gridSizeY)335 static void computePositions(vector<tcu::Vec2> &positions, int gridSizeX, int gridSizeY)
336 {
337     positions.resize(gridSizeX * gridSizeY * 4);
338 
339     for (int y = 0; y < gridSizeY; y++)
340         for (int x = 0; x < gridSizeX; x++)
341         {
342             float sx0   = (float)(x + 0) / (float)gridSizeX;
343             float sy0   = (float)(y + 0) / (float)gridSizeY;
344             float sx1   = (float)(x + 1) / (float)gridSizeX;
345             float sy1   = (float)(y + 1) / (float)gridSizeY;
346             float fx0   = 2.0f * sx0 - 1.0f;
347             float fy0   = 2.0f * sy0 - 1.0f;
348             float fx1   = 2.0f * sx1 - 1.0f;
349             float fy1   = 2.0f * sy1 - 1.0f;
350             int baseNdx = (y * gridSizeX + x) * 4;
351 
352             positions[baseNdx + 0] = tcu::Vec2(fx0, fy0);
353             positions[baseNdx + 1] = tcu::Vec2(fx0, fy1);
354             positions[baseNdx + 2] = tcu::Vec2(fx1, fy0);
355             positions[baseNdx + 3] = tcu::Vec2(fx1, fy1);
356         }
357 }
358 
computeIndices(vector<uint16_t> & indices,int gridSizeX,int gridSizeY)359 static void computeIndices(vector<uint16_t> &indices, int gridSizeX, int gridSizeY)
360 {
361     indices.resize(3 * 2 * gridSizeX * gridSizeY);
362 
363     for (int quadNdx = 0; quadNdx < gridSizeX * gridSizeY; quadNdx++)
364     {
365         int v00 = quadNdx * 4 + 0;
366         int v01 = quadNdx * 4 + 1;
367         int v10 = quadNdx * 4 + 2;
368         int v11 = quadNdx * 4 + 3;
369 
370         DE_ASSERT(v11 < (1 << 16));
371 
372         indices[quadNdx * 6 + 0] = (uint16_t)v10;
373         indices[quadNdx * 6 + 1] = (uint16_t)v00;
374         indices[quadNdx * 6 + 2] = (uint16_t)v01;
375 
376         indices[quadNdx * 6 + 3] = (uint16_t)v10;
377         indices[quadNdx * 6 + 4] = (uint16_t)v01;
378         indices[quadNdx * 6 + 5] = (uint16_t)v11;
379     }
380 }
381 
fetchVtxColor(const uint8_t * ptr,int vtxNdx)382 static inline tcu::Vec4 fetchVtxColor(const uint8_t *ptr, int vtxNdx)
383 {
384     return tcu::RGBA(*(ptr + vtxNdx * 3 + 0), *(ptr + vtxNdx * 3 + 1), *(ptr + vtxNdx * 3 + 2), 255).toVec();
385 }
386 
renderQuadGridReference(tcu::Surface & dst,int numQuads,int rowLength,const uint8_t * inPtr)387 static void renderQuadGridReference(tcu::Surface &dst, int numQuads, int rowLength, const uint8_t *inPtr)
388 {
389     using tcu::Vec4;
390 
391     dst.setSize(rowLength * VERIFY_QUAD_SIZE,
392                 (numQuads / rowLength + (numQuads % rowLength != 0 ? 1 : 0)) * VERIFY_QUAD_SIZE);
393 
394     tcu::PixelBufferAccess dstAccess = dst.getAccess();
395     tcu::clear(dstAccess, tcu::IVec4(0, 0, 0, 0xff));
396 
397     for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
398     {
399         int x0   = (quadNdx % rowLength) * VERIFY_QUAD_SIZE;
400         int y0   = (quadNdx / rowLength) * VERIFY_QUAD_SIZE;
401         Vec4 v00 = fetchVtxColor(inPtr, quadNdx * 4 + 0);
402         Vec4 v10 = fetchVtxColor(inPtr, quadNdx * 4 + 1);
403         Vec4 v01 = fetchVtxColor(inPtr, quadNdx * 4 + 2);
404         Vec4 v11 = fetchVtxColor(inPtr, quadNdx * 4 + 3);
405 
406         for (int y = 0; y < VERIFY_QUAD_SIZE; y++)
407             for (int x = 0; x < VERIFY_QUAD_SIZE; x++)
408             {
409                 float fx = ((float)x + 0.5f) / (float)VERIFY_QUAD_SIZE;
410                 float fy = ((float)y + 0.5f) / (float)VERIFY_QUAD_SIZE;
411 
412                 bool tri       = fx + fy <= 1.0f;
413                 float tx       = tri ? fx : (1.0f - fx);
414                 float ty       = tri ? fy : (1.0f - fy);
415                 const Vec4 &t0 = tri ? v00 : v11;
416                 const Vec4 &t1 = tri ? v01 : v10;
417                 const Vec4 &t2 = tri ? v10 : v01;
418                 Vec4 color     = t0 + (t1 - t0) * tx + (t2 - t0) * ty;
419 
420                 dstAccess.setPixel(color, x0 + x, y0 + y);
421             }
422     }
423 }
424 
verify(uint32_t buffer,const uint8_t * refPtr,int offset,int numBytes)425 bool VertexArrayVerifier::verify(uint32_t buffer, const uint8_t *refPtr, int offset, int numBytes)
426 {
427     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
428     const int numBytesInVtx               = 3;
429     const int numBytesInQuad              = numBytesInVtx * 4;
430     int maxQuadsX                         = de::min(128, renderTarget.getWidth() / VERIFY_QUAD_SIZE);
431     int maxQuadsY                         = de::min(128, renderTarget.getHeight() / VERIFY_QUAD_SIZE);
432     int maxQuadsPerBatch                  = maxQuadsX * maxQuadsY;
433     int numVerified                       = 0;
434     uint32_t program                      = m_program->getProgram();
435     tcu::RGBA threshold                   = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(4, 4, 4, 4);
436     bool isOk                             = true;
437 
438     vector<tcu::Vec2> positions;
439     vector<uint16_t> indices;
440 
441     tcu::Surface rendered;
442     tcu::Surface reference;
443 
444     DE_ASSERT(numBytes >= numBytesInQuad); // Can't render full quad with smaller buffers.
445 
446     computePositions(positions, maxQuadsX, maxQuadsY);
447     computeIndices(indices, maxQuadsX, maxQuadsY);
448 
449     // Reset buffer bindings.
450     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
451     glBindBuffer(GL_ARRAY_BUFFER, 0);
452 
453     // Setup rendering state.
454     glViewport(0, 0, maxQuadsX * VERIFY_QUAD_SIZE, maxQuadsY * VERIFY_QUAD_SIZE);
455     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
456     glUseProgram(program);
457     glEnableVertexAttribArray(m_posLoc);
458     glVertexAttribPointer(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]);
459     glEnableVertexAttribArray(m_byteVecLoc);
460     glBindBuffer(GL_ARRAY_BUFFER, buffer);
461 
462     while (numVerified < numBytes)
463     {
464         int numRemaining     = numBytes - numVerified;
465         bool isLeftoverBatch = numRemaining < numBytesInQuad;
466         int numBytesToVerify =
467             isLeftoverBatch ? numBytesInQuad :
468                               de::min(maxQuadsPerBatch * numBytesInQuad, numRemaining - numRemaining % numBytesInQuad);
469         int curOffset       = isLeftoverBatch ? (numBytes - numBytesInQuad) : numVerified;
470         int numQuads        = numBytesToVerify / numBytesInQuad;
471         int numCols         = de::min(maxQuadsX, numQuads);
472         int numRows         = numQuads / maxQuadsX + (numQuads % maxQuadsX != 0 ? 1 : 0);
473         string imageSetDesc = string("Bytes ") + de::toString(offset + curOffset) + " to " +
474                               de::toString(offset + curOffset + numBytesToVerify - 1);
475 
476         DE_ASSERT(numBytesToVerify > 0 && numBytesToVerify % numBytesInQuad == 0);
477         DE_ASSERT(de::inBounds(curOffset, 0, numBytes));
478         DE_ASSERT(de::inRange(curOffset + numBytesToVerify, curOffset, numBytes));
479 
480         // Render batch.
481         glClear(GL_COLOR_BUFFER_BIT);
482         glVertexAttribPointer(m_byteVecLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0,
483                               (const glw::GLvoid *)(uintptr_t)(offset + curOffset));
484         glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, &indices[0]);
485 
486         renderQuadGridReference(reference, numQuads, numCols, refPtr + offset + curOffset);
487 
488         rendered.setSize(numCols * VERIFY_QUAD_SIZE, numRows * VERIFY_QUAD_SIZE);
489         glu::readPixels(m_context.getRenderContext(), 0, 0, rendered.getAccess());
490 
491         if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(),
492                                         reference, rendered, threshold, tcu::COMPARE_LOG_RESULT))
493         {
494             isOk = false;
495             break;
496         }
497 
498         numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
499     }
500 
501     glDisableVertexAttribArray(m_posLoc);
502     glDisableVertexAttribArray(m_byteVecLoc);
503 
504     return isOk;
505 }
506 
507 // IndexArrayVerifier
508 
IndexArrayVerifier(Context & context)509 IndexArrayVerifier::IndexArrayVerifier(Context &context)
510     : BufferVerifierBase(context)
511     , m_program(DE_NULL)
512     , m_posLoc(0)
513     , m_colorLoc(0)
514 {
515     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
516                                        glu::makeVtxFragSources("attribute highp vec2 a_position;\n"
517                                                                "attribute mediump vec3 a_color;\n"
518                                                                "varying mediump vec3 v_color;\n"
519                                                                "void main (void)\n"
520                                                                "{\n"
521                                                                "    gl_Position = vec4(a_position, 0.0, 1.0);\n"
522                                                                "    v_color = a_color;\n"
523                                                                "}\n",
524 
525                                                                "varying mediump vec3 v_color;\n"
526                                                                "void main (void)\n"
527                                                                "{\n"
528                                                                "    gl_FragColor = vec4(v_color, 1.0);\n"
529                                                                "}\n"));
530 
531     if (!m_program->isOk())
532     {
533         m_context.getTestContext().getLog() << *m_program;
534         delete m_program;
535         TCU_FAIL("Compile failed");
536     }
537 
538     const glw::Functions &funcs = context.getRenderContext().getFunctions();
539     m_posLoc                    = funcs.getAttribLocation(m_program->getProgram(), "a_position");
540     m_colorLoc                  = funcs.getAttribLocation(m_program->getProgram(), "a_color");
541 }
542 
~IndexArrayVerifier(void)543 IndexArrayVerifier::~IndexArrayVerifier(void)
544 {
545     delete m_program;
546 }
547 
computeIndexVerifierPositions(std::vector<tcu::Vec2> & dst)548 static void computeIndexVerifierPositions(std::vector<tcu::Vec2> &dst)
549 {
550     const int numPosX = 16;
551     const int numPosY = 16;
552 
553     dst.resize(numPosX * numPosY);
554 
555     for (int y = 0; y < numPosY; y++)
556     {
557         for (int x = 0; x < numPosX; x++)
558         {
559             float xf = float(x) / float(numPosX - 1);
560             float yf = float(y) / float(numPosY - 1);
561 
562             dst[y * numPosX + x] = tcu::Vec2(2.0f * xf - 1.0f, 2.0f * yf - 1.0f);
563         }
564     }
565 }
566 
computeIndexVerifierColors(std::vector<tcu::Vec3> & dst)567 static void computeIndexVerifierColors(std::vector<tcu::Vec3> &dst)
568 {
569     const int numColors = 256;
570     const float minVal  = 0.1f;
571     const float maxVal  = 0.5f;
572     de::Random rnd(0xabc231);
573 
574     dst.resize(numColors);
575 
576     for (std::vector<tcu::Vec3>::iterator i = dst.begin(); i != dst.end(); ++i)
577     {
578         i->x() = rnd.getFloat(minVal, maxVal);
579         i->y() = rnd.getFloat(minVal, maxVal);
580         i->z() = rnd.getFloat(minVal, maxVal);
581     }
582 }
583 
584 template <typename T>
execVertexFetch(T * dst,const T * src,const uint8_t * indices,int numIndices)585 static void execVertexFetch(T *dst, const T *src, const uint8_t *indices, int numIndices)
586 {
587     for (int i = 0; i < numIndices; ++i)
588         dst[i] = src[indices[i]];
589 }
590 
verify(uint32_t buffer,const uint8_t * refPtr,int offset,int numBytes)591 bool IndexArrayVerifier::verify(uint32_t buffer, const uint8_t *refPtr, int offset, int numBytes)
592 {
593     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
594     const int viewportW                   = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, renderTarget.getWidth());
595     const int viewportH                   = de::min<int>(INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, renderTarget.getHeight());
596     const int minBytesPerBatch            = 2;
597     const tcu::RGBA threshold(0, 0, 0, 0);
598 
599     std::vector<tcu::Vec2> positions;
600     std::vector<tcu::Vec3> colors;
601 
602     std::vector<tcu::Vec2> fetchedPos(MAX_LINES_PER_INDEX_ARRAY_DRAW + 1);
603     std::vector<tcu::Vec3> fetchedColor(MAX_LINES_PER_INDEX_ARRAY_DRAW + 1);
604 
605     tcu::Surface indexBufferImg(viewportW, viewportH);
606     tcu::Surface referenceImg(viewportW, viewportH);
607 
608     int numVerified = 0;
609     bool isOk       = true;
610 
611     DE_STATIC_ASSERT(sizeof(tcu::Vec2) == sizeof(float) * 2);
612     DE_STATIC_ASSERT(sizeof(tcu::Vec3) == sizeof(float) * 3);
613 
614     computeIndexVerifierPositions(positions);
615     computeIndexVerifierColors(colors);
616 
617     // Reset buffer bindings.
618     glBindBuffer(GL_ARRAY_BUFFER, 0);
619     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
620 
621     // Setup rendering state.
622     glViewport(0, 0, viewportW, viewportH);
623     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
624     glUseProgram(m_program->getProgram());
625     glEnableVertexAttribArray(m_posLoc);
626     glEnableVertexAttribArray(m_colorLoc);
627     glEnable(GL_BLEND);
628     glBlendFunc(GL_ONE, GL_ONE);
629     glBlendEquation(GL_FUNC_ADD);
630 
631     while (numVerified < numBytes)
632     {
633         int numRemaining     = numBytes - numVerified;
634         bool isLeftoverBatch = numRemaining < minBytesPerBatch;
635         int numBytesToVerify =
636             isLeftoverBatch ? minBytesPerBatch : de::min(MAX_LINES_PER_INDEX_ARRAY_DRAW + 1, numRemaining);
637         int curOffset       = isLeftoverBatch ? (numBytes - minBytesPerBatch) : numVerified;
638         string imageSetDesc = string("Bytes ") + de::toString(offset + curOffset) + " to " +
639                               de::toString(offset + curOffset + numBytesToVerify - 1);
640 
641         // Step 1: Render using index buffer.
642         glClear(GL_COLOR_BUFFER_BIT);
643         glVertexAttribPointer(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &positions[0]);
644         glVertexAttribPointer(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &colors[0]);
645         glDrawElements(GL_LINE_STRIP, numBytesToVerify, GL_UNSIGNED_BYTE, (void *)(uintptr_t)(offset + curOffset));
646         glu::readPixels(m_context.getRenderContext(), 0, 0, indexBufferImg.getAccess());
647 
648         // Step 2: Do manual fetch and render without index buffer.
649         execVertexFetch(&fetchedPos[0], &positions[0], refPtr + offset + curOffset, numBytesToVerify);
650         execVertexFetch(&fetchedColor[0], &colors[0], refPtr + offset + curOffset, numBytesToVerify);
651 
652         glClear(GL_COLOR_BUFFER_BIT);
653         glVertexAttribPointer(m_posLoc, 2, GL_FLOAT, GL_FALSE, 0, &fetchedPos[0]);
654         glVertexAttribPointer(m_colorLoc, 3, GL_FLOAT, GL_FALSE, 0, &fetchedColor[0]);
655         glDrawArrays(GL_LINE_STRIP, 0, numBytesToVerify);
656         glu::readPixels(m_context.getRenderContext(), 0, 0, referenceImg.getAccess());
657 
658         if (!tcu::pixelThresholdCompare(m_context.getTestContext().getLog(), "RenderResult", imageSetDesc.c_str(),
659                                         referenceImg, indexBufferImg, threshold, tcu::COMPARE_LOG_RESULT))
660         {
661             isOk = false;
662             break;
663         }
664 
665         numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
666     }
667 
668     return isOk;
669 }
670 
671 } // namespace BufferTestUtil
672 } // namespace Functional
673 } // namespace gles2
674 } // namespace deqp
675