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