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