xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fVertexArrayObjectTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 Vertex array object tests
22  *//*--------------------------------------------------------------------*/
23 #include "es3fVertexArrayObjectTests.hpp"
24 
25 #include "gluShaderProgram.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluRenderContext.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuRenderTarget.hpp"
33 
34 #include "deRandom.hpp"
35 #include "deString.h"
36 #include "deMemory.h"
37 
38 #include <vector>
39 #include <string>
40 #include <memory>
41 
42 #include "glw.h"
43 
44 using std::string;
45 using std::vector;
46 
47 namespace deqp
48 {
49 namespace gles3
50 {
51 namespace Functional
52 {
53 
54 namespace
55 {
56 struct Attribute
57 {
58     Attribute(void);
59     GLboolean enabled;
60     GLint size;
61     GLint stride;
62     GLenum type;
63     GLboolean integer;
64     GLint divisor;
65     GLint offset;
66     GLboolean normalized;
67 
68     int bufferNdx;
69 };
70 
71 struct VertexArrayState
72 {
73     VertexArrayState(void);
74 
75     vector<Attribute> attributes;
76     int elementArrayBuffer;
77 };
78 
VertexArrayState(void)79 VertexArrayState::VertexArrayState(void) : elementArrayBuffer(-1)
80 {
81 }
82 
Attribute(void)83 Attribute::Attribute(void)
84     : enabled(GL_FALSE)
85     , size(1)
86     , stride(0)
87     , type(GL_FLOAT)
88     , integer(GL_FALSE)
89     , divisor(0)
90     , offset(0)
91     , normalized(GL_FALSE)
92     , bufferNdx(0)
93 {
94 }
95 
96 struct BufferSpec
97 {
98     int count;
99     int size;
100     int componentCount;
101     int stride;
102     int offset;
103 
104     GLenum type;
105 
106     int intRangeMin;
107     int intRangeMax;
108 
109     float floatRangeMin;
110     float floatRangeMax;
111 };
112 
113 struct Spec
114 {
115     Spec(void);
116 
117     int count;
118     int instances;
119     bool useDrawElements;
120     GLenum indexType;
121     int indexOffset;
122     int indexRangeMin;
123     int indexRangeMax;
124     int indexCount;
125     VertexArrayState state;
126     VertexArrayState vao;
127     vector<BufferSpec> buffers;
128 };
129 
Spec(void)130 Spec::Spec(void)
131     : count(-1)
132     , instances(-1)
133     , useDrawElements(false)
134     , indexType(GL_NONE)
135     , indexOffset(-1)
136     , indexRangeMin(-1)
137     , indexRangeMax(-1)
138     , indexCount(-1)
139 {
140 }
141 
142 } // namespace
143 
144 class VertexArrayObjectTest : public TestCase
145 {
146 public:
147     VertexArrayObjectTest(Context &context, const Spec &spec, const char *name, const char *description);
148     ~VertexArrayObjectTest(void);
149     virtual void init(void);
150     virtual void deinit(void);
151     virtual IterateResult iterate(void);
152 
153 private:
154     Spec m_spec;
155     tcu::TestLog &m_log;
156     vector<GLuint> m_buffers;
157     glu::ShaderProgram *m_vaoProgram;
158     glu::ShaderProgram *m_stateProgram;
159     de::Random m_random;
160     uint8_t *m_indices;
161 
162     void logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state, const std::string &msg);
163     uint8_t *createRandomBufferData(const BufferSpec &buffer);
164     uint8_t *generateIndices(void);
165     glu::ShaderProgram *createProgram(const VertexArrayState &state);
166     void setState(const VertexArrayState &state);
167     void render(tcu::Surface &vaoResult, tcu::Surface &defaultResult);
168     void makeDrawCall(const VertexArrayState &state);
169     void genReferences(tcu::Surface &vaoRef, tcu::Surface &defaultRef);
170 
171     VertexArrayObjectTest(const VertexArrayObjectTest &);
172     VertexArrayObjectTest &operator=(const VertexArrayObjectTest &);
173 };
174 
VertexArrayObjectTest(Context & context,const Spec & spec,const char * name,const char * description)175 VertexArrayObjectTest::VertexArrayObjectTest(Context &context, const Spec &spec, const char *name,
176                                              const char *description)
177     : TestCase(context, name, description)
178     , m_spec(spec)
179     , m_log(context.getTestContext().getLog())
180     , m_vaoProgram(NULL)
181     , m_stateProgram(NULL)
182     , m_random(deStringHash(name))
183     , m_indices(NULL)
184 {
185     // Makes zero to zero mapping for buffers
186     m_buffers.push_back(0);
187 }
188 
~VertexArrayObjectTest(void)189 VertexArrayObjectTest::~VertexArrayObjectTest(void)
190 {
191 }
192 
logVertexArrayState(tcu::TestLog & log,const VertexArrayState & state,const std::string & msg)193 void VertexArrayObjectTest::logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state,
194                                                 const std::string &msg)
195 {
196     std::stringstream message;
197 
198     message << msg << "\n";
199     message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
200 
201     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
202     {
203         message << "attribute : " << attribNdx << "\n"
204                 << "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : "
205                 << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") << "\n"
206                 << "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size << "\n"
207                 << "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride << "\n"
208                 << "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type << "\n"
209                 << "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : "
210                 << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") << "\n"
211                 << "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : "
212                 << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") << "\n"
213                 << "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor << "\n"
214                 << "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset << "\n"
215                 << "\tGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx]
216                 << "\n";
217     }
218     log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
219 }
220 
init(void)221 void VertexArrayObjectTest::init(void)
222 {
223     // \note [mika] Index 0 is reserved for 0 buffer
224     for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
225     {
226         uint8_t *data = createRandomBufferData(m_spec.buffers[bufferNdx]);
227 
228         try
229         {
230             GLuint buffer;
231             GLU_CHECK_CALL(glGenBuffers(1, &buffer));
232             m_buffers.push_back(buffer);
233 
234             GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
235             GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
236             GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
237         }
238         catch (...)
239         {
240             delete[] data;
241             throw;
242         }
243 
244         delete[] data;
245     }
246 
247     m_vaoProgram = createProgram(m_spec.vao);
248     m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
249     m_log << *m_vaoProgram;
250     m_stateProgram = createProgram(m_spec.state);
251     m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
252     m_log << *m_stateProgram;
253 
254     if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
255         TCU_FAIL("Failed to compile shaders");
256 
257     if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
258         m_indices = generateIndices();
259 }
260 
deinit(void)261 void VertexArrayObjectTest::deinit(void)
262 {
263     GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
264     m_buffers.clear();
265     delete m_vaoProgram;
266     delete m_stateProgram;
267     delete[] m_indices;
268 }
269 
generateIndices(void)270 uint8_t *VertexArrayObjectTest::generateIndices(void)
271 {
272     int typeSize = 0;
273     switch (m_spec.indexType)
274     {
275     case GL_UNSIGNED_INT:
276         typeSize = sizeof(GLuint);
277         break;
278     case GL_UNSIGNED_SHORT:
279         typeSize = sizeof(GLushort);
280         break;
281     case GL_UNSIGNED_BYTE:
282         typeSize = sizeof(GLubyte);
283         break;
284     default:
285         DE_ASSERT(false);
286     }
287 
288     uint8_t *indices = new uint8_t[m_spec.indexCount * typeSize];
289 
290     for (int i = 0; i < m_spec.indexCount; i++)
291     {
292         uint8_t *pos = indices + typeSize * i;
293 
294         switch (m_spec.indexType)
295         {
296         case GL_UNSIGNED_INT:
297         {
298             GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
299             deMemcpy(pos, &v, sizeof(v));
300             break;
301         }
302 
303         case GL_UNSIGNED_SHORT:
304         {
305             GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
306             deMemcpy(pos, &v, sizeof(v));
307             break;
308         }
309 
310         case GL_UNSIGNED_BYTE:
311         {
312             GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
313             deMemcpy(pos, &v, sizeof(v));
314             break;
315         }
316 
317         default:
318             DE_ASSERT(false);
319         }
320     }
321 
322     return indices;
323 }
324 
createRandomBufferData(const BufferSpec & buffer)325 uint8_t *VertexArrayObjectTest::createRandomBufferData(const BufferSpec &buffer)
326 {
327     uint8_t *data = new uint8_t[buffer.size];
328 
329     int stride;
330 
331     if (buffer.stride != 0)
332     {
333         stride = buffer.stride;
334     }
335     else
336     {
337         switch (buffer.type)
338         {
339         case GL_FLOAT:
340             stride = buffer.componentCount * (int)sizeof(GLfloat);
341             break;
342         case GL_INT:
343             stride = buffer.componentCount * (int)sizeof(GLint);
344             break;
345         case GL_UNSIGNED_INT:
346             stride = buffer.componentCount * (int)sizeof(GLuint);
347             break;
348         case GL_SHORT:
349             stride = buffer.componentCount * (int)sizeof(GLshort);
350             break;
351         case GL_UNSIGNED_SHORT:
352             stride = buffer.componentCount * (int)sizeof(GLushort);
353             break;
354         case GL_BYTE:
355             stride = buffer.componentCount * (int)sizeof(GLbyte);
356             break;
357         case GL_UNSIGNED_BYTE:
358             stride = buffer.componentCount * (int)sizeof(GLubyte);
359             break;
360 
361         default:
362             stride = 0;
363             DE_ASSERT(false);
364         }
365     }
366 
367     uint8_t *itr = data;
368 
369     for (int pos = 0; pos < buffer.count; pos++)
370     {
371         uint8_t *componentItr = itr;
372         for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
373         {
374             switch (buffer.type)
375             {
376             case GL_FLOAT:
377             {
378                 float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
379                 deMemcpy(componentItr, &v, sizeof(v));
380                 componentItr += sizeof(v);
381                 break;
382             }
383 
384             case GL_INT:
385             {
386                 GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
387                 deMemcpy(componentItr, &v, sizeof(v));
388                 componentItr += sizeof(v);
389                 break;
390             }
391 
392             case GL_UNSIGNED_INT:
393             {
394                 GLuint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
395                 deMemcpy(componentItr, &v, sizeof(v));
396                 componentItr += sizeof(v);
397                 break;
398             }
399 
400             case GL_SHORT:
401             {
402                 GLshort v = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
403                 deMemcpy(componentItr, &v, sizeof(v));
404                 componentItr += sizeof(v);
405                 break;
406             }
407 
408             case GL_UNSIGNED_SHORT:
409             {
410                 GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
411                 deMemcpy(componentItr, &v, sizeof(v));
412                 componentItr += sizeof(v);
413                 break;
414             }
415 
416             case GL_BYTE:
417             {
418                 GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
419                 deMemcpy(componentItr, &v, sizeof(v));
420                 componentItr += sizeof(v);
421                 break;
422             }
423 
424             case GL_UNSIGNED_BYTE:
425             {
426                 GLubyte v = (GLubyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
427                 deMemcpy(componentItr, &v, sizeof(v));
428                 componentItr += sizeof(v);
429                 break;
430             }
431 
432             default:
433                 DE_ASSERT(false);
434             }
435         }
436 
437         itr += stride;
438     }
439 
440     return data;
441 }
442 
createProgram(const VertexArrayState & state)443 glu::ShaderProgram *VertexArrayObjectTest::createProgram(const VertexArrayState &state)
444 {
445     std::stringstream vertexShaderStream;
446     std::stringstream value;
447 
448     vertexShaderStream << "#version 300 es\n";
449 
450     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
451     {
452         if (state.attributes[attribNdx].integer)
453             vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx
454                                << ";\n";
455         else
456             vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx
457                                << ";\n";
458 
459         if (state.attributes[attribNdx].integer)
460         {
461             float scale = 0.0f;
462 
463             switch (state.attributes[0].type)
464             {
465             case GL_SHORT:
466                 scale = (1.0f / float((1u << 14) - 1u));
467                 break;
468             case GL_UNSIGNED_SHORT:
469                 scale = (1.0f / float((1u << 15) - 1u));
470                 break;
471             case GL_INT:
472                 scale = (1.0f / float((1u << 30) - 1u));
473                 break;
474             case GL_UNSIGNED_INT:
475                 scale = (1.0f / float((1u << 31) - 1u));
476                 break;
477             case GL_BYTE:
478                 scale = (1.0f / float((1u << 6) - 1u));
479                 break;
480             case GL_UNSIGNED_BYTE:
481                 scale = (1.0f / float((1u << 7) - 1u));
482                 break;
483 
484             default:
485                 DE_ASSERT(false);
486             }
487             value << (attribNdx != 0 ? " + " : "") << scale << " * vec4(a_attrib" << attribNdx << ")";
488         }
489         else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
490         {
491             float scale = 0.0f;
492 
493             switch (state.attributes[0].type)
494             {
495             case GL_SHORT:
496                 scale = (0.5f / float((1u << 14) - 1u));
497                 break;
498             case GL_UNSIGNED_SHORT:
499                 scale = (0.5f / float((1u << 15) - 1u));
500                 break;
501             case GL_INT:
502                 scale = (0.5f / float((1u << 30) - 1u));
503                 break;
504             case GL_UNSIGNED_INT:
505                 scale = (0.5f / float((1u << 31) - 1u));
506                 break;
507             case GL_BYTE:
508                 scale = (0.5f / float((1u << 6) - 1u));
509                 break;
510             case GL_UNSIGNED_BYTE:
511                 scale = (0.5f / float((1u << 7) - 1u));
512                 break;
513 
514             default:
515                 DE_ASSERT(false);
516             }
517             value << (attribNdx != 0 ? " + " : "") << scale << " * a_attrib" << attribNdx;
518         }
519         else
520             value << (attribNdx != 0 ? " + " : "") << "a_attrib" << attribNdx;
521     }
522 
523     vertexShaderStream << "out mediump vec4 v_value;\n"
524                        << "void main (void)\n"
525                        << "{\n"
526                        << "\tv_value = " << value.str() << ";\n";
527 
528     if (state.attributes[0].integer)
529     {
530         float scale = 0.0f;
531 
532         switch (state.attributes[0].type)
533         {
534         case GL_SHORT:
535             scale = (1.0f / float((1u << 14) - 1u));
536             break;
537         case GL_UNSIGNED_SHORT:
538             scale = (1.0f / float((1u << 15) - 1u));
539             break;
540         case GL_INT:
541             scale = (1.0f / float((1u << 30) - 1u));
542             break;
543         case GL_UNSIGNED_INT:
544             scale = (1.0f / float((1u << 31) - 1u));
545             break;
546         case GL_BYTE:
547             scale = (1.0f / float((1u << 6) - 1u));
548             break;
549         case GL_UNSIGNED_BYTE:
550             scale = (1.0f / float((1u << 7) - 1u));
551             break;
552 
553         default:
554             DE_ASSERT(false);
555         }
556 
557         vertexShaderStream << "\tgl_Position = vec4(" << scale << " * "
558                            << "vec3(a_attrib0.xyz), 1.0);\n"
559                            << "}";
560     }
561     else
562     {
563         if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
564         {
565             vertexShaderStream << "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
566                                << "}";
567         }
568         else
569         {
570             float scale = 0.0f;
571 
572             switch (state.attributes[0].type)
573             {
574             case GL_SHORT:
575                 scale = (1.0f / float((1u << 14) - 1u));
576                 break;
577             case GL_UNSIGNED_SHORT:
578                 scale = (1.0f / float((1u << 15) - 1u));
579                 break;
580             case GL_INT:
581                 scale = (1.0f / float((1u << 30) - 1u));
582                 break;
583             case GL_UNSIGNED_INT:
584                 scale = (1.0f / float((1u << 31) - 1u));
585                 break;
586             case GL_BYTE:
587                 scale = (1.0f / float((1u << 6) - 1u));
588                 break;
589             case GL_UNSIGNED_BYTE:
590                 scale = (1.0f / float((1u << 7) - 1u));
591                 break;
592 
593             default:
594                 DE_ASSERT(false);
595             }
596 
597             scale *= 0.5f;
598 
599             vertexShaderStream << "\tgl_Position = vec4(" << scale << " * "
600                                << "a_attrib0.xyz, 1.0);\n"
601                                << "}";
602         }
603     }
604 
605     const char *fragmentShader = "#version 300 es\n"
606                                  "in mediump vec4 v_value;\n"
607                                  "layout(location = 0) out mediump vec4 fragColor;\n"
608                                  "void main (void)\n"
609                                  "{\n"
610                                  "\tfragColor = vec4(v_value.xyz, 1.0);\n"
611                                  "}";
612 
613     return new glu::ShaderProgram(m_context.getRenderContext(),
614                                   glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
615 }
616 
setState(const VertexArrayState & state)617 void VertexArrayObjectTest::setState(const VertexArrayState &state)
618 {
619     GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
620 
621     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
622     {
623         GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
624         if (state.attributes[attribNdx].enabled)
625             GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
626         else
627             GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
628 
629         if (state.attributes[attribNdx].integer)
630             GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size,
631                                                   state.attributes[attribNdx].type, state.attributes[attribNdx].stride,
632                                                   (const GLvoid *)((GLintptr)state.attributes[attribNdx].offset)));
633         else
634             GLU_CHECK_CALL(
635                 glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type,
636                                       state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride,
637                                       (const GLvoid *)((GLintptr)state.attributes[attribNdx].offset)));
638 
639         GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
640     }
641 }
642 
makeDrawCall(const VertexArrayState & state)643 void VertexArrayObjectTest::makeDrawCall(const VertexArrayState &state)
644 {
645     GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
646     GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
647 
648     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
649     {
650         if (state.attributes[attribNdx].integer)
651             glVertexAttribI4i(attribNdx, 0, 0, 0, 1);
652         else
653             glVertexAttrib4f(attribNdx, 0.0f, 0.0f, 0.0f, 1.0f);
654     }
655 
656     if (m_spec.useDrawElements)
657     {
658         if (state.elementArrayBuffer == 0)
659         {
660             if (m_spec.instances == 0)
661                 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
662             else
663                 GLU_CHECK_CALL(
664                     glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
665         }
666         else
667         {
668             if (m_spec.instances == 0)
669                 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType,
670                                               (GLvoid *)((GLintptr)m_spec.indexOffset)));
671             else
672                 GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType,
673                                                        (GLvoid *)((GLintptr)m_spec.indexOffset), m_spec.instances));
674         }
675     }
676     else
677     {
678         if (m_spec.instances == 0)
679             GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
680         else
681             GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
682     }
683 }
684 
render(tcu::Surface & vaoResult,tcu::Surface & defaultResult)685 void VertexArrayObjectTest::render(tcu::Surface &vaoResult, tcu::Surface &defaultResult)
686 {
687     GLuint vao = 0;
688 
689     GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
690     GLU_CHECK_CALL(glBindVertexArray(vao));
691     setState(m_spec.vao);
692     GLU_CHECK_CALL(glBindVertexArray(0));
693 
694     setState(m_spec.state);
695 
696     GLU_CHECK_CALL(glBindVertexArray(vao));
697     GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
698     makeDrawCall(m_spec.vao);
699     glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
700     setState(m_spec.vao);
701     GLU_CHECK_CALL(glBindVertexArray(0));
702 
703     GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
704     makeDrawCall(m_spec.state);
705     glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
706 }
707 
genReferences(tcu::Surface & vaoRef,tcu::Surface & defaultRef)708 void VertexArrayObjectTest::genReferences(tcu::Surface &vaoRef, tcu::Surface &defaultRef)
709 {
710     setState(m_spec.vao);
711     GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
712     makeDrawCall(m_spec.vao);
713     glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
714 
715     setState(m_spec.state);
716     GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
717     makeDrawCall(m_spec.state);
718     glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
719 }
720 
iterate(void)721 TestCase::IterateResult VertexArrayObjectTest::iterate(void)
722 {
723     tcu::Surface vaoReference(m_context.getRenderContext().getRenderTarget().getWidth(),
724                               m_context.getRenderContext().getRenderTarget().getHeight());
725     tcu::Surface stateReference(m_context.getRenderContext().getRenderTarget().getWidth(),
726                                 m_context.getRenderContext().getRenderTarget().getHeight());
727 
728     tcu::Surface vaoResult(m_context.getRenderContext().getRenderTarget().getWidth(),
729                            m_context.getRenderContext().getRenderTarget().getHeight());
730     tcu::Surface stateResult(m_context.getRenderContext().getRenderTarget().getWidth(),
731                              m_context.getRenderContext().getRenderTarget().getHeight());
732 
733     bool isOk;
734 
735     logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
736     logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
737     genReferences(stateReference, vaoReference);
738     render(stateResult, vaoResult);
739 
740     isOk = tcu::pixelThresholdCompare(m_log, "Results", "Comparison result from rendering with Vertex Array State",
741                                       stateReference, stateResult, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
742     isOk = isOk &&
743            tcu::pixelThresholdCompare(m_log, "Results", "Comparison result from rendering with Vertex Array Object",
744                                       vaoReference, vaoResult, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
745 
746     if (isOk)
747     {
748         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
749         return STOP;
750     }
751     else
752     {
753         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
754         return STOP;
755     }
756 }
757 
758 class MultiVertexArrayObjectTest : public TestCase
759 {
760 public:
761     MultiVertexArrayObjectTest(Context &context, const char *name, const char *description);
762     ~MultiVertexArrayObjectTest(void);
763     virtual void init(void);
764     virtual void deinit(void);
765     virtual IterateResult iterate(void);
766 
767 private:
768     Spec m_spec;
769     tcu::TestLog &m_log;
770     vector<GLuint> m_buffers;
771     glu::ShaderProgram *m_vaoProgram;
772     glu::ShaderProgram *m_stateProgram;
773     de::Random m_random;
774     uint8_t *m_indices;
775 
776     void logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state, const std::string &msg);
777     uint8_t *createRandomBufferData(const BufferSpec &buffer);
778     uint8_t *generateIndices(void);
779     glu::ShaderProgram *createProgram(const VertexArrayState &state);
780     void setState(const VertexArrayState &state);
781     void render(tcu::Surface &vaoResult, tcu::Surface &defaultResult);
782     void makeDrawCall(const VertexArrayState &state);
783     void genReferences(tcu::Surface &vaoRef, tcu::Surface &defaultRef);
784 
785     MultiVertexArrayObjectTest(const MultiVertexArrayObjectTest &);
786     MultiVertexArrayObjectTest &operator=(const MultiVertexArrayObjectTest &);
787 };
788 
MultiVertexArrayObjectTest(Context & context,const char * name,const char * description)789 MultiVertexArrayObjectTest::MultiVertexArrayObjectTest(Context &context, const char *name, const char *description)
790     : TestCase(context, name, description)
791     , m_log(context.getTestContext().getLog())
792     , m_vaoProgram(NULL)
793     , m_stateProgram(NULL)
794     , m_random(deStringHash(name))
795     , m_indices(NULL)
796 {
797     // Makes zero to zero mapping for buffers
798     m_buffers.push_back(0);
799 }
800 
~MultiVertexArrayObjectTest(void)801 MultiVertexArrayObjectTest::~MultiVertexArrayObjectTest(void)
802 {
803 }
804 
logVertexArrayState(tcu::TestLog & log,const VertexArrayState & state,const std::string & msg)805 void MultiVertexArrayObjectTest::logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state,
806                                                      const std::string &msg)
807 {
808     std::stringstream message;
809 
810     message << msg << "\n";
811     message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
812 
813     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
814     {
815         message << "attribute : " << attribNdx << "\n"
816                 << "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : "
817                 << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") << "\n"
818                 << "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size << "\n"
819                 << "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride << "\n"
820                 << "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type << "\n"
821                 << "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : "
822                 << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") << "\n"
823                 << "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : "
824                 << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") << "\n"
825                 << "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor << "\n"
826                 << "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset << "\n"
827                 << "\t GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx]
828                 << "\n";
829     }
830     log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
831 }
832 
init(void)833 void MultiVertexArrayObjectTest::init(void)
834 {
835     GLint attribCount;
836 
837     GLU_CHECK_CALL(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribCount));
838 
839     m_spec.useDrawElements          = false;
840     m_spec.instances                = 0;
841     m_spec.count                    = 24;
842     m_spec.indexOffset              = 0;
843     m_spec.indexRangeMin            = 0;
844     m_spec.indexRangeMax            = 0;
845     m_spec.indexType                = GL_NONE;
846     m_spec.indexCount               = 0;
847     m_spec.vao.elementArrayBuffer   = 0;
848     m_spec.state.elementArrayBuffer = 0;
849 
850     for (int attribNdx = 0; attribNdx < attribCount; attribNdx++)
851     {
852         BufferSpec shortCoordBuffer48 = {48, 2 * 384, 4, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f};
853         m_spec.buffers.push_back(shortCoordBuffer48);
854 
855         m_spec.state.attributes.push_back(Attribute());
856         m_spec.state.attributes[attribNdx].enabled    = (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
857         m_spec.state.attributes[attribNdx].size       = m_random.getInt(2, 4);
858         m_spec.state.attributes[attribNdx].stride     = 2 * m_random.getInt(1, 3);
859         m_spec.state.attributes[attribNdx].type       = GL_SHORT;
860         m_spec.state.attributes[attribNdx].integer    = m_random.getBool();
861         m_spec.state.attributes[attribNdx].divisor    = m_random.getInt(0, 1);
862         m_spec.state.attributes[attribNdx].offset     = 2 * m_random.getInt(0, 2);
863         m_spec.state.attributes[attribNdx].normalized = m_random.getBool();
864         m_spec.state.attributes[attribNdx].bufferNdx  = attribNdx + 1;
865 
866         if (attribNdx == 0)
867         {
868             m_spec.state.attributes[attribNdx].divisor = 0;
869             m_spec.state.attributes[attribNdx].enabled = GL_TRUE;
870             m_spec.state.attributes[attribNdx].size    = 2;
871         }
872 
873         m_spec.vao.attributes.push_back(Attribute());
874         m_spec.vao.attributes[attribNdx].enabled    = (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
875         m_spec.vao.attributes[attribNdx].size       = m_random.getInt(2, 4);
876         m_spec.vao.attributes[attribNdx].stride     = 2 * m_random.getInt(1, 3);
877         m_spec.vao.attributes[attribNdx].type       = GL_SHORT;
878         m_spec.vao.attributes[attribNdx].integer    = m_random.getBool();
879         m_spec.vao.attributes[attribNdx].divisor    = m_random.getInt(0, 1);
880         m_spec.vao.attributes[attribNdx].offset     = 2 * m_random.getInt(0, 2);
881         m_spec.vao.attributes[attribNdx].normalized = m_random.getBool();
882         m_spec.vao.attributes[attribNdx].bufferNdx  = attribCount - attribNdx;
883 
884         if (attribNdx == 0)
885         {
886             m_spec.vao.attributes[attribNdx].divisor = 0;
887             m_spec.vao.attributes[attribNdx].enabled = GL_TRUE;
888             m_spec.vao.attributes[attribNdx].size    = 2;
889         }
890     }
891 
892     // \note [mika] Index 0 is reserved for 0 buffer
893     for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
894     {
895         uint8_t *data = createRandomBufferData(m_spec.buffers[bufferNdx]);
896 
897         try
898         {
899             GLuint buffer;
900             GLU_CHECK_CALL(glGenBuffers(1, &buffer));
901             m_buffers.push_back(buffer);
902 
903             GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
904             GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
905             GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
906         }
907         catch (...)
908         {
909             delete[] data;
910             throw;
911         }
912 
913         delete[] data;
914     }
915 
916     m_vaoProgram = createProgram(m_spec.vao);
917     m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
918     m_log << *m_vaoProgram;
919     m_stateProgram = createProgram(m_spec.state);
920     m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
921     m_log << *m_stateProgram;
922 
923     if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
924         TCU_FAIL("Failed to compile shaders");
925 
926     if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
927         m_indices = generateIndices();
928 }
929 
deinit(void)930 void MultiVertexArrayObjectTest::deinit(void)
931 {
932     GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
933     m_buffers.clear();
934     delete m_vaoProgram;
935     delete m_stateProgram;
936     delete[] m_indices;
937 }
938 
generateIndices(void)939 uint8_t *MultiVertexArrayObjectTest::generateIndices(void)
940 {
941     int typeSize = 0;
942     switch (m_spec.indexType)
943     {
944     case GL_UNSIGNED_INT:
945         typeSize = sizeof(GLuint);
946         break;
947     case GL_UNSIGNED_SHORT:
948         typeSize = sizeof(GLushort);
949         break;
950     case GL_UNSIGNED_BYTE:
951         typeSize = sizeof(GLubyte);
952         break;
953     default:
954         DE_ASSERT(false);
955     }
956 
957     uint8_t *indices = new uint8_t[m_spec.indexCount * typeSize];
958 
959     for (int i = 0; i < m_spec.indexCount; i++)
960     {
961         uint8_t *pos = indices + typeSize * i;
962 
963         switch (m_spec.indexType)
964         {
965         case GL_UNSIGNED_INT:
966         {
967             GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
968             deMemcpy(pos, &v, sizeof(v));
969             break;
970         }
971 
972         case GL_UNSIGNED_SHORT:
973         {
974             GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
975             deMemcpy(pos, &v, sizeof(v));
976             break;
977         }
978 
979         case GL_UNSIGNED_BYTE:
980         {
981             GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
982             deMemcpy(pos, &v, sizeof(v));
983             break;
984         }
985 
986         default:
987             DE_ASSERT(false);
988         }
989     }
990 
991     return indices;
992 }
993 
createRandomBufferData(const BufferSpec & buffer)994 uint8_t *MultiVertexArrayObjectTest::createRandomBufferData(const BufferSpec &buffer)
995 {
996     uint8_t *data = new uint8_t[buffer.size];
997 
998     int stride;
999 
1000     if (buffer.stride != 0)
1001     {
1002         stride = buffer.stride;
1003     }
1004     else
1005     {
1006         switch (buffer.type)
1007         {
1008         case GL_FLOAT:
1009             stride = buffer.componentCount * (int)sizeof(GLfloat);
1010             break;
1011         case GL_INT:
1012             stride = buffer.componentCount * (int)sizeof(GLint);
1013             break;
1014         case GL_UNSIGNED_INT:
1015             stride = buffer.componentCount * (int)sizeof(GLuint);
1016             break;
1017         case GL_SHORT:
1018             stride = buffer.componentCount * (int)sizeof(GLshort);
1019             break;
1020         case GL_UNSIGNED_SHORT:
1021             stride = buffer.componentCount * (int)sizeof(GLushort);
1022             break;
1023         case GL_BYTE:
1024             stride = buffer.componentCount * (int)sizeof(GLbyte);
1025             break;
1026         case GL_UNSIGNED_BYTE:
1027             stride = buffer.componentCount * (int)sizeof(GLubyte);
1028             break;
1029 
1030         default:
1031             stride = 0;
1032             DE_ASSERT(false);
1033         }
1034     }
1035 
1036     uint8_t *itr = data;
1037 
1038     for (int pos = 0; pos < buffer.count; pos++)
1039     {
1040         uint8_t *componentItr = itr;
1041         for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
1042         {
1043             switch (buffer.type)
1044             {
1045             case GL_FLOAT:
1046             {
1047                 float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
1048                 deMemcpy(componentItr, &v, sizeof(v));
1049                 componentItr += sizeof(v);
1050                 break;
1051             }
1052 
1053             case GL_INT:
1054             {
1055                 GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1056                 deMemcpy(componentItr, &v, sizeof(v));
1057                 componentItr += sizeof(v);
1058                 break;
1059             }
1060 
1061             case GL_UNSIGNED_INT:
1062             {
1063                 GLuint v = (GLuint)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1064                 deMemcpy(componentItr, &v, sizeof(v));
1065                 componentItr += sizeof(v);
1066                 break;
1067             }
1068 
1069             case GL_SHORT:
1070             {
1071                 GLshort v = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1072                 deMemcpy(componentItr, &v, sizeof(v));
1073                 componentItr += sizeof(v);
1074                 break;
1075             }
1076 
1077             case GL_UNSIGNED_SHORT:
1078             {
1079                 GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1080                 deMemcpy(componentItr, &v, sizeof(v));
1081                 componentItr += sizeof(v);
1082                 break;
1083             }
1084 
1085             case GL_BYTE:
1086             {
1087                 GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1088                 deMemcpy(componentItr, &v, sizeof(v));
1089                 componentItr += sizeof(v);
1090                 break;
1091             }
1092 
1093             case GL_UNSIGNED_BYTE:
1094             {
1095                 GLubyte v = (GLubyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
1096                 deMemcpy(componentItr, &v, sizeof(v));
1097                 componentItr += sizeof(v);
1098                 break;
1099             }
1100 
1101             default:
1102                 DE_ASSERT(false);
1103             }
1104         }
1105 
1106         itr += stride;
1107     }
1108 
1109     return data;
1110 }
1111 
createProgram(const VertexArrayState & state)1112 glu::ShaderProgram *MultiVertexArrayObjectTest::createProgram(const VertexArrayState &state)
1113 {
1114     std::stringstream vertexShaderStream;
1115     std::stringstream value;
1116 
1117     vertexShaderStream << "#version 300 es\n";
1118 
1119     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
1120     {
1121         if (state.attributes[attribNdx].integer)
1122             vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx
1123                                << ";\n";
1124         else
1125             vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx
1126                                << ";\n";
1127 
1128         if (state.attributes[attribNdx].integer)
1129         {
1130             float scale = 0.0f;
1131 
1132             switch (state.attributes[0].type)
1133             {
1134             case GL_SHORT:
1135                 scale = (1.0f / float((1u << 14) - 1u));
1136                 break;
1137             case GL_UNSIGNED_SHORT:
1138                 scale = (1.0f / float((1u << 15) - 1u));
1139                 break;
1140             case GL_INT:
1141                 scale = (1.0f / float((1u << 30) - 1u));
1142                 break;
1143             case GL_UNSIGNED_INT:
1144                 scale = (1.0f / float((1u << 31) - 1u));
1145                 break;
1146             case GL_BYTE:
1147                 scale = (1.0f / float((1u << 6) - 1u));
1148                 break;
1149             case GL_UNSIGNED_BYTE:
1150                 scale = (1.0f / float((1u << 7) - 1u));
1151                 break;
1152 
1153             default:
1154                 DE_ASSERT(false);
1155             }
1156             value << (attribNdx != 0 ? " + " : "") << scale << " * vec4(a_attrib" << attribNdx << ")";
1157         }
1158         else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
1159         {
1160             float scale = 0.0f;
1161 
1162             switch (state.attributes[0].type)
1163             {
1164             case GL_SHORT:
1165                 scale = (0.5f / float((1u << 14) - 1u));
1166                 break;
1167             case GL_UNSIGNED_SHORT:
1168                 scale = (0.5f / float((1u << 15) - 1u));
1169                 break;
1170             case GL_INT:
1171                 scale = (0.5f / float((1u << 30) - 1u));
1172                 break;
1173             case GL_UNSIGNED_INT:
1174                 scale = (0.5f / float((1u << 31) - 1u));
1175                 break;
1176             case GL_BYTE:
1177                 scale = (0.5f / float((1u << 6) - 1u));
1178                 break;
1179             case GL_UNSIGNED_BYTE:
1180                 scale = (0.5f / float((1u << 7) - 1u));
1181                 break;
1182 
1183             default:
1184                 DE_ASSERT(false);
1185             }
1186             value << (attribNdx != 0 ? " + " : "") << scale << " * a_attrib" << attribNdx;
1187         }
1188         else
1189             value << (attribNdx != 0 ? " + " : "") << "a_attrib" << attribNdx;
1190     }
1191 
1192     vertexShaderStream << "out mediump vec4 v_value;\n"
1193                        << "void main (void)\n"
1194                        << "{\n"
1195                        << "\tv_value = " << value.str() << ";\n";
1196 
1197     if (state.attributes[0].integer)
1198     {
1199         float scale = 0.0f;
1200 
1201         switch (state.attributes[0].type)
1202         {
1203         case GL_SHORT:
1204             scale = (1.0f / float((1u << 14) - 1u));
1205             break;
1206         case GL_UNSIGNED_SHORT:
1207             scale = (1.0f / float((1u << 15) - 1u));
1208             break;
1209         case GL_INT:
1210             scale = (1.0f / float((1u << 30) - 1u));
1211             break;
1212         case GL_UNSIGNED_INT:
1213             scale = (1.0f / float((1u << 31) - 1u));
1214             break;
1215         case GL_BYTE:
1216             scale = (1.0f / float((1u << 6) - 1u));
1217             break;
1218         case GL_UNSIGNED_BYTE:
1219             scale = (1.0f / float((1u << 7) - 1u));
1220             break;
1221 
1222         default:
1223             DE_ASSERT(false);
1224         }
1225 
1226         vertexShaderStream << "\tgl_Position = vec4(" << scale << " * "
1227                            << "a_attrib0.xyz, 1.0);\n"
1228                            << "}";
1229     }
1230     else
1231     {
1232         if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
1233         {
1234             vertexShaderStream << "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
1235                                << "}";
1236         }
1237         else
1238         {
1239             float scale = 0.0f;
1240 
1241             switch (state.attributes[0].type)
1242             {
1243             case GL_SHORT:
1244                 scale = (1.0f / float((1u << 14) - 1u));
1245                 break;
1246             case GL_UNSIGNED_SHORT:
1247                 scale = (1.0f / float((1u << 15) - 1u));
1248                 break;
1249             case GL_INT:
1250                 scale = (1.0f / float((1u << 30) - 1u));
1251                 break;
1252             case GL_UNSIGNED_INT:
1253                 scale = (1.0f / float((1u << 31) - 1u));
1254                 break;
1255             case GL_BYTE:
1256                 scale = (1.0f / float((1u << 6) - 1u));
1257                 break;
1258             case GL_UNSIGNED_BYTE:
1259                 scale = (1.0f / float((1u << 7) - 1u));
1260                 break;
1261 
1262             default:
1263                 DE_ASSERT(false);
1264             }
1265 
1266             scale *= 0.5f;
1267 
1268             vertexShaderStream << "\tgl_Position = vec4(" << scale << " * "
1269                                << "vec3(a_attrib0.xyz), 1.0);\n"
1270                                << "}";
1271         }
1272     }
1273 
1274     const char *fragmentShader = "#version 300 es\n"
1275                                  "in mediump vec4 v_value;\n"
1276                                  "layout(location = 0) out mediump vec4 fragColor;\n"
1277                                  "void main (void)\n"
1278                                  "{\n"
1279                                  "\tfragColor = vec4(v_value.xyz, 1.0);\n"
1280                                  "}";
1281 
1282     return new glu::ShaderProgram(m_context.getRenderContext(),
1283                                   glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
1284 }
1285 
setState(const VertexArrayState & state)1286 void MultiVertexArrayObjectTest::setState(const VertexArrayState &state)
1287 {
1288     GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
1289 
1290     for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
1291     {
1292         GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
1293         if (state.attributes[attribNdx].enabled)
1294             GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
1295         else
1296             GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
1297 
1298         if (state.attributes[attribNdx].integer)
1299             GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size,
1300                                                   state.attributes[attribNdx].type, state.attributes[attribNdx].stride,
1301                                                   (const GLvoid *)((GLintptr)state.attributes[attribNdx].offset)));
1302         else
1303             GLU_CHECK_CALL(
1304                 glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type,
1305                                       state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride,
1306                                       (const GLvoid *)((GLintptr)state.attributes[attribNdx].offset)));
1307 
1308         GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
1309     }
1310 }
1311 
makeDrawCall(const VertexArrayState & state)1312 void MultiVertexArrayObjectTest::makeDrawCall(const VertexArrayState &state)
1313 {
1314     GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
1315     GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1316 
1317     if (m_spec.useDrawElements)
1318     {
1319         if (state.elementArrayBuffer == 0)
1320         {
1321             if (m_spec.instances == 0)
1322                 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
1323             else
1324                 GLU_CHECK_CALL(
1325                     glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
1326         }
1327         else
1328         {
1329             if (m_spec.instances == 0)
1330                 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType,
1331                                               (GLvoid *)((GLintptr)m_spec.indexOffset)));
1332             else
1333                 GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType,
1334                                                        (GLvoid *)((GLintptr)m_spec.indexOffset), m_spec.instances));
1335         }
1336     }
1337     else
1338     {
1339         if (m_spec.instances == 0)
1340             GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
1341         else
1342             GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
1343     }
1344 }
1345 
render(tcu::Surface & vaoResult,tcu::Surface & defaultResult)1346 void MultiVertexArrayObjectTest::render(tcu::Surface &vaoResult, tcu::Surface &defaultResult)
1347 {
1348     GLuint vao = 0;
1349 
1350     GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
1351     GLU_CHECK_CALL(glBindVertexArray(vao));
1352     setState(m_spec.vao);
1353     GLU_CHECK_CALL(glBindVertexArray(0));
1354 
1355     setState(m_spec.state);
1356 
1357     GLU_CHECK_CALL(glBindVertexArray(vao));
1358     GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
1359     makeDrawCall(m_spec.vao);
1360     glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
1361     setState(m_spec.vao);
1362     GLU_CHECK_CALL(glBindVertexArray(0));
1363 
1364     GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
1365     makeDrawCall(m_spec.state);
1366     glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
1367 }
1368 
genReferences(tcu::Surface & vaoRef,tcu::Surface & defaultRef)1369 void MultiVertexArrayObjectTest::genReferences(tcu::Surface &vaoRef, tcu::Surface &defaultRef)
1370 {
1371     setState(m_spec.vao);
1372     GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
1373     makeDrawCall(m_spec.vao);
1374     glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
1375 
1376     setState(m_spec.state);
1377     GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
1378     makeDrawCall(m_spec.state);
1379     glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
1380 }
1381 
iterate(void)1382 TestCase::IterateResult MultiVertexArrayObjectTest::iterate(void)
1383 {
1384     tcu::Surface vaoReference(m_context.getRenderContext().getRenderTarget().getWidth(),
1385                               m_context.getRenderContext().getRenderTarget().getHeight());
1386     tcu::Surface stateReference(m_context.getRenderContext().getRenderTarget().getWidth(),
1387                                 m_context.getRenderContext().getRenderTarget().getHeight());
1388 
1389     tcu::Surface vaoResult(m_context.getRenderContext().getRenderTarget().getWidth(),
1390                            m_context.getRenderContext().getRenderTarget().getHeight());
1391     tcu::Surface stateResult(m_context.getRenderContext().getRenderTarget().getWidth(),
1392                              m_context.getRenderContext().getRenderTarget().getHeight());
1393 
1394     bool isOk;
1395 
1396     logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
1397     logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
1398     genReferences(stateReference, vaoReference);
1399     render(stateResult, vaoResult);
1400 
1401     isOk = tcu::pixelThresholdCompare(m_log, "Results", "Comparison result from rendering with Vertex Array State",
1402                                       stateReference, stateResult, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1403     isOk = isOk &&
1404            tcu::pixelThresholdCompare(m_log, "Results", "Comparison result from rendering with Vertex Array Object",
1405                                       vaoReference, vaoResult, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1406 
1407     if (isOk)
1408     {
1409         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1410         return STOP;
1411     }
1412     else
1413     {
1414         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1415         return STOP;
1416     }
1417 }
1418 
VertexArrayObjectTestGroup(Context & context)1419 VertexArrayObjectTestGroup::VertexArrayObjectTestGroup(Context &context)
1420     : TestCaseGroup(context, "vertex_array_objects", "Vertex array object test cases")
1421 {
1422 }
1423 
~VertexArrayObjectTestGroup(void)1424 VertexArrayObjectTestGroup::~VertexArrayObjectTestGroup(void)
1425 {
1426 }
1427 
init(void)1428 void VertexArrayObjectTestGroup::init(void)
1429 {
1430     BufferSpec floatCoordBuffer48_1 = {48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f};
1431     BufferSpec floatCoordBuffer48_2 = {48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f};
1432 
1433     BufferSpec shortCoordBuffer48 = {48, 192, 2, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f};
1434 
1435     // Different buffer
1436     {
1437         Spec spec;
1438 
1439         VertexArrayState state;
1440 
1441         state.attributes.push_back(Attribute());
1442 
1443         state.attributes[0].enabled    = true;
1444         state.attributes[0].size       = 2;
1445         state.attributes[0].stride     = 0;
1446         state.attributes[0].type       = GL_FLOAT;
1447         state.attributes[0].integer    = GL_FALSE;
1448         state.attributes[0].divisor    = 0;
1449         state.attributes[0].offset     = 0;
1450         state.attributes[0].normalized = GL_FALSE;
1451 
1452         state.elementArrayBuffer = 0;
1453 
1454         spec.buffers.push_back(floatCoordBuffer48_1);
1455         spec.buffers.push_back(floatCoordBuffer48_2);
1456 
1457         spec.useDrawElements = false;
1458         spec.instances       = 0;
1459         spec.count           = 48;
1460         spec.vao             = state;
1461         spec.state           = state;
1462         spec.indexOffset     = 0;
1463         spec.indexRangeMin   = 0;
1464         spec.indexRangeMax   = 0;
1465         spec.indexType       = GL_NONE;
1466         spec.indexCount      = 0;
1467 
1468         spec.state.attributes[0].bufferNdx = 1;
1469         spec.vao.attributes[0].bufferNdx   = 2;
1470         addChild(new VertexArrayObjectTest(m_context, spec, "diff_buffer", "diff_buffer"));
1471     }
1472     // Different size
1473     {
1474         Spec spec;
1475 
1476         VertexArrayState state;
1477 
1478         state.attributes.push_back(Attribute());
1479 
1480         state.attributes[0].enabled    = true;
1481         state.attributes[0].size       = 2;
1482         state.attributes[0].stride     = 0;
1483         state.attributes[0].type       = GL_FLOAT;
1484         state.attributes[0].integer    = GL_FALSE;
1485         state.attributes[0].divisor    = 0;
1486         state.attributes[0].offset     = 0;
1487         state.attributes[0].normalized = GL_FALSE;
1488         state.attributes[0].bufferNdx  = 1;
1489 
1490         state.elementArrayBuffer = 0;
1491 
1492         spec.buffers.push_back(floatCoordBuffer48_1);
1493 
1494         spec.useDrawElements = false;
1495         spec.instances       = 0;
1496         spec.count           = 24;
1497         spec.vao             = state;
1498         spec.state           = state;
1499         spec.indexOffset     = 0;
1500         spec.indexRangeMin   = 0;
1501         spec.indexRangeMax   = 0;
1502         spec.indexType       = GL_NONE;
1503         spec.indexCount      = 0;
1504 
1505         spec.state.attributes[0].size = 2;
1506         spec.vao.attributes[0].size   = 3;
1507         addChild(new VertexArrayObjectTest(m_context, spec, "diff_size", "diff_size"));
1508     }
1509 
1510     // Different stride
1511     {
1512         Spec spec;
1513 
1514         VertexArrayState state;
1515 
1516         state.attributes.push_back(Attribute());
1517 
1518         state.attributes[0].enabled    = true;
1519         state.attributes[0].size       = 2;
1520         state.attributes[0].stride     = 0;
1521         state.attributes[0].type       = GL_SHORT;
1522         state.attributes[0].integer    = GL_FALSE;
1523         state.attributes[0].divisor    = 0;
1524         state.attributes[0].offset     = 0;
1525         state.attributes[0].normalized = GL_TRUE;
1526         state.attributes[0].bufferNdx  = 1;
1527 
1528         state.elementArrayBuffer = 0;
1529 
1530         spec.buffers.push_back(shortCoordBuffer48);
1531 
1532         spec.useDrawElements = false;
1533         spec.instances       = 0;
1534         spec.count           = 24;
1535         spec.vao             = state;
1536         spec.state           = state;
1537         spec.indexOffset     = 0;
1538         spec.indexRangeMin   = 0;
1539         spec.indexRangeMax   = 0;
1540         spec.indexType       = GL_NONE;
1541         spec.indexCount      = 0;
1542 
1543         spec.vao.attributes[0].stride   = 2;
1544         spec.state.attributes[0].stride = 4;
1545         addChild(new VertexArrayObjectTest(m_context, spec, "diff_stride", "diff_stride"));
1546     }
1547 
1548     // Different types
1549     {
1550         Spec spec;
1551 
1552         VertexArrayState state;
1553 
1554         state.attributes.push_back(Attribute());
1555 
1556         state.attributes[0].enabled    = true;
1557         state.attributes[0].size       = 2;
1558         state.attributes[0].stride     = 0;
1559         state.attributes[0].type       = GL_SHORT;
1560         state.attributes[0].integer    = GL_FALSE;
1561         state.attributes[0].divisor    = 0;
1562         state.attributes[0].offset     = 0;
1563         state.attributes[0].normalized = GL_TRUE;
1564         state.attributes[0].bufferNdx  = 1;
1565 
1566         state.elementArrayBuffer = 0;
1567 
1568         spec.buffers.push_back(shortCoordBuffer48);
1569 
1570         spec.useDrawElements = false;
1571         spec.instances       = 0;
1572         spec.count           = 24;
1573         spec.vao             = state;
1574         spec.state           = state;
1575         spec.indexOffset     = 0;
1576         spec.indexRangeMin   = 0;
1577         spec.indexRangeMax   = 0;
1578         spec.indexType       = GL_NONE;
1579         spec.indexCount      = 0;
1580 
1581         spec.vao.attributes[0].type   = GL_SHORT;
1582         spec.state.attributes[0].type = GL_BYTE;
1583         addChild(new VertexArrayObjectTest(m_context, spec, "diff_type", "diff_type"));
1584     }
1585     // Different "integer"
1586     {
1587         Spec spec;
1588 
1589         VertexArrayState state;
1590 
1591         state.attributes.push_back(Attribute());
1592 
1593         state.attributes[0].enabled    = true;
1594         state.attributes[0].size       = 2;
1595         state.attributes[0].stride     = 0;
1596         state.attributes[0].type       = GL_BYTE;
1597         state.attributes[0].integer    = GL_TRUE;
1598         state.attributes[0].divisor    = 0;
1599         state.attributes[0].offset     = 0;
1600         state.attributes[0].normalized = GL_FALSE;
1601         state.attributes[0].bufferNdx  = 1;
1602 
1603         state.elementArrayBuffer = 0;
1604 
1605         spec.buffers.push_back(shortCoordBuffer48);
1606 
1607         spec.useDrawElements = false;
1608         spec.count           = 24;
1609         spec.vao             = state;
1610         spec.state           = state;
1611         spec.instances       = 0;
1612         spec.indexOffset     = 0;
1613         spec.indexRangeMin   = 0;
1614         spec.indexRangeMax   = 0;
1615         spec.indexType       = GL_NONE;
1616         spec.indexCount      = 0;
1617 
1618         spec.state.attributes[0].integer = GL_FALSE;
1619         spec.vao.attributes[0].integer   = GL_TRUE;
1620         addChild(new VertexArrayObjectTest(m_context, spec, "diff_integer", "diff_integer"));
1621     }
1622     // Different divisor
1623     {
1624         Spec spec;
1625 
1626         VertexArrayState state;
1627 
1628         state.attributes.push_back(Attribute());
1629         state.attributes.push_back(Attribute());
1630 
1631         state.attributes[0].enabled    = true;
1632         state.attributes[0].size       = 2;
1633         state.attributes[0].stride     = 0;
1634         state.attributes[0].type       = GL_SHORT;
1635         state.attributes[0].integer    = GL_FALSE;
1636         state.attributes[0].divisor    = 0;
1637         state.attributes[0].offset     = 0;
1638         state.attributes[0].normalized = GL_TRUE;
1639         state.attributes[0].bufferNdx  = 1;
1640 
1641         state.attributes[1].enabled    = true;
1642         state.attributes[1].size       = 4;
1643         state.attributes[1].stride     = 0;
1644         state.attributes[1].type       = GL_FLOAT;
1645         state.attributes[1].integer    = GL_FALSE;
1646         state.attributes[1].divisor    = 0;
1647         state.attributes[1].offset     = 0;
1648         state.attributes[1].normalized = GL_FALSE;
1649         state.attributes[1].bufferNdx  = 2;
1650 
1651         state.elementArrayBuffer = 0;
1652 
1653         spec.buffers.push_back(shortCoordBuffer48);
1654         spec.buffers.push_back(floatCoordBuffer48_1);
1655 
1656         spec.useDrawElements = false;
1657         spec.instances       = 10;
1658         spec.count           = 12;
1659         spec.vao             = state;
1660         spec.state           = state;
1661         spec.indexOffset     = 0;
1662         spec.indexRangeMin   = 0;
1663         spec.indexRangeMax   = 0;
1664         spec.indexType       = GL_NONE;
1665         spec.indexCount      = 0;
1666 
1667         spec.vao.attributes[1].divisor   = 3;
1668         spec.state.attributes[1].divisor = 2;
1669 
1670         addChild(new VertexArrayObjectTest(m_context, spec, "diff_divisor", "diff_divisor"));
1671     }
1672     // Different offset
1673     {
1674         Spec spec;
1675 
1676         VertexArrayState state;
1677 
1678         state.attributes.push_back(Attribute());
1679 
1680         state.attributes[0].enabled    = true;
1681         state.attributes[0].size       = 2;
1682         state.attributes[0].stride     = 0;
1683         state.attributes[0].type       = GL_SHORT;
1684         state.attributes[0].integer    = GL_FALSE;
1685         state.attributes[0].divisor    = 0;
1686         state.attributes[0].offset     = 0;
1687         state.attributes[0].normalized = GL_TRUE;
1688         state.attributes[0].bufferNdx  = 1;
1689 
1690         state.elementArrayBuffer = 0;
1691 
1692         spec.buffers.push_back(shortCoordBuffer48);
1693 
1694         spec.useDrawElements = false;
1695         spec.instances       = 0;
1696         spec.count           = 24;
1697         spec.vao             = state;
1698         spec.state           = state;
1699         spec.indexOffset     = 0;
1700         spec.indexRangeMin   = 0;
1701         spec.indexRangeMax   = 0;
1702         spec.indexType       = GL_NONE;
1703         spec.indexCount      = 0;
1704 
1705         spec.vao.attributes[0].offset   = 2;
1706         spec.state.attributes[0].offset = 4;
1707         addChild(new VertexArrayObjectTest(m_context, spec, "diff_offset", "diff_offset"));
1708     }
1709     // Different normalize
1710     {
1711         Spec spec;
1712 
1713         VertexArrayState state;
1714 
1715         state.attributes.push_back(Attribute());
1716 
1717         state.attributes[0].enabled    = true;
1718         state.attributes[0].size       = 2;
1719         state.attributes[0].stride     = 0;
1720         state.attributes[0].type       = GL_SHORT;
1721         state.attributes[0].integer    = GL_FALSE;
1722         state.attributes[0].divisor    = 0;
1723         state.attributes[0].offset     = 0;
1724         state.attributes[0].normalized = GL_TRUE;
1725         state.attributes[0].bufferNdx  = 1;
1726 
1727         state.elementArrayBuffer = 0;
1728 
1729         spec.buffers.push_back(shortCoordBuffer48);
1730 
1731         spec.useDrawElements = false;
1732         spec.instances       = 0;
1733         spec.count           = 48;
1734         spec.vao             = state;
1735         spec.state           = state;
1736         spec.indexOffset     = 0;
1737         spec.indexRangeMin   = 0;
1738         spec.indexRangeMax   = 0;
1739         spec.indexType       = GL_NONE;
1740         spec.indexCount      = 0;
1741 
1742         spec.vao.attributes[0].normalized   = GL_TRUE;
1743         spec.state.attributes[0].normalized = GL_FALSE;
1744         addChild(new VertexArrayObjectTest(m_context, spec, "diff_normalize", "diff_normalize"));
1745     }
1746     // DrawElements with buffer / Pointer
1747     {
1748         Spec spec;
1749 
1750         VertexArrayState state;
1751 
1752         state.attributes.push_back(Attribute());
1753 
1754         state.attributes[0].enabled    = true;
1755         state.attributes[0].size       = 2;
1756         state.attributes[0].stride     = 0;
1757         state.attributes[0].type       = GL_FLOAT;
1758         state.attributes[0].integer    = GL_FALSE;
1759         state.attributes[0].divisor    = 0;
1760         state.attributes[0].offset     = 0;
1761         state.attributes[0].normalized = GL_TRUE;
1762         state.attributes[0].bufferNdx  = 1;
1763 
1764         state.elementArrayBuffer = 0;
1765 
1766         spec.buffers.push_back(floatCoordBuffer48_1);
1767 
1768         BufferSpec indexBuffer = {24, 192, 1, 0, 0, GL_UNSIGNED_SHORT, 0, 48, 0.0f, 0.0f};
1769         spec.buffers.push_back(indexBuffer);
1770 
1771         spec.useDrawElements = true;
1772         spec.count           = 24;
1773         spec.vao             = state;
1774         spec.state           = state;
1775         spec.instances       = 0;
1776         spec.indexOffset     = 0;
1777         spec.indexRangeMin   = 0;
1778         spec.indexRangeMax   = 48;
1779         spec.indexType       = GL_UNSIGNED_SHORT;
1780         spec.indexCount      = 24;
1781 
1782         spec.state.elementArrayBuffer = 0;
1783         spec.vao.elementArrayBuffer   = 2;
1784         addChild(new VertexArrayObjectTest(m_context, spec, "diff_indices", "diff_indices"));
1785     }
1786     // Use all attributes
1787 
1788     addChild(new MultiVertexArrayObjectTest(m_context, "all_attributes", "all_attributes"));
1789 }
1790 
1791 } // namespace Functional
1792 } // namespace gles3
1793 } // namespace deqp
1794