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