xref: /aosp_15_r20/external/deqp/modules/gles31/stress/es31sDrawTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 
2 /*-------------------------------------------------------------------------
3  * drawElements Quality Program OpenGL ES 3.1 Module
4  * -------------------------------------------------
5  *
6  * Copyright 2014 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Drawing stress tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "es31sDrawTests.hpp"
26 #include "glsDrawTest.hpp"
27 #include "gluRenderContext.hpp"
28 #include "gluCallLogWrapper.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "deRandom.hpp"
33 #include "deStringUtil.hpp"
34 #include "deUniquePtr.hpp"
35 
36 #include <set>
37 
38 namespace deqp
39 {
40 namespace gles31
41 {
42 namespace Stress
43 {
44 namespace
45 {
46 
47 static const char *s_colorVertexShaderSource   = "#version 310 es\n"
48                                                  "in highp vec4 a_position;\n"
49                                                  "in highp vec4 a_color;\n"
50                                                  "out highp vec4 v_color;\n"
51                                                  "void main (void)\n"
52                                                  "{\n"
53                                                  "    gl_Position = a_position;\n"
54                                                  "    v_color = a_color;\n"
55                                                  "}\n";
56 static const char *s_colorFragmentShaderSource = "#version 310 es\n"
57                                                  "layout(location = 0) out highp vec4 fragColor;\n"
58                                                  "in highp vec4 v_color;\n"
59                                                  "void main (void)\n"
60                                                  "{\n"
61                                                  "    fragColor = v_color;\n"
62                                                  "}\n";
63 struct DrawElementsCommand
64 {
65     uint32_t count;
66     uint32_t primCount;
67     uint32_t firstIndex;
68     int32_t baseVertex;
69     uint32_t reservedMustBeZero;
70 };
71 DE_STATIC_ASSERT(5 * sizeof(uint32_t) == sizeof(DrawElementsCommand)); // tight packing
72 
73 struct DrawArraysCommand
74 {
75     uint32_t count;
76     uint32_t primCount;
77     uint32_t first;
78     uint32_t reservedMustBeZero;
79 };
80 DE_STATIC_ASSERT(4 * sizeof(uint32_t) == sizeof(DrawArraysCommand)); // tight packing
81 
82 class InvalidDrawCase : public TestCase
83 {
84 public:
85     enum DrawType
86     {
87         DRAW_ARRAYS,
88         DRAW_ELEMENTS,
89 
90         DRAW_LAST
91     };
92     enum InvalidOperation
93     {
94         INVALID_DATA_COUNT = 0,
95         INVALID_DATA_FIRST,
96         INVALID_DATA_INSTANCED,
97         INVALID_INDEX_COUNT,
98         INVALID_INDEX_FIRST,
99         INVALID_RESERVED,
100         INVALID_INDEX,
101 
102         INVALID_LAST
103     };
104 
105     InvalidDrawCase(Context &context, const char *name, const char *desc, DrawType type, InvalidOperation op);
106     ~InvalidDrawCase(void);
107 
108     void init(void);
109     void deinit(void);
110     IterateResult iterate(void);
111 
112 private:
113     const DrawType m_drawType;
114     const InvalidOperation m_op;
115     glw::GLuint m_dataBufferID;
116     glw::GLuint m_indexBufferID;
117     glw::GLuint m_cmdBufferID;
118     glw::GLuint m_colorBufferID;
119     glw::GLuint m_vao;
120 };
121 
InvalidDrawCase(Context & context,const char * name,const char * desc,DrawType type,InvalidOperation op)122 InvalidDrawCase::InvalidDrawCase(Context &context, const char *name, const char *desc, DrawType type,
123                                  InvalidOperation op)
124     : TestCase(context, name, desc)
125     , m_drawType(type)
126     , m_op(op)
127     , m_dataBufferID(0)
128     , m_indexBufferID(0)
129     , m_cmdBufferID(0)
130     , m_colorBufferID(0)
131     , m_vao(0)
132 {
133     DE_ASSERT(type < DRAW_LAST);
134     DE_ASSERT(op < INVALID_LAST);
135 }
136 
~InvalidDrawCase(void)137 InvalidDrawCase::~InvalidDrawCase(void)
138 {
139     deinit();
140 }
141 
init(void)142 void InvalidDrawCase::init(void)
143 {
144 }
145 
deinit(void)146 void InvalidDrawCase::deinit(void)
147 {
148     if (m_dataBufferID)
149     {
150         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBufferID);
151         m_dataBufferID = 0;
152     }
153     if (m_indexBufferID)
154     {
155         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID);
156         m_indexBufferID = 0;
157     }
158     if (m_cmdBufferID)
159     {
160         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_cmdBufferID);
161         m_cmdBufferID = 0;
162     }
163     if (m_colorBufferID)
164     {
165         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorBufferID);
166         m_colorBufferID = 0;
167     }
168     if (m_vao)
169     {
170         m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
171         m_vao = 0;
172     }
173 }
174 
iterate(void)175 InvalidDrawCase::IterateResult InvalidDrawCase::iterate(void)
176 {
177     const int drawCount          = 10;    //!< number of elements safe to draw (all buffers have this)
178     const int overBoundDrawCount = 10000; //!< number of elements in all other buffers than our target buffer
179     const int drawInstances      = 1;
180     const int overBoundInstances = 1000;
181 
182     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
183     glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
184                                                                  << glu::VertexSource(s_colorVertexShaderSource)
185                                                                  << glu::FragmentSource(s_colorFragmentShaderSource));
186     const uint32_t programID    = program.getProgram();
187     const int32_t posLocation   = gl.glGetAttribLocation(programID, "a_position");
188     const int32_t colorLocation = gl.glGetAttribLocation(programID, "a_color");
189 
190     gl.enableLogging(true);
191 
192     gl.glGenVertexArrays(1, &m_vao);
193     gl.glBindVertexArray(m_vao);
194     glu::checkError(gl.glGetError(), "gen vao", __FILE__, __LINE__);
195 
196     // indices
197     if (m_drawType == DRAW_ELEMENTS)
198     {
199         const int indexBufferSize = (m_op == INVALID_INDEX_COUNT) ? (drawCount) : (overBoundDrawCount);
200         std::vector<uint16_t> indices(indexBufferSize);
201 
202         for (int ndx = 0; ndx < (int)indices.size(); ++ndx)
203             indices[ndx] = (uint16_t)((m_op == INVALID_INDEX) ? (overBoundDrawCount + ndx) : (ndx));
204 
205         gl.glGenBuffers(1, &m_indexBufferID);
206         gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
207         gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size() * sizeof(uint16_t)), &indices[0], GL_STATIC_DRAW);
208         glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
209     }
210 
211     // data
212     {
213         const int dataSize = (m_op == INVALID_DATA_COUNT) ? (drawCount) : (overBoundDrawCount);
214 
215         // any data is ok
216         gl.glGenBuffers(1, &m_dataBufferID);
217         gl.glBindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
218         gl.glBufferData(GL_ARRAY_BUFFER, dataSize * sizeof(float[4]), DE_NULL, GL_STATIC_DRAW);
219         gl.glVertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
220         gl.glEnableVertexAttribArray(posLocation);
221         glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
222     }
223 
224     // potentially instanced data
225     {
226         const int dataSize = drawInstances;
227 
228         gl.glGenBuffers(1, &m_colorBufferID);
229         gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorBufferID);
230         gl.glBufferData(GL_ARRAY_BUFFER, dataSize * sizeof(float[4]), DE_NULL, GL_STATIC_DRAW);
231         gl.glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
232         gl.glEnableVertexAttribArray(colorLocation);
233         gl.glVertexAttribDivisor(colorLocation, 1);
234         glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
235     }
236 
237     // command
238     if (m_drawType == DRAW_ARRAYS)
239     {
240         DrawArraysCommand drawCommand;
241         drawCommand.count              = overBoundDrawCount;
242         drawCommand.primCount          = (m_op == INVALID_DATA_INSTANCED) ? (overBoundInstances) : (drawInstances);
243         drawCommand.first              = (m_op == INVALID_DATA_FIRST) ? (overBoundDrawCount) : (0);
244         drawCommand.reservedMustBeZero = (m_op == INVALID_RESERVED) ? (5) : (0);
245 
246         m_testCtx.getLog() << tcu::TestLog::Message << "drawCommand:"
247                            << "\n\tcount:\t" << drawCommand.count << "\n\tprimCount\t" << drawCommand.primCount
248                            << "\n\tfirst\t" << drawCommand.first << "\n\treservedMustBeZero\t"
249                            << drawCommand.reservedMustBeZero << tcu::TestLog::EndMessage;
250 
251         gl.glGenBuffers(1, &m_cmdBufferID);
252         gl.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
253         gl.glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
254         glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
255     }
256     else if (m_drawType == DRAW_ELEMENTS)
257     {
258         DrawElementsCommand drawCommand;
259         drawCommand.count              = overBoundDrawCount;
260         drawCommand.primCount          = (m_op == INVALID_DATA_INSTANCED) ? (overBoundInstances) : (drawInstances);
261         drawCommand.firstIndex         = (m_op == INVALID_INDEX_FIRST) ? (overBoundDrawCount) : (0);
262         drawCommand.baseVertex         = (m_op == INVALID_DATA_FIRST) ? (overBoundDrawCount) : (0);
263         drawCommand.reservedMustBeZero = (m_op == INVALID_RESERVED) ? (5) : (0);
264 
265         m_testCtx.getLog() << tcu::TestLog::Message << "drawCommand:"
266                            << "\n\tcount:\t" << drawCommand.count << "\n\tprimCount\t" << drawCommand.primCount
267                            << "\n\tfirstIndex\t" << drawCommand.firstIndex << "\n\tbaseVertex\t"
268                            << drawCommand.baseVertex << "\n\treservedMustBeZero\t" << drawCommand.reservedMustBeZero
269                            << tcu::TestLog::EndMessage;
270 
271         gl.glGenBuffers(1, &m_cmdBufferID);
272         gl.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
273         gl.glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
274         glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
275     }
276     else
277         DE_ASSERT(false);
278 
279     gl.glViewport(0, 0, 1, 1);
280     gl.glUseProgram(programID);
281 
282     if (m_drawType == DRAW_ELEMENTS)
283         gl.glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, DE_NULL);
284     else if (m_drawType == DRAW_ARRAYS)
285         gl.glDrawArraysIndirect(GL_TRIANGLES, DE_NULL);
286     else
287         DE_ASSERT(false);
288 
289     gl.glUseProgram(0);
290     gl.glFinish();
291 
292     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
293     return STOP;
294 }
295 
296 class RandomGroup : public TestCaseGroup
297 {
298 public:
299     RandomGroup(Context &context, const char *name, const char *descr);
300     ~RandomGroup(void);
301 
302     void init(void);
303 };
304 
305 template <int SIZE>
306 struct UniformWeightArray
307 {
308     float weights[SIZE];
309 
UniformWeightArraydeqp::gles31::Stress::__anon9c7365ba0111::UniformWeightArray310     UniformWeightArray(void)
311     {
312         for (int i = 0; i < SIZE; ++i)
313             weights[i] = 1.0f;
314     }
315 };
316 
RandomGroup(Context & context,const char * name,const char * descr)317 RandomGroup::RandomGroup(Context &context, const char *name, const char *descr) : TestCaseGroup(context, name, descr)
318 {
319 }
320 
~RandomGroup(void)321 RandomGroup::~RandomGroup(void)
322 {
323 }
324 
init(void)325 void RandomGroup::init(void)
326 {
327     const int numAttempts = 100;
328 
329     const int attribCounts[]            = {1, 2, 5};
330     const float attribWeights[]         = {30, 10, 1};
331     const int primitiveCounts[]         = {1, 5, 64};
332     const float primitiveCountWeights[] = {20, 10, 1};
333     const int indexOffsets[]            = {0, 7, 13};
334     const float indexOffsetWeights[]    = {20, 20, 1};
335     const int firsts[]                  = {0, 7, 13};
336     const float firstWeights[]          = {20, 20, 1};
337 
338     const int instanceCounts[]           = {1, 2, 16, 17};
339     const float instanceWeights[]        = {20, 10, 5, 1};
340     const int indexMins[]                = {0, 1, 3, 8};
341     const int indexMaxs[]                = {4, 8, 128, 257};
342     const float indexWeights[]           = {50, 50, 50, 50};
343     const int offsets[]                  = {0, 1, 5, 12};
344     const float offsetWeights[]          = {50, 10, 10, 10};
345     const int strides[]                  = {0, 7, 16, 17};
346     const float strideWeights[]          = {50, 10, 10, 10};
347     const int instanceDivisors[]         = {0, 1, 3, 129};
348     const float instanceDivisorWeights[] = {70, 30, 10, 10};
349 
350     const int indirectOffsets[]         = {0, 1, 2};
351     const float indirectOffsetWeigths[] = {2, 1, 1};
352     const int baseVertices[]            = {0, 1, -2, 4, 3};
353     const float baseVertexWeigths[]     = {4, 1, 1, 1, 1};
354 
355     gls::DrawTestSpec::Primitive primitives[] = {
356         gls::DrawTestSpec::PRIMITIVE_POINTS,       gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
357         gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
358         gls::DrawTestSpec::PRIMITIVE_LINES,        gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
359         gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
360     const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
361 
362     gls::DrawTestSpec::DrawMethod drawMethods[] = {
363         gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
364         gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
365     };
366     const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
367 
368     gls::DrawTestSpec::IndexType indexTypes[] = {
369         gls::DrawTestSpec::INDEXTYPE_BYTE,
370         gls::DrawTestSpec::INDEXTYPE_SHORT,
371         gls::DrawTestSpec::INDEXTYPE_INT,
372     };
373     const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
374 
375     gls::DrawTestSpec::InputType inputTypes[] = {
376         gls::DrawTestSpec::INPUTTYPE_FLOAT,
377         gls::DrawTestSpec::INPUTTYPE_FIXED,
378         gls::DrawTestSpec::INPUTTYPE_BYTE,
379         gls::DrawTestSpec::INPUTTYPE_SHORT,
380         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
381         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
382         gls::DrawTestSpec::INPUTTYPE_INT,
383         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
384         gls::DrawTestSpec::INPUTTYPE_HALF,
385         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
386         gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
387     };
388     const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
389 
390     gls::DrawTestSpec::OutputType outputTypes[] = {
391         gls::DrawTestSpec::OUTPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2,  gls::DrawTestSpec::OUTPUTTYPE_VEC3,
392         gls::DrawTestSpec::OUTPUTTYPE_VEC4,  gls::DrawTestSpec::OUTPUTTYPE_INT,   gls::DrawTestSpec::OUTPUTTYPE_UINT,
393         gls::DrawTestSpec::OUTPUTTYPE_IVEC2, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
394         gls::DrawTestSpec::OUTPUTTYPE_UVEC2, gls::DrawTestSpec::OUTPUTTYPE_UVEC3, gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
395     };
396     const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
397 
398     gls::DrawTestSpec::Usage usages[] = {
399         gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, gls::DrawTestSpec::USAGE_STATIC_DRAW,
400         gls::DrawTestSpec::USAGE_STREAM_DRAW,  gls::DrawTestSpec::USAGE_STREAM_READ,
401         gls::DrawTestSpec::USAGE_STREAM_COPY,  gls::DrawTestSpec::USAGE_STATIC_READ,
402         gls::DrawTestSpec::USAGE_STATIC_COPY,  gls::DrawTestSpec::USAGE_DYNAMIC_READ,
403         gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
404     };
405     const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
406 
407     std::set<uint32_t> insertedHashes;
408     size_t insertedCount = 0;
409 
410     for (int ndx = 0; ndx < numAttempts; ++ndx)
411     {
412         de::Random random(0xc551393 + ndx); // random does not depend on previous cases
413 
414         int attributeCount = random.chooseWeighted<int, const int *, const float *>(
415             DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
416         int drawCommandSize;
417         gls::DrawTestSpec spec;
418 
419         spec.apiType   = glu::ApiType::es(3, 1);
420         spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive>(
421             DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights);
422         spec.primitiveCount = random.chooseWeighted<int, const int *, const float *>(
423             DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights);
424         spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod>(
425             DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights);
426 
427         if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
428             drawCommandSize = sizeof(uint32_t[4]);
429         else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
430             drawCommandSize = sizeof(uint32_t[5]);
431         else
432         {
433             DE_ASSERT(false);
434             return;
435         }
436 
437         spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType>(
438             DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights);
439         spec.indexPointerOffset = random.chooseWeighted<int, const int *, const float *>(
440             DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights);
441         spec.indexStorage  = gls::DrawTestSpec::STORAGE_BUFFER;
442         spec.first         = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(firsts),
443                                                                             DE_ARRAY_END(firsts), firstWeights);
444         spec.indexMin      = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMins),
445                                                                                DE_ARRAY_END(indexMins), indexWeights);
446         spec.indexMax      = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMaxs),
447                                                                                DE_ARRAY_END(indexMaxs), indexWeights);
448         spec.instanceCount = random.chooseWeighted<int, const int *, const float *>(
449             DE_ARRAY_BEGIN(instanceCounts), DE_ARRAY_END(instanceCounts), instanceWeights);
450         spec.indirectOffset = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indirectOffsets),
451                                                                                      DE_ARRAY_END(indirectOffsets),
452                                                                                      indirectOffsetWeigths) *
453                               drawCommandSize;
454         spec.baseVertex = random.chooseWeighted<int, const int *, const float *>(
455             DE_ARRAY_BEGIN(baseVertices), DE_ARRAY_END(baseVertices), baseVertexWeigths);
456 
457         // check spec is legal
458         if (!spec.valid())
459             continue;
460 
461         for (int attrNdx = 0; attrNdx < attributeCount;)
462         {
463             bool valid;
464             gls::DrawTestSpec::AttributeSpec attribSpec;
465 
466             attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType>(
467                 DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights);
468             attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType>(
469                 DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights);
470             attribSpec.storage = gls::DrawTestSpec::STORAGE_BUFFER;
471             attribSpec.usage   = random.chooseWeighted<gls::DrawTestSpec::Usage>(
472                 DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights);
473             attribSpec.componentCount = random.getInt(1, 4);
474             attribSpec.offset         = random.chooseWeighted<int, const int *, const float *>(
475                 DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
476             attribSpec.stride = random.chooseWeighted<int, const int *, const float *>(
477                 DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
478             attribSpec.normalize       = random.getBool();
479             attribSpec.instanceDivisor = random.chooseWeighted<int, const int *, const float *>(
480                 DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
481             attribSpec.useDefaultAttribute = random.getBool();
482 
483             // check spec is legal
484             valid = attribSpec.valid(spec.apiType);
485 
486             // we do not want interleaved elements. (Might result in some weird floating point values)
487             if (attribSpec.stride &&
488                 attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
489                 valid = false;
490 
491             // try again if not valid
492             if (valid)
493             {
494                 spec.attribs.push_back(attribSpec);
495                 ++attrNdx;
496             }
497         }
498 
499         // Do not collapse all vertex positions to a single positions
500         if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
501             spec.attribs[0].instanceDivisor = 0;
502 
503         // Is render result meaningful?
504         {
505             // Only one vertex
506             if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
507                 spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
508                 continue;
509             if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
510                 continue;
511 
512             // Triangle only on one axis
513             if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES ||
514                 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN ||
515                 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
516             {
517                 if (spec.attribs[0].componentCount == 1)
518                     continue;
519                 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT ||
520                     spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT ||
521                     spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT)
522                     continue;
523                 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
524                     (spec.indexMax - spec.indexMin) < 2)
525                     continue;
526             }
527         }
528 
529         // Add case
530         {
531             uint32_t hash = spec.hash();
532             for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
533                 hash = (hash << 2) ^ (uint32_t)spec.attribs[attrNdx].hash();
534 
535             if (insertedHashes.find(hash) == insertedHashes.end())
536             {
537                 // Only unaligned cases
538                 if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
539                     spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
540                     this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec,
541                                                      de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
542                 insertedHashes.insert(hash);
543 
544                 ++insertedCount;
545             }
546         }
547     }
548 }
549 
550 } // namespace
551 
DrawTests(Context & context)552 DrawTests::DrawTests(Context &context) : TestCaseGroup(context, "draw_indirect", "Indirect drawing tests")
553 {
554 }
555 
~DrawTests(void)556 DrawTests::~DrawTests(void)
557 {
558 }
559 
init(void)560 void DrawTests::init(void)
561 {
562     tcu::TestCaseGroup *const unalignedGroup =
563         new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data");
564     tcu::TestCaseGroup *const drawArraysGroup   = new tcu::TestCaseGroup(m_testCtx, "drawarrays", "draw arrays");
565     tcu::TestCaseGroup *const drawElementsGroup = new tcu::TestCaseGroup(m_testCtx, "drawelements", "draw elements");
566 
567     addChild(unalignedGroup);
568     addChild(drawArraysGroup);
569     addChild(drawElementsGroup);
570 
571     // .unaligned_data
572     {
573         unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands."));
574     }
575 
576     // .drawarrays
577     {
578         drawArraysGroup->addChild(new InvalidDrawCase(
579             m_context, "data_over_bounds_with_count", "Draw arrays vertex elements beyond the array end are accessed",
580             InvalidDrawCase::DRAW_ARRAYS, InvalidDrawCase::INVALID_DATA_COUNT));
581         drawArraysGroup->addChild(new InvalidDrawCase(
582             m_context, "data_over_bounds_with_first", "Draw arrays vertex elements beyond the array end are accessed",
583             InvalidDrawCase::DRAW_ARRAYS, InvalidDrawCase::INVALID_DATA_FIRST));
584         drawArraysGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_primcount",
585                                                       "Draw arrays vertex elements beyond the array end are accessed",
586                                                       InvalidDrawCase::DRAW_ARRAYS,
587                                                       InvalidDrawCase::INVALID_DATA_INSTANCED));
588         drawArraysGroup->addChild(new InvalidDrawCase(m_context, "reserved_non_zero",
589                                                       "reservedMustBeZero is set to non-zero value",
590                                                       InvalidDrawCase::DRAW_ARRAYS, InvalidDrawCase::INVALID_RESERVED));
591     }
592 
593     // .drawelements
594     {
595         drawElementsGroup->addChild(new InvalidDrawCase(
596             m_context, "data_over_bounds_with_count", "Draw elements vertex elements beyond the array end are accessed",
597             InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_DATA_COUNT));
598         drawElementsGroup->addChild(
599             new InvalidDrawCase(m_context, "data_over_bounds_with_basevertex",
600                                 "Draw elements vertex elements beyond the array end are accessed",
601                                 InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_DATA_FIRST));
602         drawElementsGroup->addChild(
603             new InvalidDrawCase(m_context, "data_over_bounds_with_indices",
604                                 "Draw elements vertex elements beyond the array end are accessed",
605                                 InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_INDEX));
606         drawElementsGroup->addChild(
607             new InvalidDrawCase(m_context, "data_over_bounds_with_primcount",
608                                 "Draw elements vertex elements beyond the array end are accessed",
609                                 InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_DATA_INSTANCED));
610         drawElementsGroup->addChild(new InvalidDrawCase(
611             m_context, "index_over_bounds_with_count", "Draw elements index elements beyond the array end are accessed",
612             InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_INDEX_COUNT));
613         drawElementsGroup->addChild(
614             new InvalidDrawCase(m_context, "index_over_bounds_with_firstindex",
615                                 "Draw elements index elements beyond the array end are accessed",
616                                 InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_INDEX_FIRST));
617         drawElementsGroup->addChild(
618             new InvalidDrawCase(m_context, "reserved_non_zero", "reservedMustBeZero is set to non-zero value",
619                                 InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_RESERVED));
620     }
621 }
622 
623 } // namespace Stress
624 } // namespace gles31
625 } // namespace deqp
626