xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fDrawElementsBaseVertexTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2017 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 GL_EXT_draw_elements_base_vertex tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fDrawElementsBaseVertexTests.hpp"
25 #include "deRandom.hpp"
26 #include "deStringUtil.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "sglrGLContext.hpp"
30 #include "glsDrawTest.hpp"
31 #include "gluStrUtil.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluContextInfo.hpp"
34 
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37 
38 #include <string>
39 #include <set>
40 
41 using std::string;
42 using std::vector;
43 using tcu::TestLog;
44 
45 using namespace glw;
46 
47 namespace deqp
48 {
49 namespace gles31
50 {
51 namespace Functional
52 {
53 namespace
54 {
55 
56 enum TestIterationType
57 {
58     TYPE_DRAW_COUNT,     // !< test with 1, 5, and 25 primitives
59     TYPE_INSTANCE_COUNT, // !< test with 1, 4, and 11 instances
60 
61     TYPE_LAST
62 };
63 
getElementCount(gls::DrawTestSpec::Primitive primitive,size_t primitiveCount)64 static size_t getElementCount(gls::DrawTestSpec::Primitive primitive, size_t primitiveCount)
65 {
66     switch (primitive)
67     {
68     case gls::DrawTestSpec::PRIMITIVE_POINTS:
69         return primitiveCount;
70     case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:
71         return primitiveCount * 3;
72     case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
73         return primitiveCount + 2;
74     case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
75         return primitiveCount + 2;
76     case gls::DrawTestSpec::PRIMITIVE_LINES:
77         return primitiveCount * 2;
78     case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:
79         return primitiveCount + 1;
80     case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:
81         return (primitiveCount == 1) ? (2) : (primitiveCount);
82     case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
83         return primitiveCount * 4;
84     case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
85         return primitiveCount + 3;
86     case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
87         return primitiveCount * 6;
88     case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
89         return primitiveCount * 2 + 4;
90     default:
91         DE_ASSERT(false);
92         return 0;
93     }
94 }
95 
addRangeElementsToSpec(gls::DrawTestSpec & spec)96 static void addRangeElementsToSpec(gls::DrawTestSpec &spec)
97 {
98     if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
99     {
100         spec.indexMin = 0;
101         spec.indexMax = (int)getElementCount(spec.primitive, spec.primitiveCount);
102     }
103 }
104 
addTestIterations(gls::DrawTest * test,gls::DrawTestSpec & spec,TestIterationType type)105 static void addTestIterations(gls::DrawTest *test, gls::DrawTestSpec &spec, TestIterationType type)
106 {
107     if (type == TYPE_DRAW_COUNT)
108     {
109         spec.primitiveCount = 1;
110         addRangeElementsToSpec(spec);
111         test->addIteration(spec, "draw count = 1");
112 
113         spec.primitiveCount = 5;
114         addRangeElementsToSpec(spec);
115         test->addIteration(spec, "draw count = 5");
116 
117         spec.primitiveCount = 25;
118         addRangeElementsToSpec(spec);
119         test->addIteration(spec, "draw count = 25");
120     }
121     else if (type == TYPE_INSTANCE_COUNT)
122     {
123         spec.instanceCount = 1;
124         addRangeElementsToSpec(spec);
125         test->addIteration(spec, "instance count = 1");
126 
127         spec.instanceCount = 4;
128         addRangeElementsToSpec(spec);
129         test->addIteration(spec, "instance count = 4");
130 
131         spec.instanceCount = 11;
132         addRangeElementsToSpec(spec);
133         test->addIteration(spec, "instance count = 11");
134     }
135     else
136         DE_ASSERT(false);
137 }
138 
genBasicSpec(gls::DrawTestSpec & spec,glu::ContextType & contextType,gls::DrawTestSpec::DrawMethod method)139 static void genBasicSpec(gls::DrawTestSpec &spec, glu::ContextType &contextType, gls::DrawTestSpec::DrawMethod method)
140 {
141     spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
142     spec.primitive          = gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
143     spec.primitiveCount     = 5;
144     spec.drawMethod         = method;
145     spec.indexType          = gls::DrawTestSpec::INDEXTYPE_LAST;
146     spec.indexPointerOffset = 0;
147     spec.indexStorage       = gls::DrawTestSpec::STORAGE_LAST;
148     spec.first              = 0;
149     spec.indexMin           = 0;
150     spec.indexMax           = 0;
151     spec.instanceCount      = 1;
152     spec.indirectOffset     = 0;
153 
154     spec.attribs.resize(2);
155 
156     spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
157     spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
158     spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
159     spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
160     spec.attribs[0].componentCount      = 4;
161     spec.attribs[0].offset              = 0;
162     spec.attribs[0].stride              = 0;
163     spec.attribs[0].normalize           = false;
164     spec.attribs[0].instanceDivisor     = 0;
165     spec.attribs[0].useDefaultAttribute = false;
166 
167     spec.attribs[1].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
168     spec.attribs[1].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
169     spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
170     spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
171     spec.attribs[1].componentCount      = 2;
172     spec.attribs[1].offset              = 0;
173     spec.attribs[1].stride              = 0;
174     spec.attribs[1].normalize           = false;
175     spec.attribs[1].instanceDivisor     = 0;
176     spec.attribs[1].useDefaultAttribute = false;
177 
178     addRangeElementsToSpec(spec);
179 }
180 
181 class VertexIDCase : public TestCase
182 {
183 public:
184     VertexIDCase(Context &context, gls::DrawTestSpec::DrawMethod drawMethod);
185     ~VertexIDCase(void);
186 
187     void init(void);
188     void deinit(void);
189     IterateResult iterate(void);
190 
191     void draw(GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLint baseVertex);
192     void verifyImage(const tcu::Surface &image);
193 
194 private:
195     const glw::Functions &m_gl;
196     glu::ShaderProgram *m_program;
197     GLuint m_vao;
198     GLuint m_coordinatesBuffer;
199     GLuint m_elementsBuffer;
200     int m_iterNdx;
201     gls::DrawTestSpec::DrawMethod m_method;
202 
203     enum
204     {
205         VIEWPORT_WIDTH  = 64,
206         VIEWPORT_HEIGHT = 64
207     };
208 
209     enum
210     {
211         MAX_VERTICES = 2 * 3 //!< 2 triangles, totals 6 vertices
212     };
213 };
214 
VertexIDCase(Context & context,gls::DrawTestSpec::DrawMethod drawMethod)215 VertexIDCase::VertexIDCase(Context &context, gls::DrawTestSpec::DrawMethod drawMethod)
216     : TestCase(context, "vertex_id", "gl_VertexID Test")
217     , m_gl(m_context.getRenderContext().getFunctions())
218     , m_program(DE_NULL)
219     , m_vao(0)
220     , m_coordinatesBuffer(0)
221     , m_elementsBuffer(0)
222     , m_iterNdx(0)
223     , m_method(drawMethod)
224 {
225 }
226 
~VertexIDCase(void)227 VertexIDCase::~VertexIDCase(void)
228 {
229     VertexIDCase::deinit();
230 }
231 
init(void)232 void VertexIDCase::init(void)
233 {
234     auto ctxType = m_context.getRenderContext().getType();
235     if (m_method == deqp::gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX ||
236         m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX ||
237         m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
238     {
239         const bool supportsES32orGL45 =
240             contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5));
241         TCU_CHECK_AND_THROW(NotSupportedError,
242                             supportsES32orGL45 ||
243                                 m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_elements_base_vertex"),
244                             "GL_EXT_draw_elements_base_vertex is not supported.");
245     }
246 
247     m_testCtx.getLog() << TestLog::Message
248                        << "gl_VertexID should be the index of the vertex that is being passed to the shader. i.e. "
249                           "indices[i] + basevertex"
250                        << TestLog::EndMessage;
251 
252     DE_ASSERT(!m_program);
253     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
254                                        glu::makeVtxFragSources("#version 310 es\n"
255                                                                "in highp vec4 a_position;\n"
256                                                                "out mediump vec4 v_color;\n"
257                                                                "uniform highp vec4 u_colors[8];\n"
258                                                                "void main (void)\n"
259                                                                "{\n"
260                                                                "    gl_Position = a_position;\n"
261                                                                "    v_color = u_colors[gl_VertexID];\n"
262                                                                "}\n",
263 
264                                                                "#version 310 es\n"
265                                                                "in mediump vec4 v_color;\n"
266                                                                "layout(location = 0) out mediump vec4 o_color;\n"
267                                                                "void main (void)\n"
268                                                                "{\n"
269                                                                "    o_color = v_color;\n"
270                                                                "}\n"));
271 
272     m_testCtx.getLog() << *m_program;
273 
274     if (!m_program->isOk())
275     {
276         delete m_program;
277         m_program = DE_NULL;
278         TCU_FAIL("Failed to compile shader program");
279     }
280 
281     GLU_CHECK_GLW_CALL(m_gl, useProgram(m_program->getProgram()));
282 
283     GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_coordinatesBuffer));
284     GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_elementsBuffer));
285 
286     if (!glu::isContextTypeES(ctxType))
287         GLU_CHECK_GLW_CALL(m_gl, genVertexArrays(1, &m_vao));
288 }
289 
deinit(void)290 void VertexIDCase::deinit(void)
291 {
292     delete m_program;
293     m_program = DE_NULL;
294 
295     if (m_elementsBuffer)
296     {
297         GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_elementsBuffer));
298         m_elementsBuffer = 0;
299     }
300 
301     if (m_coordinatesBuffer)
302     {
303         GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_coordinatesBuffer));
304         m_coordinatesBuffer = 0;
305     }
306 
307     if (m_vao)
308     {
309         GLU_CHECK_GLW_CALL(m_gl, deleteVertexArrays(1, &m_vao));
310         m_vao = 0;
311     }
312 }
313 
draw(GLenum mode,GLsizei count,GLenum type,GLvoid * indices,GLint baseVertex)314 void VertexIDCase::draw(GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLint baseVertex)
315 {
316     switch (m_method)
317     {
318     case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX:
319         GLU_CHECK_GLW_CALL(m_gl, drawElementsBaseVertex(mode, count, type, indices, baseVertex));
320         break;
321 
322     case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX:
323     {
324         GLint maxElementsVertices = 0;
325         GLU_CHECK_GLW_CALL(m_gl, getIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxElementsVertices));
326         GLU_CHECK_GLW_CALL(m_gl,
327                            drawRangeElementsBaseVertex(mode, 0, maxElementsVertices, count, type, indices, baseVertex));
328         break;
329     }
330 
331     case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX:
332         GLU_CHECK_GLW_CALL(m_gl, drawElementsInstancedBaseVertex(mode, count, type, indices, 1, baseVertex));
333         break;
334 
335     default:
336         DE_FATAL("Draw method not supported");
337     }
338 }
339 
verifyImage(const tcu::Surface & image)340 void VertexIDCase::verifyImage(const tcu::Surface &image)
341 {
342     tcu::TestLog &log = m_testCtx.getLog();
343     bool isOk         = true;
344 
345     const int colorThreshold = 0; // expect perfect match
346     tcu::Surface error(image.getWidth(), image.getHeight());
347 
348     for (int y = 0; y < image.getHeight(); y++)
349         for (int x = 0; x < image.getWidth(); x++)
350         {
351             const tcu::RGBA pixel = image.getPixel(x, y);
352             bool pixelOk          = true;
353 
354             // Ignore pixels not drawn with basevertex
355             if ((x < image.getWidth() * 1 / 4) || (x > image.getWidth() * 3 / 4) || (y < image.getHeight() * 1 / 4) ||
356                 (y > image.getHeight() * 3 / 4))
357                 continue;
358 
359             // Any pixel with !(B ~= 255) is faulty
360             if (de::abs(pixel.getBlue() - 255) > colorThreshold)
361                 pixelOk = false;
362 
363             error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
364             isOk = isOk && pixelOk;
365         }
366 
367     if (!isOk)
368     {
369         log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
370         log << TestLog::ImageSet("Verification result", "Result of rendering")
371             << TestLog::Image("Result", "Result", image) << TestLog::Image("Error Mask", "Error mask", error)
372             << TestLog::EndImageSet;
373     }
374     else
375     {
376         log << TestLog::ImageSet("Verification result", "Result of rendering")
377             << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet;
378     }
379 
380     if (isOk)
381         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
382     else
383         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
384 }
385 
iterate(void)386 VertexIDCase::IterateResult VertexIDCase::iterate(void)
387 {
388     const GLuint drawCount     = 6;
389     const GLuint baseVertex    = 4;
390     const GLuint coordLocation = m_gl.getAttribLocation(m_program->getProgram(), "a_position");
391     const GLuint colorLocation = m_gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
392 
393     tcu::Surface surface(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
394 
395     const GLfloat coords[] = {
396         // full viewport quad
397         -1.0f,
398         -1.0f,
399         +1.0f,
400         -1.0f,
401         +1.0f,
402         +1.0f,
403         -1.0f,
404         +1.0f,
405 
406         // half viewport quad centred
407         -0.5f,
408         -0.5f,
409         +0.5f,
410         -0.5f,
411         +0.5f,
412         +0.5f,
413         -0.5f,
414         +0.5f,
415     };
416 
417     const GLushort indices[] = {
418         0, 1, 2, 2, 3, 0,
419     };
420 
421     const GLfloat colors[] = {
422         0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
423 
424         0.0f, 0.0f, 1.0f, 1.0f, // blue
425         0.0f, 0.0f, 1.0f, 1.0f, // blue
426         0.0f, 0.0f, 1.0f, 1.0f, // blue
427         0.0f, 0.0f, 1.0f, 1.0f, // blue
428     };
429 
430     GLU_CHECK_GLW_CALL(m_gl, viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT));
431     GLU_CHECK_GLW_CALL(m_gl, clearColor(1.0f, 1.0f, 1.0f, 1.0f)); // white
432     GLU_CHECK_GLW_CALL(m_gl, clear(GL_COLOR_BUFFER_BIT));
433 
434     GLU_CHECK_GLW_CALL(m_gl, uniform4fv(colorLocation, DE_LENGTH_OF_ARRAY(colors), &colors[0]));
435 
436     GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ARRAY_BUFFER, m_coordinatesBuffer));
437     GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW));
438 
439     if (m_vao)
440         GLU_CHECK_GLW_CALL(m_gl, bindVertexArray(m_vao));
441     GLU_CHECK_GLW_CALL(m_gl, enableVertexAttribArray(coordLocation));
442     GLU_CHECK_GLW_CALL(m_gl, vertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL));
443 
444     if (m_iterNdx == 0)
445     {
446         tcu::ScopedLogSection logSection(m_testCtx.getLog(), "Iter0", "Indices in client-side array");
447         draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, (GLvoid *)indices, baseVertex);
448     }
449 
450     if (m_iterNdx == 1)
451     {
452         tcu::ScopedLogSection logSection(m_testCtx.getLog(), "Iter1", "Indices in element array buffer");
453         GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementsBuffer));
454         GLU_CHECK_GLW_CALL(
455             m_gl, bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0], GL_STATIC_DRAW));
456         draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, DE_NULL, baseVertex);
457     }
458 
459     glu::readPixels(m_context.getRenderContext(), 0, 0, surface.getAccess());
460     verifyImage(surface);
461 
462     m_iterNdx += 1;
463 
464     return (m_iterNdx < 2) ? CONTINUE : STOP;
465 }
466 
467 class BuiltInVariableGroup : public TestCaseGroup
468 {
469 public:
470     BuiltInVariableGroup(Context &context, const char *name, const char *descr,
471                          gls::DrawTestSpec::DrawMethod drawMethod);
472     ~BuiltInVariableGroup(void);
473 
474     void init(void);
475 
476 private:
477     gls::DrawTestSpec::DrawMethod m_method;
478 };
479 
BuiltInVariableGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)480 BuiltInVariableGroup::BuiltInVariableGroup(Context &context, const char *name, const char *descr,
481                                            gls::DrawTestSpec::DrawMethod drawMethod)
482     : TestCaseGroup(context, name, descr)
483     , m_method(drawMethod)
484 {
485 }
486 
~BuiltInVariableGroup(void)487 BuiltInVariableGroup::~BuiltInVariableGroup(void)
488 {
489 }
490 
init(void)491 void BuiltInVariableGroup::init(void)
492 {
493     addChild(new VertexIDCase(m_context, m_method));
494 }
495 
496 class IndexGroup : public TestCaseGroup
497 {
498 public:
499     IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
500     ~IndexGroup(void);
501 
502     void init(void);
503 
504 private:
505     gls::DrawTestSpec::DrawMethod m_method;
506 };
507 
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)508 IndexGroup::IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod)
509     : TestCaseGroup(context, name, descr)
510     , m_method(drawMethod)
511 {
512 }
513 
~IndexGroup(void)514 IndexGroup::~IndexGroup(void)
515 {
516 }
517 
init(void)518 void IndexGroup::init(void)
519 {
520     struct IndexTest
521     {
522         gls::DrawTestSpec::IndexType type;
523         int offsets[3];
524     };
525 
526     const IndexTest tests[] = {
527         {gls::DrawTestSpec::INDEXTYPE_BYTE, {0, 1, -1}},
528         {gls::DrawTestSpec::INDEXTYPE_SHORT, {0, 2, -1}},
529         {gls::DrawTestSpec::INDEXTYPE_INT, {0, 4, -1}},
530     };
531 
532     gls::DrawTestSpec spec;
533     glu::ContextType contextType = m_context.getRenderContext().getType();
534     genBasicSpec(spec, contextType, m_method);
535 
536     spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
537 
538     for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
539     {
540         const IndexTest &indexTest = tests[testNdx];
541 
542         const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
543         const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
544         gls::DrawTest *test    = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
545 
546         spec.indexType = indexTest.type;
547 
548         for (int iterationNdx = 0;
549              iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1;
550              ++iterationNdx)
551         {
552             const std::string iterationDesc =
553                 std::string("first vertex ") +
554                 de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type));
555             spec.indexPointerOffset = indexTest.offsets[iterationNdx];
556             test->addIteration(spec, iterationDesc.c_str());
557         }
558 
559         addChild(test);
560     }
561 }
562 
563 class BaseVertexGroup : public TestCaseGroup
564 {
565 public:
566     BaseVertexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
567     ~BaseVertexGroup(void);
568 
569     void init(void);
570 
571 private:
572     gls::DrawTestSpec::DrawMethod m_method;
573 };
574 
BaseVertexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)575 BaseVertexGroup::BaseVertexGroup(Context &context, const char *name, const char *descr,
576                                  gls::DrawTestSpec::DrawMethod drawMethod)
577     : TestCaseGroup(context, name, descr)
578     , m_method(drawMethod)
579 {
580 }
581 
~BaseVertexGroup(void)582 BaseVertexGroup::~BaseVertexGroup(void)
583 {
584 }
585 
init(void)586 void BaseVertexGroup::init(void)
587 {
588     struct IndexTest
589     {
590         bool positiveBase;
591         gls::DrawTestSpec::IndexType type;
592         int baseVertex[2];
593     };
594 
595     const IndexTest tests[] = {
596         {true, gls::DrawTestSpec::INDEXTYPE_BYTE, {1, 2}},     {true, gls::DrawTestSpec::INDEXTYPE_SHORT, {1, 2}},
597         {true, gls::DrawTestSpec::INDEXTYPE_INT, {1, 2}},      {false, gls::DrawTestSpec::INDEXTYPE_BYTE, {-1, -2}},
598         {false, gls::DrawTestSpec::INDEXTYPE_SHORT, {-1, -2}}, {false, gls::DrawTestSpec::INDEXTYPE_INT, {-1, -2}},
599     };
600 
601     gls::DrawTestSpec spec;
602     glu::ContextType contextType = m_context.getRenderContext().getType();
603     genBasicSpec(spec, contextType, m_method);
604 
605     spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
606 
607     for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
608     {
609         const IndexTest &indexTest = tests[testNdx];
610 
611         const std::string name = std::string("index_") + (indexTest.positiveBase ? "" : "neg_") +
612                                  gls::DrawTestSpec::indexTypeToString(indexTest.type);
613         const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
614         gls::DrawTest *test    = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
615 
616         spec.indexType = indexTest.type;
617 
618         for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx)
619         {
620             const std::string iterationDesc =
621                 std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]);
622             spec.baseVertex = indexTest.baseVertex[iterationNdx];
623             // spec.indexMin + spec.baseVertex can not be a negative value
624             if (spec.indexMin + spec.baseVertex < 0)
625             {
626                 spec.indexMax -= (spec.indexMin + spec.baseVertex);
627                 spec.indexMin -= (spec.indexMin + spec.baseVertex);
628             }
629             test->addIteration(spec, iterationDesc.c_str());
630         }
631 
632         addChild(test);
633     }
634 }
635 
636 class AttributeGroup : public TestCaseGroup
637 {
638 public:
639     AttributeGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod,
640                    gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType,
641                    gls::DrawTestSpec::Storage indexStorage);
642     ~AttributeGroup(void);
643 
644     void init(void);
645 
646 private:
647     gls::DrawTestSpec::DrawMethod m_method;
648     gls::DrawTestSpec::Primitive m_primitive;
649     gls::DrawTestSpec::IndexType m_indexType;
650     gls::DrawTestSpec::Storage m_indexStorage;
651 };
652 
AttributeGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod,gls::DrawTestSpec::Primitive primitive,gls::DrawTestSpec::IndexType indexType,gls::DrawTestSpec::Storage indexStorage)653 AttributeGroup::AttributeGroup(Context &context, const char *name, const char *descr,
654                                gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive,
655                                gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage)
656     : TestCaseGroup(context, name, descr)
657     , m_method(drawMethod)
658     , m_primitive(primitive)
659     , m_indexType(indexType)
660     , m_indexStorage(indexStorage)
661 {
662 }
663 
~AttributeGroup(void)664 AttributeGroup::~AttributeGroup(void)
665 {
666 }
667 
init(void)668 void AttributeGroup::init(void)
669 {
670     // Single attribute
671     {
672         gls::DrawTest *test =
673             new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
674         gls::DrawTestSpec spec;
675         glu::ContextType contextType = m_context.getRenderContext().getType();
676 
677         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
678         spec.primitive          = m_primitive;
679         spec.primitiveCount     = 5;
680         spec.drawMethod         = m_method;
681         spec.indexType          = m_indexType;
682         spec.indexPointerOffset = 0;
683         spec.indexStorage       = m_indexStorage;
684         spec.first              = 0;
685         spec.indexMin           = 0;
686         spec.indexMax           = 0;
687         spec.instanceCount      = 1;
688         spec.indirectOffset     = 0;
689 
690         spec.attribs.resize(1);
691 
692         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
693         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
694         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
695         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
696         spec.attribs[0].componentCount      = 2;
697         spec.attribs[0].offset              = 0;
698         spec.attribs[0].stride              = 0;
699         spec.attribs[0].normalize           = false;
700         spec.attribs[0].instanceDivisor     = 0;
701         spec.attribs[0].useDefaultAttribute = false;
702 
703         addTestIterations(test, spec, TYPE_DRAW_COUNT);
704 
705         this->addChild(test);
706     }
707 
708     // Multiple attribute
709     {
710         gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes",
711                                                 "Multiple attribute arrays.");
712         gls::DrawTestSpec spec;
713         glu::ContextType contextType = m_context.getRenderContext().getType();
714 
715         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
716         spec.primitive          = m_primitive;
717         spec.primitiveCount     = 5;
718         spec.drawMethod         = m_method;
719         spec.indexType          = m_indexType;
720         spec.indexPointerOffset = 0;
721         spec.indexStorage       = m_indexStorage;
722         spec.first              = 0;
723         spec.indexMin           = 0;
724         spec.indexMax           = 0;
725         spec.instanceCount      = 1;
726         spec.indirectOffset     = 0;
727 
728         spec.attribs.resize(2);
729 
730         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
731         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
732         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
733         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
734         spec.attribs[0].componentCount      = 4;
735         spec.attribs[0].offset              = 0;
736         spec.attribs[0].stride              = 0;
737         spec.attribs[0].normalize           = false;
738         spec.attribs[0].instanceDivisor     = 0;
739         spec.attribs[0].useDefaultAttribute = false;
740 
741         spec.attribs[1].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
742         spec.attribs[1].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
743         spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
744         spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
745         spec.attribs[1].componentCount      = 2;
746         spec.attribs[1].offset              = 0;
747         spec.attribs[1].stride              = 0;
748         spec.attribs[1].normalize           = false;
749         spec.attribs[1].instanceDivisor     = 0;
750         spec.attribs[1].useDefaultAttribute = false;
751 
752         addTestIterations(test, spec, TYPE_DRAW_COUNT);
753 
754         this->addChild(test);
755     }
756 
757     // Multiple attribute, second one divided
758     {
759         gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes",
760                                                 "Instanced attribute array.");
761         gls::DrawTestSpec spec;
762         glu::ContextType contextType = m_context.getRenderContext().getType();
763 
764         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
765         spec.primitive          = m_primitive;
766         spec.primitiveCount     = 5;
767         spec.drawMethod         = m_method;
768         spec.indexType          = m_indexType;
769         spec.indexPointerOffset = 0;
770         spec.indexStorage       = m_indexStorage;
771         spec.first              = 0;
772         spec.indexMin           = 0;
773         spec.indexMax           = 0;
774         spec.instanceCount      = 1;
775         spec.indirectOffset     = 0;
776 
777         spec.attribs.resize(3);
778 
779         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
780         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
781         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
782         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
783         spec.attribs[0].componentCount      = 4;
784         spec.attribs[0].offset              = 0;
785         spec.attribs[0].stride              = 0;
786         spec.attribs[0].normalize           = false;
787         spec.attribs[0].instanceDivisor     = 0;
788         spec.attribs[0].useDefaultAttribute = false;
789 
790         // Add another position component so the instances wont be drawn on each other
791         spec.attribs[1].inputType                   = gls::DrawTestSpec::INPUTTYPE_FLOAT;
792         spec.attribs[1].outputType                  = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
793         spec.attribs[1].storage                     = gls::DrawTestSpec::STORAGE_BUFFER;
794         spec.attribs[1].usage                       = gls::DrawTestSpec::USAGE_STATIC_DRAW;
795         spec.attribs[1].componentCount              = 2;
796         spec.attribs[1].offset                      = 0;
797         spec.attribs[1].stride                      = 0;
798         spec.attribs[1].normalize                   = false;
799         spec.attribs[1].instanceDivisor             = 1;
800         spec.attribs[1].useDefaultAttribute         = false;
801         spec.attribs[1].additionalPositionAttribute = true;
802 
803         // Instanced color
804         spec.attribs[2].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
805         spec.attribs[2].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
806         spec.attribs[2].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
807         spec.attribs[2].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
808         spec.attribs[2].componentCount      = 3;
809         spec.attribs[2].offset              = 0;
810         spec.attribs[2].stride              = 0;
811         spec.attribs[2].normalize           = false;
812         spec.attribs[2].instanceDivisor     = 1;
813         spec.attribs[2].useDefaultAttribute = false;
814 
815         addTestIterations(test, spec, TYPE_INSTANCE_COUNT);
816 
817         this->addChild(test);
818     }
819 
820     // Multiple attribute, second one default
821     {
822         gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute",
823                                                 "Attribute specified with glVertexAttrib*.");
824         gls::DrawTestSpec spec;
825         glu::ContextType contextType = m_context.getRenderContext().getType();
826 
827         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
828         spec.primitive          = m_primitive;
829         spec.primitiveCount     = 5;
830         spec.drawMethod         = m_method;
831         spec.indexType          = m_indexType;
832         spec.indexPointerOffset = 0;
833         spec.indexStorage       = m_indexStorage;
834         spec.first              = 0;
835         spec.indexMin           = 0;
836         spec.indexMax           = 0;
837         spec.instanceCount      = 1;
838         spec.indirectOffset     = 0;
839 
840         spec.attribs.resize(2);
841 
842         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
843         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
844         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
845         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
846         spec.attribs[0].componentCount      = 2;
847         spec.attribs[0].offset              = 0;
848         spec.attribs[0].stride              = 0;
849         spec.attribs[0].normalize           = false;
850         spec.attribs[0].instanceDivisor     = 0;
851         spec.attribs[0].useDefaultAttribute = false;
852 
853         struct IOPair
854         {
855             gls::DrawTestSpec::InputType input;
856             gls::DrawTestSpec::OutputType output;
857             int componentCount;
858         } iopairs[] = {
859             {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, 4},
860             {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2},
861             {gls::DrawTestSpec::INPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4},
862             {gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4},
863         };
864 
865         for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
866         {
867             const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) +
868                                      de::toString(iopairs[ioNdx].componentCount) + " to " +
869                                      gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
870 
871             spec.attribs[1].inputType           = iopairs[ioNdx].input;
872             spec.attribs[1].outputType          = iopairs[ioNdx].output;
873             spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
874             spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
875             spec.attribs[1].componentCount      = iopairs[ioNdx].componentCount;
876             spec.attribs[1].offset              = 0;
877             spec.attribs[1].stride              = 0;
878             spec.attribs[1].normalize           = false;
879             spec.attribs[1].instanceDivisor     = 0;
880             spec.attribs[1].useDefaultAttribute = true;
881 
882             test->addIteration(spec, desc.c_str());
883         }
884 
885         this->addChild(test);
886     }
887 }
888 
889 class MethodGroup : public TestCaseGroup
890 {
891 public:
892     MethodGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
893     ~MethodGroup(void);
894 
895     void init(void);
896 
897 private:
898     gls::DrawTestSpec::DrawMethod m_method;
899 };
900 
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)901 MethodGroup::MethodGroup(Context &context, const char *name, const char *descr,
902                          gls::DrawTestSpec::DrawMethod drawMethod)
903     : TestCaseGroup(context, name, descr)
904     , m_method(drawMethod)
905 {
906 }
907 
~MethodGroup(void)908 MethodGroup::~MethodGroup(void)
909 {
910 }
911 
init(void)912 void MethodGroup::init(void)
913 {
914     const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) ||
915                          (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) ||
916                          (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX);
917 
918     const gls::DrawTestSpec::Primitive primitive[] = {
919         gls::DrawTestSpec::PRIMITIVE_POINTS,       gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
920         gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
921         gls::DrawTestSpec::PRIMITIVE_LINES,        gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
922         gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
923 
924     if (indexed)
925     {
926         // Index-tests
927         this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
928         this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method));
929         this->addChild(
930             new BuiltInVariableGroup(m_context, "builtin_variable", "Built in shader variable tests", m_method));
931     }
932 
933     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
934     {
935         const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
936         const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
937 
938         this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx],
939                                           gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
940     }
941 }
942 
943 } // namespace
944 
DrawElementsBaseVertexTests(Context & context)945 DrawElementsBaseVertexTests::DrawElementsBaseVertexTests(Context &context)
946     : TestCaseGroup(context, "draw_base_vertex", "Base vertex extension drawing tests")
947 {
948 }
949 
~DrawElementsBaseVertexTests(void)950 DrawElementsBaseVertexTests::~DrawElementsBaseVertexTests(void)
951 {
952 }
953 
init(void)954 void DrawElementsBaseVertexTests::init(void)
955 {
956     const gls::DrawTestSpec::DrawMethod basicMethods[] = {
957         gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
958         gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
959         gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
960     };
961 
962     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
963     {
964         const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
965         const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
966 
967         this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
968     }
969 }
970 
971 } // namespace Functional
972 } // namespace gles31
973 } // namespace deqp
974