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