xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fDrawTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Drawing tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fDrawTests.hpp"
25 #include "deRandom.hpp"
26 #include "deStringUtil.hpp"
27 #include "deMemory.h"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuVectorUtil.hpp"
30 #include "sglrGLContext.hpp"
31 #include "glsDrawTest.hpp"
32 #include "gluStrUtil.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluCallLogWrapper.hpp"
35 
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 
39 #include <set>
40 
41 namespace deqp
42 {
43 namespace gles31
44 {
45 namespace Functional
46 {
47 namespace
48 {
49 
50 enum TestIterationType
51 {
52     TYPE_DRAW_COUNT,     // !< test with 1, 5, and 25 primitives
53     TYPE_INSTANCE_COUNT, // !< test with 1, 4, and 11 instances
54 
55     TYPE_LAST
56 };
57 
58 static const char *s_commonVertexShaderSource   = "#version 310 es\n"
59                                                   "in highp vec4 a_position;\n"
60                                                   "void main (void)\n"
61                                                   "{\n"
62                                                   "    gl_Position = a_position;\n"
63                                                   "}\n";
64 static const char *s_commonFragmentShaderSource = "#version 310 es\n"
65                                                   "layout(location = 0) out highp vec4 fragColor;\n"
66                                                   "void main (void)\n"
67                                                   "{\n"
68                                                   "    fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
69                                                   "}\n";
70 
71 static const char *s_colorVertexShaderSource   = "#version 310 es\n"
72                                                  "in highp vec4 a_position;\n"
73                                                  "in highp vec4 a_color;\n"
74                                                  "out highp vec4 v_color;\n"
75                                                  "void main (void)\n"
76                                                  "{\n"
77                                                  "    gl_Position = a_position;\n"
78                                                  "    v_color = a_color;\n"
79                                                  "}\n";
80 static const char *s_colorFragmentShaderSource = "#version 310 es\n"
81                                                  "layout(location = 0) out highp vec4 fragColor;\n"
82                                                  "in highp vec4 v_color;\n"
83                                                  "void main (void)\n"
84                                                  "{\n"
85                                                  "    fragColor = v_color;\n"
86                                                  "}\n";
87 struct DrawElementsCommand
88 {
89     uint32_t count;
90     uint32_t primCount;
91     uint32_t firstIndex;
92     int32_t baseVertex;
93     uint32_t reservedMustBeZero;
94 };
95 DE_STATIC_ASSERT(5 * sizeof(uint32_t) == sizeof(DrawElementsCommand)); // tight packing
96 
97 struct DrawArraysCommand
98 {
99     uint32_t count;
100     uint32_t primCount;
101     uint32_t first;
102     uint32_t reservedMustBeZero;
103 };
104 DE_STATIC_ASSERT(4 * sizeof(uint32_t) == sizeof(DrawArraysCommand)); // tight packing
105 
106 // Verifies image contains only yellow or greeen, or a linear combination
107 // of these colors.
verifyImageYellowGreen(const tcu::Surface & image,tcu::TestLog & log)108 static bool verifyImageYellowGreen(const tcu::Surface &image, tcu::TestLog &log)
109 {
110     using tcu::TestLog;
111 
112     const int colorThreshold = 20;
113 
114     tcu::Surface error(image.getWidth(), image.getHeight());
115     bool isOk = true;
116 
117     for (int y = 0; y < image.getHeight(); y++)
118         for (int x = 0; x < image.getWidth(); x++)
119         {
120             const tcu::RGBA pixel = image.getPixel(x, y);
121             bool pixelOk          = true;
122 
123             // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
124             if (de::abs(pixel.getGreen() - 255) > colorThreshold)
125                 pixelOk = false;
126 
127             // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
128             if (de::abs(pixel.getBlue() - 0) > colorThreshold)
129                 pixelOk = false;
130 
131             error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
132             isOk = isOk && pixelOk;
133         }
134 
135     if (!isOk)
136     {
137         log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
138         log << TestLog::ImageSet("Verfication result", "Result of rendering")
139             << TestLog::Image("Result", "Result", image) << TestLog::Image("ErrorMask", "Error mask", error)
140             << TestLog::EndImageSet;
141     }
142     else
143     {
144         log << TestLog::ImageSet("Verfication result", "Result of rendering")
145             << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet;
146     }
147 
148     return isOk;
149 }
150 
addTestIterations(gls::DrawTest * test,gls::DrawTestSpec & spec,TestIterationType type)151 static void addTestIterations(gls::DrawTest *test, gls::DrawTestSpec &spec, TestIterationType type)
152 {
153     if (type == TYPE_DRAW_COUNT)
154     {
155         spec.primitiveCount = 1;
156         test->addIteration(spec, "draw count = 1");
157 
158         spec.primitiveCount = 5;
159         test->addIteration(spec, "draw count = 5");
160 
161         spec.primitiveCount = 25;
162         test->addIteration(spec, "draw count = 25");
163     }
164     else if (type == TYPE_INSTANCE_COUNT)
165     {
166         spec.instanceCount = 1;
167         test->addIteration(spec, "instance count = 1");
168 
169         spec.instanceCount = 4;
170         test->addIteration(spec, "instance count = 4");
171 
172         spec.instanceCount = 11;
173         test->addIteration(spec, "instance count = 11");
174     }
175     else
176         DE_ASSERT(false);
177 }
178 
genBasicSpec(gls::DrawTestSpec & spec,glu::ContextType contextType,gls::DrawTestSpec::DrawMethod method)179 static void genBasicSpec(gls::DrawTestSpec &spec, glu::ContextType contextType, gls::DrawTestSpec::DrawMethod method)
180 {
181     spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
182     spec.primitive          = gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
183     spec.primitiveCount     = 5;
184     spec.drawMethod         = method;
185     spec.indexType          = gls::DrawTestSpec::INDEXTYPE_LAST;
186     spec.indexPointerOffset = 0;
187     spec.indexStorage       = gls::DrawTestSpec::STORAGE_LAST;
188     spec.first              = 0;
189     spec.indexMin           = 0;
190     spec.indexMax           = 0;
191     spec.instanceCount      = 1;
192     spec.indirectOffset     = 0;
193 
194     spec.attribs.resize(2);
195 
196     spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
197     spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
198     spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
199     spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
200     spec.attribs[0].componentCount      = 4;
201     spec.attribs[0].offset              = 0;
202     spec.attribs[0].stride              = 0;
203     spec.attribs[0].normalize           = false;
204     spec.attribs[0].instanceDivisor     = 0;
205     spec.attribs[0].useDefaultAttribute = false;
206 
207     spec.attribs[1].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
208     spec.attribs[1].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
209     spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
210     spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
211     spec.attribs[1].componentCount      = 2;
212     spec.attribs[1].offset              = 0;
213     spec.attribs[1].stride              = 0;
214     spec.attribs[1].normalize           = false;
215     spec.attribs[1].instanceDivisor     = 0;
216     spec.attribs[1].useDefaultAttribute = false;
217 }
218 
sizeToString(int size)219 static std::string sizeToString(int size)
220 {
221     if (size < 1024)
222         return de::toString(size) + " byte(s)";
223     if (size < 1024 * 1024)
224         return de::toString(size / 1024) + " KB";
225     return de::toString(size / 1024 / 1024) + " MB";
226 }
227 
228 class AttributeGroup : public TestCaseGroup
229 {
230 public:
231     AttributeGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod,
232                    gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType,
233                    gls::DrawTestSpec::Storage indexStorage);
234     ~AttributeGroup(void);
235 
236     void init(void);
237 
238 private:
239     gls::DrawTestSpec::DrawMethod m_method;
240     gls::DrawTestSpec::Primitive m_primitive;
241     gls::DrawTestSpec::IndexType m_indexType;
242     gls::DrawTestSpec::Storage m_indexStorage;
243 };
244 
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)245 AttributeGroup::AttributeGroup(Context &context, const char *name, const char *descr,
246                                gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive,
247                                gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage)
248     : TestCaseGroup(context, name, descr)
249     , m_method(drawMethod)
250     , m_primitive(primitive)
251     , m_indexType(indexType)
252     , m_indexStorage(indexStorage)
253 {
254 }
255 
~AttributeGroup(void)256 AttributeGroup::~AttributeGroup(void)
257 {
258 }
259 
init(void)260 void AttributeGroup::init(void)
261 {
262     // Single attribute
263     {
264         gls::DrawTest *test =
265             new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
266         glu::ContextType contextType = m_context.getRenderContext().getType();
267         gls::DrawTestSpec spec;
268 
269         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
270         spec.primitive          = m_primitive;
271         spec.primitiveCount     = 5;
272         spec.drawMethod         = m_method;
273         spec.indexType          = m_indexType;
274         spec.indexPointerOffset = 0;
275         spec.indexStorage       = m_indexStorage;
276         spec.first              = 0;
277         spec.indexMin           = 0;
278         spec.indexMax           = 0;
279         spec.instanceCount      = 1;
280         spec.indirectOffset     = 0;
281 
282         spec.attribs.resize(1);
283 
284         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
285         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
286         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
287         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
288         spec.attribs[0].componentCount      = 2;
289         spec.attribs[0].offset              = 0;
290         spec.attribs[0].stride              = 0;
291         spec.attribs[0].normalize           = false;
292         spec.attribs[0].instanceDivisor     = 0;
293         spec.attribs[0].useDefaultAttribute = false;
294 
295         addTestIterations(test, spec, TYPE_DRAW_COUNT);
296 
297         this->addChild(test);
298     }
299 
300     // Multiple attribute
301     {
302         gls::DrawTest *test          = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes",
303                                                          "Multiple attribute arrays.");
304         glu::ContextType contextType = m_context.getRenderContext().getType();
305         gls::DrawTestSpec spec;
306 
307         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
308         spec.primitive          = m_primitive;
309         spec.primitiveCount     = 5;
310         spec.drawMethod         = m_method;
311         spec.indexType          = m_indexType;
312         spec.indexPointerOffset = 0;
313         spec.indexStorage       = m_indexStorage;
314         spec.first              = 0;
315         spec.indexMin           = 0;
316         spec.indexMax           = 0;
317         spec.instanceCount      = 1;
318         spec.indirectOffset     = 0;
319 
320         spec.attribs.resize(2);
321 
322         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
323         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
324         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
325         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
326         spec.attribs[0].componentCount      = 4;
327         spec.attribs[0].offset              = 0;
328         spec.attribs[0].stride              = 0;
329         spec.attribs[0].normalize           = false;
330         spec.attribs[0].instanceDivisor     = 0;
331         spec.attribs[0].useDefaultAttribute = false;
332 
333         spec.attribs[1].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
334         spec.attribs[1].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
335         spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
336         spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
337         spec.attribs[1].componentCount      = 2;
338         spec.attribs[1].offset              = 0;
339         spec.attribs[1].stride              = 0;
340         spec.attribs[1].normalize           = false;
341         spec.attribs[1].instanceDivisor     = 0;
342         spec.attribs[1].useDefaultAttribute = false;
343 
344         addTestIterations(test, spec, TYPE_DRAW_COUNT);
345 
346         this->addChild(test);
347     }
348 
349     // Multiple attribute, second one divided
350     {
351         gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes",
352                                                 "Instanced attribute array.");
353         glu::ContextType contextType = m_context.getRenderContext().getType();
354         gls::DrawTestSpec spec;
355 
356         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
357         spec.primitive          = m_primitive;
358         spec.primitiveCount     = 5;
359         spec.drawMethod         = m_method;
360         spec.indexType          = m_indexType;
361         spec.indexPointerOffset = 0;
362         spec.indexStorage       = m_indexStorage;
363         spec.first              = 0;
364         spec.indexMin           = 0;
365         spec.indexMax           = 0;
366         spec.instanceCount      = 1;
367         spec.indirectOffset     = 0;
368 
369         spec.attribs.resize(3);
370 
371         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
372         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
373         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
374         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
375         spec.attribs[0].componentCount      = 4;
376         spec.attribs[0].offset              = 0;
377         spec.attribs[0].stride              = 0;
378         spec.attribs[0].normalize           = false;
379         spec.attribs[0].instanceDivisor     = 0;
380         spec.attribs[0].useDefaultAttribute = false;
381 
382         // Add another position component so the instances wont be drawn on each other
383         spec.attribs[1].inputType                   = gls::DrawTestSpec::INPUTTYPE_FLOAT;
384         spec.attribs[1].outputType                  = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
385         spec.attribs[1].storage                     = gls::DrawTestSpec::STORAGE_BUFFER;
386         spec.attribs[1].usage                       = gls::DrawTestSpec::USAGE_STATIC_DRAW;
387         spec.attribs[1].componentCount              = 2;
388         spec.attribs[1].offset                      = 0;
389         spec.attribs[1].stride                      = 0;
390         spec.attribs[1].normalize                   = false;
391         spec.attribs[1].instanceDivisor             = 1;
392         spec.attribs[1].useDefaultAttribute         = false;
393         spec.attribs[1].additionalPositionAttribute = true;
394 
395         // Instanced color
396         spec.attribs[2].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
397         spec.attribs[2].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
398         spec.attribs[2].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
399         spec.attribs[2].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
400         spec.attribs[2].componentCount      = 3;
401         spec.attribs[2].offset              = 0;
402         spec.attribs[2].stride              = 0;
403         spec.attribs[2].normalize           = false;
404         spec.attribs[2].instanceDivisor     = 1;
405         spec.attribs[2].useDefaultAttribute = false;
406 
407         addTestIterations(test, spec, TYPE_INSTANCE_COUNT);
408 
409         this->addChild(test);
410     }
411 
412     // Multiple attribute, second one default
413     {
414         gls::DrawTest *test          = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute",
415                                                          "Attribute specified with glVertexAttrib*.");
416         glu::ContextType contextType = m_context.getRenderContext().getType();
417         gls::DrawTestSpec spec;
418 
419         spec.apiType            = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
420         spec.primitive          = m_primitive;
421         spec.primitiveCount     = 5;
422         spec.drawMethod         = m_method;
423         spec.indexType          = m_indexType;
424         spec.indexPointerOffset = 0;
425         spec.indexStorage       = m_indexStorage;
426         spec.first              = 0;
427         spec.indexMin           = 0;
428         spec.indexMax           = 0;
429         spec.instanceCount      = 1;
430         spec.indirectOffset     = 0;
431 
432         spec.attribs.resize(2);
433 
434         spec.attribs[0].inputType           = gls::DrawTestSpec::INPUTTYPE_FLOAT;
435         spec.attribs[0].outputType          = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
436         spec.attribs[0].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
437         spec.attribs[0].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
438         spec.attribs[0].componentCount      = 2;
439         spec.attribs[0].offset              = 0;
440         spec.attribs[0].stride              = 0;
441         spec.attribs[0].normalize           = false;
442         spec.attribs[0].instanceDivisor     = 0;
443         spec.attribs[0].useDefaultAttribute = false;
444 
445         struct IOPair
446         {
447             gls::DrawTestSpec::InputType input;
448             gls::DrawTestSpec::OutputType output;
449             int componentCount;
450         } iopairs[] = {
451             {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, 4},
452             {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2},
453             {gls::DrawTestSpec::INPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4},
454             {gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4},
455         };
456 
457         for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
458         {
459             const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) +
460                                      de::toString(iopairs[ioNdx].componentCount) + " to " +
461                                      gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
462 
463             spec.attribs[1].inputType           = iopairs[ioNdx].input;
464             spec.attribs[1].outputType          = iopairs[ioNdx].output;
465             spec.attribs[1].storage             = gls::DrawTestSpec::STORAGE_BUFFER;
466             spec.attribs[1].usage               = gls::DrawTestSpec::USAGE_STATIC_DRAW;
467             spec.attribs[1].componentCount      = iopairs[ioNdx].componentCount;
468             spec.attribs[1].offset              = 0;
469             spec.attribs[1].stride              = 0;
470             spec.attribs[1].normalize           = false;
471             spec.attribs[1].instanceDivisor     = 0;
472             spec.attribs[1].useDefaultAttribute = true;
473 
474             test->addIteration(spec, desc.c_str());
475         }
476 
477         this->addChild(test);
478     }
479 }
480 
481 class IndexGroup : public TestCaseGroup
482 {
483 public:
484     IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
485     ~IndexGroup(void);
486 
487     void init(void);
488 
489 private:
490     gls::DrawTestSpec::DrawMethod m_method;
491 };
492 
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)493 IndexGroup::IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod)
494     : TestCaseGroup(context, name, descr)
495     , m_method(drawMethod)
496 {
497 }
498 
~IndexGroup(void)499 IndexGroup::~IndexGroup(void)
500 {
501 }
502 
init(void)503 void IndexGroup::init(void)
504 {
505     struct IndexTest
506     {
507         gls::DrawTestSpec::IndexType type;
508         int offsets[3];
509     };
510 
511     const IndexTest tests[] = {
512         {gls::DrawTestSpec::INDEXTYPE_BYTE, {0, 1, -1}},
513         {gls::DrawTestSpec::INDEXTYPE_SHORT, {0, 2, -1}},
514         {gls::DrawTestSpec::INDEXTYPE_INT, {0, 4, -1}},
515     };
516 
517     gls::DrawTestSpec spec;
518     genBasicSpec(spec, m_context.getRenderContext().getType(), m_method);
519 
520     spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
521 
522     for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
523     {
524         const IndexTest &indexTest = tests[testNdx];
525 
526         const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
527         const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
528         gls::DrawTest *test    = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
529 
530         spec.indexType = indexTest.type;
531 
532         for (int iterationNdx = 0;
533              iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1;
534              ++iterationNdx)
535         {
536             const std::string iterationDesc =
537                 std::string("first vertex ") +
538                 de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type));
539             spec.indexPointerOffset = indexTest.offsets[iterationNdx];
540             test->addIteration(spec, iterationDesc.c_str());
541         }
542 
543         addChild(test);
544     }
545 }
546 
547 class BaseVertexGroup : public TestCaseGroup
548 {
549 public:
550     BaseVertexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
551     ~BaseVertexGroup(void);
552 
553     void init(void);
554 
555 private:
556     gls::DrawTestSpec::DrawMethod m_method;
557 };
558 
BaseVertexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)559 BaseVertexGroup::BaseVertexGroup(Context &context, const char *name, const char *descr,
560                                  gls::DrawTestSpec::DrawMethod drawMethod)
561     : TestCaseGroup(context, name, descr)
562     , m_method(drawMethod)
563 {
564 }
565 
~BaseVertexGroup(void)566 BaseVertexGroup::~BaseVertexGroup(void)
567 {
568 }
569 
init(void)570 void BaseVertexGroup::init(void)
571 {
572     struct IndexTest
573     {
574         bool positiveBase;
575         gls::DrawTestSpec::IndexType type;
576         int baseVertex[2];
577     };
578 
579     const IndexTest tests[] = {
580         {true, gls::DrawTestSpec::INDEXTYPE_BYTE, {1, 2}},     {true, gls::DrawTestSpec::INDEXTYPE_SHORT, {1, 2}},
581         {true, gls::DrawTestSpec::INDEXTYPE_INT, {1, 2}},      {false, gls::DrawTestSpec::INDEXTYPE_BYTE, {-1, -2}},
582         {false, gls::DrawTestSpec::INDEXTYPE_SHORT, {-1, -2}}, {false, gls::DrawTestSpec::INDEXTYPE_INT, {-1, -2}},
583     };
584 
585     gls::DrawTestSpec spec;
586     genBasicSpec(spec, m_context.getRenderContext().getType(), m_method);
587 
588     spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
589 
590     for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
591     {
592         const IndexTest &indexTest = tests[testNdx];
593 
594         const std::string name = std::string("index_") + (indexTest.positiveBase ? "" : "neg_") +
595                                  gls::DrawTestSpec::indexTypeToString(indexTest.type);
596         const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
597         gls::DrawTest *test    = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
598 
599         spec.indexType = indexTest.type;
600 
601         for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx)
602         {
603             const std::string iterationDesc =
604                 std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]);
605             spec.baseVertex = indexTest.baseVertex[iterationNdx];
606             test->addIteration(spec, iterationDesc.c_str());
607         }
608 
609         addChild(test);
610     }
611 }
612 
613 class FirstGroup : public TestCaseGroup
614 {
615 public:
616     FirstGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
617     ~FirstGroup(void);
618 
619     void init(void);
620 
621 private:
622     gls::DrawTestSpec::DrawMethod m_method;
623 };
624 
FirstGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)625 FirstGroup::FirstGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod)
626     : TestCaseGroup(context, name, descr)
627     , m_method(drawMethod)
628 {
629 }
630 
~FirstGroup(void)631 FirstGroup::~FirstGroup(void)
632 {
633 }
634 
init(void)635 void FirstGroup::init(void)
636 {
637     const int firsts[] = {1, 3, 17};
638 
639     gls::DrawTestSpec spec;
640     genBasicSpec(spec, m_context.getRenderContext().getType(), m_method);
641 
642     for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); ++firstNdx)
643     {
644         const std::string name = std::string("first_") + de::toString(firsts[firstNdx]);
645         const std::string desc = std::string("first ") + de::toString(firsts[firstNdx]);
646         gls::DrawTest *test    = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
647 
648         spec.first = firsts[firstNdx];
649 
650         addTestIterations(test, spec, TYPE_DRAW_COUNT);
651 
652         this->addChild(test);
653     }
654 }
655 
656 class MethodGroup : public TestCaseGroup
657 {
658 public:
659     MethodGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
660     ~MethodGroup(void);
661 
662     void init(void);
663 
664 private:
665     gls::DrawTestSpec::DrawMethod m_method;
666 };
667 
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)668 MethodGroup::MethodGroup(Context &context, const char *name, const char *descr,
669                          gls::DrawTestSpec::DrawMethod drawMethod)
670     : TestCaseGroup(context, name, descr)
671     , m_method(drawMethod)
672 {
673 }
674 
~MethodGroup(void)675 MethodGroup::~MethodGroup(void)
676 {
677 }
678 
init(void)679 void MethodGroup::init(void)
680 {
681     const bool indexed  = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT);
682     const bool hasFirst = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT);
683 
684     const gls::DrawTestSpec::Primitive primitive[] = {
685         gls::DrawTestSpec::PRIMITIVE_POINTS,       gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
686         gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
687         gls::DrawTestSpec::PRIMITIVE_LINES,        gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
688         gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
689 
690     if (hasFirst)
691     {
692         // First-tests
693         this->addChild(new FirstGroup(m_context, "first", "First tests", m_method));
694     }
695 
696     if (indexed)
697     {
698         // Index-tests
699         this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
700         this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method));
701     }
702 
703     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
704     {
705         const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
706         const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
707 
708         this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx],
709                                           gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
710     }
711 }
712 
713 class GridProgram : public sglr::ShaderProgram
714 {
715 public:
716     GridProgram(void);
717 
718     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
719     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
720                         const rr::FragmentShadingContext &context) const;
721 };
722 
GridProgram(void)723 GridProgram::GridProgram(void)
724     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
725                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
726                           << sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
727                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
728                           << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
729                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
730                           << sglr::pdec::VertexSource("#version 310 es\n"
731                                                       "in highp vec4 a_position;\n"
732                                                       "in highp vec4 a_offset;\n"
733                                                       "in highp vec4 a_color;\n"
734                                                       "out highp vec4 v_color;\n"
735                                                       "void main(void)\n"
736                                                       "{\n"
737                                                       "    gl_Position = a_position + a_offset;\n"
738                                                       "    v_color = a_color;\n"
739                                                       "}\n")
740                           << sglr::pdec::FragmentSource("#version 310 es\n"
741                                                         "layout(location = 0) out highp vec4 dEQP_FragColor;\n"
742                                                         "in highp vec4 v_color;\n"
743                                                         "void main(void)\n"
744                                                         "{\n"
745                                                         "    dEQP_FragColor = v_color;\n"
746                                                         "}\n"))
747 {
748 }
749 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const750 void GridProgram::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
751                                 const int numPackets) const
752 {
753     for (int ndx = 0; ndx < numPackets; ++ndx)
754     {
755         packets[ndx]->position =
756             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
757             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
758         packets[ndx]->outputs[0] =
759             rr::readVertexAttribFloat(inputs[2], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
760     }
761 }
762 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const763 void GridProgram::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
764                                  const rr::FragmentShadingContext &context) const
765 {
766     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
767         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
768             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
769                                     rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
770 }
771 
772 class InstancedGridRenderTest : public TestCase
773 {
774 public:
775     InstancedGridRenderTest(Context &context, const char *name, const char *desc, int gridSide, bool useIndices);
776     ~InstancedGridRenderTest(void);
777 
778     IterateResult iterate(void);
779 
780 private:
781     void renderTo(sglr::Context &ctx, sglr::ShaderProgram &program, tcu::Surface &dst);
782 
783     const int m_gridSide;
784     const bool m_useIndices;
785 };
786 
InstancedGridRenderTest(Context & context,const char * name,const char * desc,int gridSide,bool useIndices)787 InstancedGridRenderTest::InstancedGridRenderTest(Context &context, const char *name, const char *desc, int gridSide,
788                                                  bool useIndices)
789     : TestCase(context, name, desc)
790     , m_gridSide(gridSide)
791     , m_useIndices(useIndices)
792 {
793 }
794 
~InstancedGridRenderTest(void)795 InstancedGridRenderTest::~InstancedGridRenderTest(void)
796 {
797 }
798 
iterate(void)799 InstancedGridRenderTest::IterateResult InstancedGridRenderTest::iterate(void)
800 {
801     const int renderTargetWidth  = de::min(1024, m_context.getRenderTarget().getWidth());
802     const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight());
803 
804     sglr::GLContext ctx(m_context.getRenderContext(), m_testCtx.getLog(),
805                         sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS,
806                         tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
807     tcu::Surface surface(renderTargetWidth, renderTargetHeight);
808     GridProgram program;
809 
810     // render
811 
812     renderTo(ctx, program, surface);
813 
814     // verify image
815     // \note the green/yellow pattern is only for clarity. The test will only verify that all instances were drawn by looking for anything non-green/yellow.
816     if (verifyImageYellowGreen(surface, m_testCtx.getLog()))
817         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
818     else
819         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
820     return STOP;
821 }
822 
renderTo(sglr::Context & ctx,sglr::ShaderProgram & program,tcu::Surface & dst)823 void InstancedGridRenderTest::renderTo(sglr::Context &ctx, sglr::ShaderProgram &program, tcu::Surface &dst)
824 {
825     const tcu::Vec4 green(0, 1, 0, 1);
826     const tcu::Vec4 yellow(1, 1, 0, 1);
827 
828     uint32_t vaoID           = 0;
829     uint32_t positionBuf     = 0;
830     uint32_t offsetBuf       = 0;
831     uint32_t colorBuf        = 0;
832     uint32_t indexBuf        = 0;
833     uint32_t drawIndirectBuf = 0;
834     uint32_t programID       = ctx.createProgram(&program);
835     int32_t posLocation      = ctx.getAttribLocation(programID, "a_position");
836     int32_t offsetLocation   = ctx.getAttribLocation(programID, "a_offset");
837     int32_t colorLocation    = ctx.getAttribLocation(programID, "a_color");
838 
839     float cellW                       = 2.0f / (float)m_gridSide;
840     float cellH                       = 2.0f / (float)m_gridSide;
841     const tcu::Vec4 vertexPositions[] = {
842         tcu::Vec4(0, 0, 0, 1),     tcu::Vec4(cellW, 0, 0, 1), tcu::Vec4(0, cellH, 0, 1),
843 
844         tcu::Vec4(0, cellH, 0, 1), tcu::Vec4(cellW, 0, 0, 1), tcu::Vec4(cellW, cellH, 0, 1),
845     };
846 
847     const uint16_t indices[] = {0, 4, 3, 2, 1, 5};
848 
849     std::vector<tcu::Vec4> offsets;
850     for (int x = 0; x < m_gridSide; ++x)
851         for (int y = 0; y < m_gridSide; ++y)
852             offsets.push_back(tcu::Vec4((float)x * cellW - 1.0f, (float)y * cellW - 1.0f, 0, 0));
853 
854     std::vector<tcu::Vec4> colors;
855     for (int x = 0; x < m_gridSide; ++x)
856         for (int y = 0; y < m_gridSide; ++y)
857             colors.push_back(((x + y) % 2 == 0) ? (green) : (yellow));
858 
859     ctx.genVertexArrays(1, &vaoID);
860     ctx.bindVertexArray(vaoID);
861 
862     ctx.genBuffers(1, &positionBuf);
863     ctx.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
864     ctx.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
865     ctx.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
866     ctx.vertexAttribDivisor(posLocation, 0);
867     ctx.enableVertexAttribArray(posLocation);
868 
869     ctx.genBuffers(1, &offsetBuf);
870     ctx.bindBuffer(GL_ARRAY_BUFFER, offsetBuf);
871     ctx.bufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(tcu::Vec4), &offsets[0], GL_STATIC_DRAW);
872     ctx.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
873     ctx.vertexAttribDivisor(offsetLocation, 1);
874     ctx.enableVertexAttribArray(offsetLocation);
875 
876     ctx.genBuffers(1, &colorBuf);
877     ctx.bindBuffer(GL_ARRAY_BUFFER, colorBuf);
878     ctx.bufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(tcu::Vec4), &colors[0], GL_STATIC_DRAW);
879     ctx.vertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
880     ctx.vertexAttribDivisor(colorLocation, 1);
881     ctx.enableVertexAttribArray(colorLocation);
882 
883     if (m_useIndices)
884     {
885         ctx.genBuffers(1, &indexBuf);
886         ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
887         ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
888     }
889 
890     ctx.genBuffers(1, &drawIndirectBuf);
891     ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf);
892 
893     if (m_useIndices)
894     {
895         DrawElementsCommand command;
896         command.count              = 6;
897         command.primCount          = m_gridSide * m_gridSide;
898         command.firstIndex         = 0;
899         command.baseVertex         = 0;
900         command.reservedMustBeZero = 0;
901 
902         ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW);
903     }
904     else
905     {
906         DrawArraysCommand command;
907         command.count              = 6;
908         command.primCount          = m_gridSide * m_gridSide;
909         command.first              = 0;
910         command.reservedMustBeZero = 0;
911 
912         ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(command), &command, GL_STATIC_DRAW);
913     }
914 
915     ctx.clearColor(0, 0, 0, 1);
916     ctx.clear(GL_COLOR_BUFFER_BIT);
917 
918     ctx.viewport(0, 0, dst.getWidth(), dst.getHeight());
919 
920     ctx.useProgram(programID);
921     if (m_useIndices)
922         ctx.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, DE_NULL);
923     else
924         ctx.drawArraysIndirect(GL_TRIANGLES, DE_NULL);
925     ctx.useProgram(0);
926 
927     glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
928 
929     ctx.deleteBuffers(1, &drawIndirectBuf);
930     if (m_useIndices)
931         ctx.deleteBuffers(1, &indexBuf);
932     ctx.deleteBuffers(1, &colorBuf);
933     ctx.deleteBuffers(1, &offsetBuf);
934     ctx.deleteBuffers(1, &positionBuf);
935     ctx.deleteVertexArrays(1, &vaoID);
936     ctx.deleteProgram(programID);
937 
938     ctx.finish();
939     ctx.readPixels(dst, 0, 0, dst.getWidth(), dst.getHeight());
940 
941     glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
942 }
943 
944 class InstancingGroup : public TestCaseGroup
945 {
946 public:
947     InstancingGroup(Context &context, const char *name, const char *descr);
948     ~InstancingGroup(void);
949 
950     void init(void);
951 };
952 
InstancingGroup(Context & context,const char * name,const char * descr)953 InstancingGroup::InstancingGroup(Context &context, const char *name, const char *descr)
954     : TestCaseGroup(context, name, descr)
955 {
956 }
957 
~InstancingGroup(void)958 InstancingGroup::~InstancingGroup(void)
959 {
960 }
961 
init(void)962 void InstancingGroup::init(void)
963 {
964     const int gridWidths[] = {
965         2, 5, 10, 32, 100,
966     };
967 
968     // drawArrays
969     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
970     {
971         const std::string name = std::string("draw_arrays_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" +
972                                  de::toString(gridWidths[ndx]);
973         const std::string desc = std::string("DrawArraysIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" +
974                                  de::toString(gridWidths[ndx]);
975 
976         this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], false));
977     }
978 
979     // drawElements
980     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
981     {
982         const std::string name = std::string("draw_elements_indirect_grid_") + de::toString(gridWidths[ndx]) + "x" +
983                                  de::toString(gridWidths[ndx]);
984         const std::string desc = std::string("DrawElementsIndirect, Grid size ") + de::toString(gridWidths[ndx]) + "x" +
985                                  de::toString(gridWidths[ndx]);
986 
987         this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], true));
988     }
989 }
990 
991 class ComputeShaderGeneratedCase : public TestCase
992 {
993 public:
994     enum DrawMethod
995     {
996         DRAWMETHOD_DRAWARRAYS,
997         DRAWMETHOD_DRAWELEMENTS,
998         DRAWMETHOD_LAST
999     };
1000 
1001     ComputeShaderGeneratedCase(Context &context, const char *name, const char *desc, DrawMethod method, bool computeCmd,
1002                                bool computeData, bool computeIndices, int gridSize, int drawCallCount);
1003     ~ComputeShaderGeneratedCase(void);
1004     void init(void);
1005     void deinit(void);
1006 
1007     IterateResult iterate(void);
1008     std::string genComputeSource(bool computeCmd, bool computeData, bool computeIndices) const;
1009 
1010 private:
1011     void createDrawCommand(void);
1012     void createDrawData(void);
1013     void createDrawIndices(void);
1014 
1015     virtual void runComputeShader(void) = 0;
1016     void renderTo(tcu::Surface &image);
1017 
1018 protected:
1019     uint32_t calcDrawBufferSize(void) const;
1020     uint32_t calcIndexBufferSize(void) const;
1021 
1022     const DrawMethod m_drawMethod;
1023     const bool m_computeCmd;
1024     const bool m_computeData;
1025     const bool m_computeIndices;
1026     const int m_commandSize;
1027     const int m_numDrawCmds;
1028     const int m_gridSize;
1029 
1030     glw::GLuint m_cmdBufferID;
1031     glw::GLuint m_dataBufferID;
1032     glw::GLuint m_indexBufferID;
1033 
1034 private:
1035     glu::ShaderProgram *m_shaderProgram;
1036 };
1037 
ComputeShaderGeneratedCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int drawCallCount)1038 ComputeShaderGeneratedCase::ComputeShaderGeneratedCase(Context &context, const char *name, const char *desc,
1039                                                        DrawMethod method, bool computeCmd, bool computeData,
1040                                                        bool computeIndices, int gridSize, int drawCallCount)
1041     : TestCase(context, name, desc)
1042     , m_drawMethod(method)
1043     , m_computeCmd(computeCmd)
1044     , m_computeData(computeData)
1045     , m_computeIndices(computeIndices)
1046     , m_commandSize((method == DRAWMETHOD_DRAWARRAYS) ? ((int)sizeof(DrawArraysCommand)) :
1047                                                         ((int)sizeof(DrawElementsCommand)))
1048     , m_numDrawCmds(drawCallCount)
1049     , m_gridSize(gridSize)
1050     , m_cmdBufferID(0)
1051     , m_dataBufferID(0)
1052     , m_indexBufferID(0)
1053     , m_shaderProgram(DE_NULL)
1054 {
1055     const int triangleCount = m_gridSize * m_gridSize * 2;
1056 
1057     DE_ASSERT(method < DRAWMETHOD_LAST);
1058     DE_ASSERT(!computeIndices || method == DRAWMETHOD_DRAWELEMENTS);
1059     DE_ASSERT(triangleCount % m_numDrawCmds == 0);
1060     DE_UNREF(triangleCount);
1061 }
1062 
~ComputeShaderGeneratedCase(void)1063 ComputeShaderGeneratedCase::~ComputeShaderGeneratedCase(void)
1064 {
1065     deinit();
1066 }
1067 
init(void)1068 void ComputeShaderGeneratedCase::init(void)
1069 {
1070     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1071 
1072     // generate basic shader
1073 
1074     m_shaderProgram = new glu::ShaderProgram(m_context.getRenderContext(),
1075                                              glu::ProgramSources() << glu::VertexSource(s_colorVertexShaderSource)
1076                                                                    << glu::FragmentSource(s_colorFragmentShaderSource));
1077     m_testCtx.getLog() << *m_shaderProgram;
1078 
1079     if (!m_shaderProgram->isOk())
1080         throw tcu::TestError("Failed to compile shader.");
1081 
1082     // gen buffers
1083     gl.genBuffers(1, &m_cmdBufferID);
1084     gl.genBuffers(1, &m_dataBufferID);
1085     gl.genBuffers(1, &m_indexBufferID);
1086 
1087     // check the SSBO buffers are of legal size
1088     {
1089         const uint64_t drawBufferElementSize  = sizeof(tcu::Vec4);
1090         const uint64_t indexBufferElementSize = sizeof(uint32_t);
1091         const int commandBufferSize           = m_commandSize * m_numDrawCmds;
1092         int64_t maxSSBOSize                   = 0;
1093 
1094         gl.getInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxSSBOSize);
1095 
1096         if (m_computeData && (uint64_t)calcDrawBufferSize() * drawBufferElementSize > (uint64_t)maxSSBOSize)
1097             throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for vertex attrib buffers");
1098         if (m_computeIndices && (uint64_t)calcIndexBufferSize() * indexBufferElementSize > (uint64_t)maxSSBOSize)
1099             throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for index buffers");
1100         if (m_computeCmd && (uint64_t)commandBufferSize > (uint64_t)maxSSBOSize)
1101             throw tcu::NotSupportedError("GL_MAX_SHADER_STORAGE_BLOCK_SIZE is too small for command buffers");
1102     }
1103 }
1104 
deinit(void)1105 void ComputeShaderGeneratedCase::deinit(void)
1106 {
1107     if (m_cmdBufferID)
1108     {
1109         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_cmdBufferID);
1110         m_cmdBufferID = 0;
1111     }
1112     if (m_dataBufferID)
1113     {
1114         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBufferID);
1115         m_dataBufferID = 0;
1116     }
1117     if (m_indexBufferID)
1118     {
1119         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID);
1120         m_indexBufferID = 0;
1121     }
1122 
1123     if (m_shaderProgram)
1124     {
1125         delete m_shaderProgram;
1126         m_shaderProgram = DE_NULL;
1127     }
1128 }
1129 
iterate(void)1130 ComputeShaderGeneratedCase::IterateResult ComputeShaderGeneratedCase::iterate(void)
1131 {
1132     const int renderTargetWidth  = de::min(1024, m_context.getRenderTarget().getWidth());
1133     const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight());
1134     const glw::Functions &gl     = m_context.getRenderContext().getFunctions();
1135     tcu::Surface surface(renderTargetWidth, renderTargetHeight);
1136 
1137     m_testCtx.getLog() << tcu::TestLog::Message << "Preparing to draw " << m_gridSize << " x " << m_gridSize << " grid."
1138                        << tcu::TestLog::EndMessage;
1139 
1140     try
1141     {
1142         // Gen command buffer
1143         if (!m_computeCmd)
1144         {
1145             m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw command buffer." << tcu::TestLog::EndMessage;
1146             createDrawCommand();
1147         }
1148 
1149         // Gen data buffer
1150         if (!m_computeData)
1151         {
1152             m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw data buffer." << tcu::TestLog::EndMessage;
1153             createDrawData();
1154         }
1155 
1156         // Gen index buffer
1157         if (!m_computeIndices && m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1158         {
1159             m_testCtx.getLog() << tcu::TestLog::Message << "Uploading draw index buffer." << tcu::TestLog::EndMessage;
1160             createDrawIndices();
1161         }
1162 
1163         // Run compute shader
1164         {
1165             m_testCtx.getLog() << tcu::TestLog::Message << "Filling following buffers using compute shader:\n"
1166                                << ((m_computeCmd) ? ("\tcommand buffer\n") : (""))
1167                                << ((m_computeData) ? ("\tdata buffer\n") : (""))
1168                                << ((m_computeIndices) ? ("\tindex buffer\n") : ("")) << tcu::TestLog::EndMessage;
1169             runComputeShader();
1170         }
1171 
1172         // Ensure data is written to the buffers before we try to read it
1173         {
1174             const glw::GLuint barriers = ((m_computeCmd) ? (GL_COMMAND_BARRIER_BIT) : (0)) |
1175                                          ((m_computeData) ? (GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) : (0)) |
1176                                          ((m_computeIndices) ? (GL_ELEMENT_ARRAY_BARRIER_BIT) : (0));
1177 
1178             m_testCtx.getLog() << tcu::TestLog::Message
1179                                << "Memory barrier. Barriers = " << glu::getMemoryBarrierFlagsStr(barriers)
1180                                << tcu::TestLog::EndMessage;
1181             gl.memoryBarrier(barriers);
1182         }
1183 
1184         // Draw from buffers
1185 
1186         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing from buffers with " << m_numDrawCmds << " draw call(s)."
1187                            << tcu::TestLog::EndMessage;
1188         renderTo(surface);
1189     }
1190     catch (glu::OutOfMemoryError &)
1191     {
1192         m_testCtx.getLog() << tcu::TestLog::Message << "Got GL_OUT_OF_MEMORY." << tcu::TestLog::EndMessage;
1193         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Got GL_OUT_OF_MEMORY");
1194         m_testCtx.setTerminateAfter(true); // Do not rely on implementation to be able to recover from OOM
1195         return STOP;
1196     }
1197 
1198     // verify image
1199     // \note the green/yellow pattern is only for clarity. The test will only verify that all grid cells were drawn by looking for anything non-green/yellow.
1200     if (verifyImageYellowGreen(surface, m_testCtx.getLog()))
1201         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1202     else
1203         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
1204     return STOP;
1205 }
1206 
genComputeSource(bool computeCmd,bool computeData,bool computeIndices) const1207 std::string ComputeShaderGeneratedCase::genComputeSource(bool computeCmd, bool computeData, bool computeIndices) const
1208 {
1209     const int cmdLayoutBinding   = 0;
1210     const int dataLayoutBinding  = (computeCmd) ? (1) : (0);
1211     const int indexLayoutBinding = (computeCmd && computeData) ? (2) : (computeCmd || computeData) ? (1) : (0);
1212 
1213     std::ostringstream buf;
1214 
1215     buf << "#version 310 es\n\n"
1216         << "precision highp int;\n"
1217         << "precision highp float;\n\n";
1218 
1219     if (computeCmd && m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1220         buf << "struct DrawArraysIndirectCommand {\n"
1221             << "    uint count;\n"
1222             << "    uint primCount;\n"
1223             << "    uint first;\n"
1224             << "    uint reservedMustBeZero;\n"
1225             << "};\n\n";
1226     else if (computeCmd && m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1227         buf << "struct DrawElementsIndirectCommand {\n"
1228             << "    uint count;\n"
1229             << "    uint primCount;\n"
1230             << "    uint firstIndex;\n"
1231             << "    int  baseVertex;\n"
1232             << "    uint reservedMustBeZero;\n"
1233             << "};\n\n";
1234 
1235     buf << "layout(local_size_x = 1, local_size_y = 1) in;\n"
1236         << "layout(std430) buffer;\n\n";
1237 
1238     if (computeCmd)
1239         buf << "layout(binding = " << cmdLayoutBinding << ") writeonly buffer CommandBuffer {\n"
1240             << "    "
1241             << ((m_drawMethod == DRAWMETHOD_DRAWARRAYS) ? ("DrawArraysIndirectCommand") :
1242                                                           ("DrawElementsIndirectCommand"))
1243             << " commands[];\n"
1244             << "};\n";
1245     if (computeData)
1246         buf << "layout(binding = " << dataLayoutBinding << ") writeonly buffer DataBuffer {\n"
1247             << "    vec4 attribs[];\n"
1248             << "};\n";
1249     if (computeIndices)
1250         buf << "layout(binding = " << indexLayoutBinding << ") writeonly buffer IndexBuffer {\n"
1251             << "    uint indices[];\n"
1252             << "};\n";
1253 
1254     buf << "\n"
1255         << "void main() {\n"
1256         << "    const uint gridSize      = " << m_gridSize << "u;\n"
1257         << "    const uint triangleCount = gridSize * gridSize * 2u;\n"
1258         << "\n";
1259 
1260     if (computeCmd)
1261     {
1262         buf << "    // command\n"
1263             << "    if (gl_GlobalInvocationID.x < " << m_numDrawCmds
1264             << "u && gl_GlobalInvocationID.y == 0u && gl_GlobalInvocationID.z == 0u) {\n"
1265             << "        const uint numDrawCallTris = triangleCount / " << m_numDrawCmds << "u;\n"
1266             << "        uint firstTri              = gl_GlobalInvocationID.x * numDrawCallTris;\n\n"
1267             << "        commands[gl_GlobalInvocationID.x].count                 = numDrawCallTris*3u;\n"
1268             << "        commands[gl_GlobalInvocationID.x].primCount             = 1u;\n";
1269 
1270         if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1271         {
1272             buf << "        commands[gl_GlobalInvocationID.x].first                 = firstTri*3u;\n";
1273         }
1274         else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1275         {
1276             buf << "        commands[gl_GlobalInvocationID.x].firstIndex            = firstTri*3u;\n";
1277             buf << "        commands[gl_GlobalInvocationID.x].baseVertex            = 0;\n";
1278         }
1279 
1280         buf << "        commands[gl_GlobalInvocationID.x].reservedMustBeZero    = 0u;\n"
1281             << "    }\n"
1282             << "\n";
1283     }
1284 
1285     if (computeData)
1286     {
1287         buf << "    // vertex attribs\n"
1288             << "    const vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1289             << "    const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n";
1290 
1291         if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1292         {
1293             buf << "    if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && "
1294                    "gl_GlobalInvocationID.z == 0u) {\n"
1295                 << "        uint        y           = gl_GlobalInvocationID.x;\n"
1296                 << "        uint        x           = gl_GlobalInvocationID.y;\n"
1297                 << "        float       posX        = (float(x)    / float(gridSize)) * 2.0 - 1.0;\n"
1298                 << "        float       posXp1      = (float(x+1u) / float(gridSize)) * 2.0 - 1.0;\n"
1299                 << "        float       posY        = (float(y)    / float(gridSize)) * 2.0 - 1.0;\n"
1300                 << "        float       posYp1      = (float(y+1u) / float(gridSize)) * 2.0 - 1.0;\n"
1301                 << "        vec4        color       = ((x + y)%2u != 0u) ? (yellow) : (green);\n"
1302                 << "\n"
1303                 << "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 0u] = vec4(posX,   posY,   0.0, 1.0);\n"
1304                 << "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 0u] = vec4(posXp1, posY,   0.0, 1.0);\n"
1305                 << "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n"
1306                 << "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 0u] = vec4(posX,   posY,   0.0, 1.0);\n"
1307                 << "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 0u] = vec4(posXp1, posYp1, 0.0, 1.0);\n"
1308                 << "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 0u] = vec4(posX,   posYp1, 0.0, 1.0);\n"
1309                 << "\n"
1310                 << "        attribs[((y * gridSize + x) * 6u + 0u) * 2u + 1u] = color;\n"
1311                 << "        attribs[((y * gridSize + x) * 6u + 1u) * 2u + 1u] = color;\n"
1312                 << "        attribs[((y * gridSize + x) * 6u + 2u) * 2u + 1u] = color;\n"
1313                 << "        attribs[((y * gridSize + x) * 6u + 3u) * 2u + 1u] = color;\n"
1314                 << "        attribs[((y * gridSize + x) * 6u + 4u) * 2u + 1u] = color;\n"
1315                 << "        attribs[((y * gridSize + x) * 6u + 5u) * 2u + 1u] = color;\n"
1316                 << "    }\n";
1317         }
1318         else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1319         {
1320             buf << "    if (gl_GlobalInvocationID.x < gridSize+1u && gl_GlobalInvocationID.y < gridSize+1u && "
1321                    "gl_GlobalInvocationID.z == 0u) {\n"
1322                 << "        uint        y           = gl_GlobalInvocationID.x;\n"
1323                 << "        uint        x           = gl_GlobalInvocationID.y;\n"
1324                 << "        float       posX        = (float(x) / float(gridSize)) * 2.0 - 1.0;\n"
1325                 << "        float       posY        = (float(y) / float(gridSize)) * 2.0 - 1.0;\n"
1326                 << "\n"
1327                 << "        attribs[(y * (gridSize+1u) + x) * 4u + 0u] = vec4(posX, posY, 0.0, 1.0);\n"
1328                 << "        attribs[(y * (gridSize+1u) + x) * 4u + 1u] = green;\n"
1329                 << "        attribs[(y * (gridSize+1u) + x) * 4u + 2u] = vec4(posX, posY, 0.0, 1.0);\n"
1330                 << "        attribs[(y * (gridSize+1u) + x) * 4u + 3u] = yellow;\n"
1331                 << "    }\n";
1332         }
1333 
1334         buf << "\n";
1335     }
1336 
1337     if (computeIndices)
1338     {
1339         buf << "    // indices\n"
1340             << "    if (gl_GlobalInvocationID.x < gridSize && gl_GlobalInvocationID.y < gridSize && "
1341                "gl_GlobalInvocationID.z == 0u) {\n"
1342             << "        uint    y       = gl_GlobalInvocationID.x;\n"
1343             << "        uint    x       = gl_GlobalInvocationID.y;\n"
1344             << "        uint    color   = ((x + y)%2u);\n"
1345             << "\n"
1346             << "        indices[(y * gridSize + x) * 6u + 0u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1347             << "        indices[(y * gridSize + x) * 6u + 1u] = ((y+1u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1348             << "        indices[(y * gridSize + x) * 6u + 2u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1349             << "        indices[(y * gridSize + x) * 6u + 3u] = ((y+0u) * (gridSize+1u) + (x+0u)) * 2u + color;\n"
1350             << "        indices[(y * gridSize + x) * 6u + 4u] = ((y+1u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1351             << "        indices[(y * gridSize + x) * 6u + 5u] = ((y+0u) * (gridSize+1u) + (x+1u)) * 2u + color;\n"
1352             << "    }\n"
1353             << "\n";
1354     }
1355 
1356     buf << "}\n";
1357 
1358     return buf.str();
1359 }
1360 
createDrawCommand(void)1361 void ComputeShaderGeneratedCase::createDrawCommand(void)
1362 {
1363     const glw::Functions &gl       = m_context.getRenderContext().getFunctions();
1364     const int triangleCount        = m_gridSize * m_gridSize * 2;
1365     const uint32_t numDrawCallTris = triangleCount / m_numDrawCmds;
1366 
1367     if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1368     {
1369         std::vector<DrawArraysCommand> cmds;
1370 
1371         for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1372         {
1373             const uint32_t firstTri = ndx * numDrawCallTris;
1374             DrawArraysCommand data;
1375 
1376             data.count              = numDrawCallTris * 3;
1377             data.primCount          = 1;
1378             data.first              = firstTri * 3;
1379             data.reservedMustBeZero = 0;
1380 
1381             cmds.push_back(data);
1382         }
1383 
1384         DE_ASSERT((int)(sizeof(DrawArraysCommand) * cmds.size()) == m_numDrawCmds * m_commandSize);
1385 
1386         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1387         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawArraysCommand) * cmds.size()), &cmds[0],
1388                       GL_STATIC_DRAW);
1389     }
1390     else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1391     {
1392         std::vector<DrawElementsCommand> cmds;
1393 
1394         for (int ndx = 0; ndx < m_numDrawCmds; ++ndx)
1395         {
1396             const uint32_t firstTri = ndx * numDrawCallTris;
1397             DrawElementsCommand data;
1398 
1399             data.count              = numDrawCallTris * 3;
1400             data.primCount          = 1;
1401             data.firstIndex         = firstTri * 3;
1402             data.baseVertex         = 0;
1403             data.reservedMustBeZero = 0;
1404 
1405             cmds.push_back(data);
1406         }
1407 
1408         DE_ASSERT((int)(sizeof(DrawElementsCommand) * cmds.size()) == m_numDrawCmds * m_commandSize);
1409 
1410         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1411         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, (glw::GLsizeiptr)(sizeof(DrawElementsCommand) * cmds.size()), &cmds[0],
1412                       GL_STATIC_DRAW);
1413     }
1414     else
1415         DE_ASSERT(false);
1416 
1417     glu::checkError(gl.getError(), "create draw command", __FILE__, __LINE__);
1418 }
1419 
createDrawData(void)1420 void ComputeShaderGeneratedCase::createDrawData(void)
1421 {
1422     const tcu::Vec4 yellow(1.0f, 1.0f, 0.0f, 1.0f);
1423     const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
1424     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1425 
1426     if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1427     {
1428         // Store elements in the order they are drawn. Interleave color.
1429         std::vector<tcu::Vec4> buffer(m_gridSize * m_gridSize * 6 * 2);
1430 
1431         DE_ASSERT(buffer.size() == calcDrawBufferSize());
1432 
1433         for (int y = 0; y < m_gridSize; ++y)
1434             for (int x = 0; x < m_gridSize; ++x)
1435             {
1436                 const float posX       = ((float)x / (float)m_gridSize) * 2.0f - 1.0f;
1437                 const float posY       = ((float)y / (float)m_gridSize) * 2.0f - 1.0f;
1438                 const float cellSize   = 2.0f / (float)m_gridSize;
1439                 const tcu::Vec4 &color = ((x + y) % 2) ? (yellow) : (green);
1440 
1441                 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1442                 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 0] = tcu::Vec4(posX + cellSize, posY, 0.0f, 1.0f);
1443                 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 0] =
1444                     tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f);
1445                 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1446                 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 0] =
1447                     tcu::Vec4(posX + cellSize, posY + cellSize, 0.0f, 1.0f);
1448                 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 0] = tcu::Vec4(posX, posY + cellSize, 0.0f, 1.0f);
1449 
1450                 buffer[((y * m_gridSize + x) * 6 + 0) * 2 + 1] = color;
1451                 buffer[((y * m_gridSize + x) * 6 + 1) * 2 + 1] = color;
1452                 buffer[((y * m_gridSize + x) * 6 + 2) * 2 + 1] = color;
1453                 buffer[((y * m_gridSize + x) * 6 + 3) * 2 + 1] = color;
1454                 buffer[((y * m_gridSize + x) * 6 + 4) * 2 + 1] = color;
1455                 buffer[((y * m_gridSize + x) * 6 + 5) * 2 + 1] = color;
1456             }
1457 
1458         gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1459         gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1460     }
1461     else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1462     {
1463         // Elements are indexed by index buffer. Interleave color. Two vertices per position since 2 colors
1464 
1465         std::vector<tcu::Vec4> buffer((m_gridSize + 1) * (m_gridSize + 1) * 4);
1466 
1467         DE_ASSERT(buffer.size() == calcDrawBufferSize());
1468 
1469         for (int y = 0; y < m_gridSize + 1; ++y)
1470             for (int x = 0; x < m_gridSize + 1; ++x)
1471             {
1472                 const float posX = ((float)x / (float)m_gridSize) * 2.0f - 1.0f;
1473                 const float posY = ((float)y / (float)m_gridSize) * 2.0f - 1.0f;
1474 
1475                 buffer[(y * (m_gridSize + 1) + x) * 4 + 0] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1476                 buffer[(y * (m_gridSize + 1) + x) * 4 + 1] = green;
1477                 buffer[(y * (m_gridSize + 1) + x) * 4 + 2] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1478                 buffer[(y * (m_gridSize + 1) + x) * 4 + 3] = yellow;
1479             }
1480 
1481         gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1482         gl.bufferData(GL_ARRAY_BUFFER, (int)(buffer.size() * sizeof(tcu::Vec4)), buffer[0].getPtr(), GL_STATIC_DRAW);
1483     }
1484     else
1485         DE_ASSERT(false);
1486 
1487     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1488 }
1489 
createDrawIndices(void)1490 void ComputeShaderGeneratedCase::createDrawIndices(void)
1491 {
1492     DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1493 
1494     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1495     std::vector<uint32_t> buffer(m_gridSize * m_gridSize * 6);
1496 
1497     DE_ASSERT(buffer.size() == calcIndexBufferSize());
1498 
1499     for (int y = 0; y < m_gridSize; ++y)
1500         for (int x = 0; x < m_gridSize; ++x)
1501         {
1502             const int color = ((x + y) % 2);
1503 
1504             buffer[(y * m_gridSize + x) * 6 + 0] = ((y + 0) * (m_gridSize + 1) + (x + 0)) * 2 + color;
1505             buffer[(y * m_gridSize + x) * 6 + 1] = ((y + 1) * (m_gridSize + 1) + (x + 0)) * 2 + color;
1506             buffer[(y * m_gridSize + x) * 6 + 2] = ((y + 1) * (m_gridSize + 1) + (x + 1)) * 2 + color;
1507             buffer[(y * m_gridSize + x) * 6 + 3] = ((y + 0) * (m_gridSize + 1) + (x + 0)) * 2 + color;
1508             buffer[(y * m_gridSize + x) * 6 + 4] = ((y + 1) * (m_gridSize + 1) + (x + 1)) * 2 + color;
1509             buffer[(y * m_gridSize + x) * 6 + 5] = ((y + 0) * (m_gridSize + 1) + (x + 1)) * 2 + color;
1510         }
1511 
1512     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1513     gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(buffer.size() * sizeof(uint32_t)), &buffer[0], GL_STATIC_DRAW);
1514     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1515 }
1516 
renderTo(tcu::Surface & dst)1517 void ComputeShaderGeneratedCase::renderTo(tcu::Surface &dst)
1518 {
1519     const glw::Functions &gl  = m_context.getRenderContext().getFunctions();
1520     const int32_t positionLoc = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_position");
1521     const int32_t colorLoc    = gl.getAttribLocation(m_shaderProgram->getProgram(), "a_color");
1522     uint32_t vaoID            = 0;
1523 
1524     gl.genVertexArrays(1, &vaoID);
1525     gl.bindVertexArray(vaoID);
1526 
1527     // Setup buffers
1528 
1529     gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
1530     gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float), DE_NULL);
1531     gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 8 * (int)sizeof(float),
1532                            glu::BufferOffsetAsPointer(4 * sizeof(float)));
1533     gl.enableVertexAttribArray(positionLoc);
1534     gl.enableVertexAttribArray(colorLoc);
1535 
1536     DE_ASSERT(positionLoc != -1);
1537     DE_ASSERT(colorLoc != -1);
1538 
1539     if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1540         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
1541 
1542     gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
1543 
1544     // draw
1545 
1546     gl.clearColor(0, 0, 0, 1);
1547     gl.clear(GL_COLOR_BUFFER_BIT);
1548     gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1549 
1550     gl.useProgram(m_shaderProgram->getProgram());
1551     for (int drawCmdNdx = 0; drawCmdNdx < m_numDrawCmds; ++drawCmdNdx)
1552     {
1553         const void *offset = glu::BufferOffsetAsPointer(drawCmdNdx * m_commandSize);
1554 
1555         if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1556             gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset);
1557         else if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1558             gl.drawArraysIndirect(GL_TRIANGLES, offset);
1559         else
1560             DE_ASSERT(false);
1561     }
1562     gl.useProgram(0);
1563 
1564     // free
1565 
1566     gl.deleteVertexArrays(1, &vaoID);
1567     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1568 
1569     gl.finish();
1570     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1571 
1572     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1573     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
1574 }
1575 
calcDrawBufferSize(void) const1576 uint32_t ComputeShaderGeneratedCase::calcDrawBufferSize(void) const
1577 {
1578     // returns size in "vec4"s
1579     if (m_drawMethod == DRAWMETHOD_DRAWARRAYS)
1580         return m_gridSize * m_gridSize * 6 * 2;
1581     else if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1582         return (m_gridSize + 1) * (m_gridSize + 1) * 4;
1583     else
1584         DE_ASSERT(false);
1585 
1586     return 0;
1587 }
1588 
calcIndexBufferSize(void) const1589 uint32_t ComputeShaderGeneratedCase::calcIndexBufferSize(void) const
1590 {
1591     if (m_drawMethod == DRAWMETHOD_DRAWELEMENTS)
1592         return m_gridSize * m_gridSize * 6;
1593     else
1594         return 0;
1595 }
1596 
1597 class ComputeShaderGeneratedCombinedCase : public ComputeShaderGeneratedCase
1598 {
1599 public:
1600     ComputeShaderGeneratedCombinedCase(Context &context, const char *name, const char *desc, DrawMethod method,
1601                                        bool computeCmd, bool computeData, bool computeIndices, int gridSize,
1602                                        int numDrawCalls);
1603     ~ComputeShaderGeneratedCombinedCase(void);
1604 
1605     void init(void);
1606     void deinit(void);
1607 
1608 private:
1609     void runComputeShader(void);
1610 
1611     glu::ShaderProgram *m_computeProgram;
1612 };
1613 
ComputeShaderGeneratedCombinedCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1614 ComputeShaderGeneratedCombinedCase::ComputeShaderGeneratedCombinedCase(Context &context, const char *name,
1615                                                                        const char *desc, DrawMethod method,
1616                                                                        bool computeCmd, bool computeData,
1617                                                                        bool computeIndices, int gridSize,
1618                                                                        int numDrawCalls)
1619     : ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize,
1620                                  numDrawCalls)
1621     , m_computeProgram(DE_NULL)
1622 {
1623 }
1624 
~ComputeShaderGeneratedCombinedCase(void)1625 ComputeShaderGeneratedCombinedCase::~ComputeShaderGeneratedCombinedCase(void)
1626 {
1627     deinit();
1628 }
1629 
init(void)1630 void ComputeShaderGeneratedCombinedCase::init(void)
1631 {
1632     // generate compute shader
1633 
1634     m_computeProgram = new glu::ShaderProgram(
1635         m_context.getRenderContext(),
1636         glu::ProgramSources() << glu::ComputeSource(genComputeSource(m_computeCmd, m_computeData, m_computeIndices)));
1637     m_testCtx.getLog() << *m_computeProgram;
1638 
1639     if (!m_computeProgram->isOk())
1640         throw tcu::TestError("Failed to compile compute shader.");
1641 
1642     // init parent
1643     ComputeShaderGeneratedCase::init();
1644 }
1645 
deinit(void)1646 void ComputeShaderGeneratedCombinedCase::deinit(void)
1647 {
1648     // deinit parent
1649     ComputeShaderGeneratedCase::deinit();
1650 
1651     if (m_computeProgram)
1652     {
1653         delete m_computeProgram;
1654         m_computeProgram = DE_NULL;
1655     }
1656 }
1657 
runComputeShader(void)1658 void ComputeShaderGeneratedCombinedCase::runComputeShader(void)
1659 {
1660     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1661     const bool indexed       = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1662     const tcu::IVec3 nullSize(0, 0, 0);
1663     const tcu::IVec3 commandDispatchSize = (m_computeCmd) ? (tcu::IVec3(m_numDrawCmds, 1, 1)) : (nullSize);
1664     const tcu::IVec3 drawElementsDataBufferDispatchSize =
1665         (m_computeData) ? (tcu::IVec3(m_gridSize + 1, m_gridSize + 1, 1)) : (nullSize);
1666     const tcu::IVec3 drawArraysDataBufferDispatchSize =
1667         (m_computeData) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize);
1668     const tcu::IVec3 indexBufferDispatchSize =
1669         (m_computeIndices && indexed) ? (tcu::IVec3(m_gridSize, m_gridSize, 1)) : (nullSize);
1670 
1671     const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ?
1672                                                   (drawElementsDataBufferDispatchSize) :
1673                                                   (drawArraysDataBufferDispatchSize);
1674     const tcu::IVec3 dispatchSize =
1675         tcu::max(tcu::max(commandDispatchSize, dataBufferDispatchSize), indexBufferDispatchSize);
1676 
1677     gl.useProgram(m_computeProgram->getProgram());
1678     glu::checkError(gl.getError(), "use compute shader", __FILE__, __LINE__);
1679 
1680     // setup buffers
1681 
1682     if (m_computeCmd)
1683     {
1684         const int bindingPoint = 0;
1685         const int bufferSize   = m_commandSize * m_numDrawCmds;
1686 
1687         m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint
1688                            << tcu::TestLog::EndMessage;
1689         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1690 
1691         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size "
1692                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1693         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1694     }
1695 
1696     if (m_computeData)
1697     {
1698         const int bindingPoint = (m_computeCmd) ? (1) : (0);
1699         const int bufferSize   = (int)(calcDrawBufferSize() * sizeof(tcu::Vec4));
1700 
1701         m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint
1702                            << tcu::TestLog::EndMessage;
1703         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1704 
1705         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size "
1706                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1707         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1708     }
1709 
1710     if (m_computeIndices)
1711     {
1712         const int bindingPoint = (m_computeCmd && m_computeData) ? (2) : (m_computeCmd || m_computeData) ? (1) : (0);
1713         const int bufferSize   = (int)(calcIndexBufferSize() * sizeof(uint32_t));
1714 
1715         m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint
1716                            << tcu::TestLog::EndMessage;
1717         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1718 
1719         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size "
1720                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1721         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1722     }
1723 
1724     glu::checkError(gl.getError(), "setup buffers", __FILE__, __LINE__);
1725 
1726     // calculate
1727 
1728     m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching compute, size = " << dispatchSize
1729                        << tcu::TestLog::EndMessage;
1730     gl.dispatchCompute(dispatchSize.x(), dispatchSize.y(), dispatchSize.z());
1731 
1732     glu::checkError(gl.getError(), "calculate", __FILE__, __LINE__);
1733 }
1734 
1735 class ComputeShaderGeneratedSeparateCase : public ComputeShaderGeneratedCase
1736 {
1737 public:
1738     ComputeShaderGeneratedSeparateCase(Context &context, const char *name, const char *desc, DrawMethod method,
1739                                        bool computeCmd, bool computeData, bool computeIndices, int gridSize,
1740                                        int numDrawCalls);
1741     ~ComputeShaderGeneratedSeparateCase(void);
1742 
1743     void init(void);
1744     void deinit(void);
1745 
1746 private:
1747     std::string genCmdComputeSource(void);
1748     std::string genDataComputeSource(void);
1749     std::string genIndexComputeSource(void);
1750     void runComputeShader(void);
1751 
1752     glu::ShaderProgram *m_computeCmdProgram;
1753     glu::ShaderProgram *m_computeDataProgram;
1754     glu::ShaderProgram *m_computeIndicesProgram;
1755 };
1756 
ComputeShaderGeneratedSeparateCase(Context & context,const char * name,const char * desc,DrawMethod method,bool computeCmd,bool computeData,bool computeIndices,int gridSize,int numDrawCalls)1757 ComputeShaderGeneratedSeparateCase::ComputeShaderGeneratedSeparateCase(Context &context, const char *name,
1758                                                                        const char *desc, DrawMethod method,
1759                                                                        bool computeCmd, bool computeData,
1760                                                                        bool computeIndices, int gridSize,
1761                                                                        int numDrawCalls)
1762     : ComputeShaderGeneratedCase(context, name, desc, method, computeCmd, computeData, computeIndices, gridSize,
1763                                  numDrawCalls)
1764     , m_computeCmdProgram(DE_NULL)
1765     , m_computeDataProgram(DE_NULL)
1766     , m_computeIndicesProgram(DE_NULL)
1767 {
1768 }
1769 
~ComputeShaderGeneratedSeparateCase(void)1770 ComputeShaderGeneratedSeparateCase::~ComputeShaderGeneratedSeparateCase(void)
1771 {
1772     deinit();
1773 }
1774 
init(void)1775 void ComputeShaderGeneratedSeparateCase::init(void)
1776 {
1777     // generate cmd compute shader
1778 
1779     if (m_computeCmd)
1780     {
1781         m_computeCmdProgram = new glu::ShaderProgram(
1782             m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genCmdComputeSource()));
1783         m_testCtx.getLog() << *m_computeCmdProgram;
1784 
1785         if (!m_computeCmdProgram->isOk())
1786             throw tcu::TestError("Failed to compile command compute shader.");
1787     }
1788 
1789     // generate data compute shader
1790 
1791     if (m_computeData)
1792     {
1793         m_computeDataProgram = new glu::ShaderProgram(
1794             m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genDataComputeSource()));
1795         m_testCtx.getLog() << *m_computeDataProgram;
1796 
1797         if (!m_computeDataProgram->isOk())
1798             throw tcu::TestError("Failed to compile data compute shader.");
1799     }
1800 
1801     // generate index compute shader
1802 
1803     if (m_computeIndices)
1804     {
1805         m_computeIndicesProgram = new glu::ShaderProgram(
1806             m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genIndexComputeSource()));
1807         m_testCtx.getLog() << *m_computeIndicesProgram;
1808 
1809         if (!m_computeIndicesProgram->isOk())
1810             throw tcu::TestError("Failed to compile data compute shader.");
1811     }
1812 
1813     // init parent
1814     ComputeShaderGeneratedCase::init();
1815 }
1816 
deinit(void)1817 void ComputeShaderGeneratedSeparateCase::deinit(void)
1818 {
1819     // deinit parent
1820     ComputeShaderGeneratedCase::deinit();
1821 
1822     if (m_computeCmdProgram)
1823     {
1824         delete m_computeCmdProgram;
1825         m_computeCmdProgram = DE_NULL;
1826     }
1827     if (m_computeDataProgram)
1828     {
1829         delete m_computeDataProgram;
1830         m_computeDataProgram = DE_NULL;
1831     }
1832     if (m_computeIndicesProgram)
1833     {
1834         delete m_computeIndicesProgram;
1835         m_computeIndicesProgram = DE_NULL;
1836     }
1837 }
1838 
genCmdComputeSource(void)1839 std::string ComputeShaderGeneratedSeparateCase::genCmdComputeSource(void)
1840 {
1841     return ComputeShaderGeneratedCase::genComputeSource(true, false, false);
1842 }
1843 
genDataComputeSource(void)1844 std::string ComputeShaderGeneratedSeparateCase::genDataComputeSource(void)
1845 {
1846     return ComputeShaderGeneratedCase::genComputeSource(false, true, false);
1847 }
1848 
genIndexComputeSource(void)1849 std::string ComputeShaderGeneratedSeparateCase::genIndexComputeSource(void)
1850 {
1851     return ComputeShaderGeneratedCase::genComputeSource(false, false, true);
1852 }
1853 
runComputeShader(void)1854 void ComputeShaderGeneratedSeparateCase::runComputeShader(void)
1855 {
1856     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1857 
1858     // Compute command
1859 
1860     if (m_computeCmd)
1861     {
1862         const int bindingPoint = 0;
1863         const tcu::IVec3 commandDispatchSize(m_numDrawCmds, 1, 1);
1864         const int bufferSize = m_commandSize * m_numDrawCmds;
1865 
1866         gl.useProgram(m_computeCmdProgram->getProgram());
1867 
1868         // setup buffers
1869 
1870         m_testCtx.getLog() << tcu::TestLog::Message << "Binding command buffer to binding point " << bindingPoint
1871                            << tcu::TestLog::EndMessage;
1872         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_cmdBufferID);
1873 
1874         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for command buffer, size "
1875                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1876         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1877 
1878         // calculate
1879 
1880         m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching command compute, size = " << commandDispatchSize
1881                            << tcu::TestLog::EndMessage;
1882         gl.dispatchCompute(commandDispatchSize.x(), commandDispatchSize.y(), commandDispatchSize.z());
1883 
1884         glu::checkError(gl.getError(), "calculate cmd", __FILE__, __LINE__);
1885     }
1886 
1887     // Compute data
1888 
1889     if (m_computeData)
1890     {
1891         const int bindingPoint = 0;
1892         const tcu::IVec3 drawElementsDataBufferDispatchSize(m_gridSize + 1, m_gridSize + 1, 1);
1893         const tcu::IVec3 drawArraysDataBufferDispatchSize(m_gridSize, m_gridSize, 1);
1894         const tcu::IVec3 dataBufferDispatchSize = (m_drawMethod == DRAWMETHOD_DRAWELEMENTS) ?
1895                                                       (drawElementsDataBufferDispatchSize) :
1896                                                       (drawArraysDataBufferDispatchSize);
1897         const int bufferSize                    = (int)(calcDrawBufferSize() * sizeof(tcu::Vec4));
1898 
1899         gl.useProgram(m_computeDataProgram->getProgram());
1900 
1901         // setup buffers
1902 
1903         m_testCtx.getLog() << tcu::TestLog::Message << "Binding data buffer to binding point " << bindingPoint
1904                            << tcu::TestLog::EndMessage;
1905         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_dataBufferID);
1906 
1907         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for data buffer, size "
1908                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1909         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1910 
1911         // calculate
1912 
1913         m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching data compute, size = " << dataBufferDispatchSize
1914                            << tcu::TestLog::EndMessage;
1915         gl.dispatchCompute(dataBufferDispatchSize.x(), dataBufferDispatchSize.y(), dataBufferDispatchSize.z());
1916 
1917         glu::checkError(gl.getError(), "calculate data", __FILE__, __LINE__);
1918     }
1919 
1920     // Compute indices
1921 
1922     if (m_computeIndices)
1923     {
1924         const int bindingPoint = 0;
1925         const tcu::IVec3 indexBufferDispatchSize(m_gridSize, m_gridSize, 1);
1926         const int bufferSize = (int)(calcIndexBufferSize() * sizeof(uint32_t));
1927 
1928         DE_ASSERT(m_drawMethod == DRAWMETHOD_DRAWELEMENTS);
1929 
1930         gl.useProgram(m_computeIndicesProgram->getProgram());
1931 
1932         // setup buffers
1933 
1934         m_testCtx.getLog() << tcu::TestLog::Message << "Binding index buffer to binding point " << bindingPoint
1935                            << tcu::TestLog::EndMessage;
1936         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, m_indexBufferID);
1937 
1938         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating memory for index buffer, size "
1939                            << sizeToString(bufferSize) << "." << tcu::TestLog::EndMessage;
1940         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_DRAW);
1941 
1942         // calculate
1943 
1944         m_testCtx.getLog() << tcu::TestLog::Message << "Dispatching index compute, size = " << indexBufferDispatchSize
1945                            << tcu::TestLog::EndMessage;
1946         gl.dispatchCompute(indexBufferDispatchSize.x(), indexBufferDispatchSize.y(), indexBufferDispatchSize.z());
1947 
1948         glu::checkError(gl.getError(), "calculate indices", __FILE__, __LINE__);
1949     }
1950 
1951     glu::checkError(gl.getError(), "post dispatch", __FILE__, __LINE__);
1952 }
1953 
1954 class ComputeShaderGeneratedGroup : public TestCaseGroup
1955 {
1956 public:
1957     ComputeShaderGeneratedGroup(Context &context, const char *name, const char *descr);
1958     ~ComputeShaderGeneratedGroup(void);
1959 
1960     void init(void);
1961 };
1962 
ComputeShaderGeneratedGroup(Context & context,const char * name,const char * descr)1963 ComputeShaderGeneratedGroup::ComputeShaderGeneratedGroup(Context &context, const char *name, const char *descr)
1964     : TestCaseGroup(context, name, descr)
1965 {
1966 }
1967 
~ComputeShaderGeneratedGroup(void)1968 ComputeShaderGeneratedGroup::~ComputeShaderGeneratedGroup(void)
1969 {
1970 }
1971 
init(void)1972 void ComputeShaderGeneratedGroup::init(void)
1973 {
1974     const int gridSize = 8;
1975     tcu::TestCaseGroup *const separateGroup =
1976         new tcu::TestCaseGroup(m_testCtx, "separate", "Use separate compute shaders for each buffer");
1977     tcu::TestCaseGroup *const combinedGroup =
1978         new tcu::TestCaseGroup(m_testCtx, "combined", "Use combined compute shader for all buffers");
1979     tcu::TestCaseGroup *const largeGroup = new tcu::TestCaseGroup(m_testCtx, "large", "Draw shapes with large buffers");
1980 
1981     this->addChild(separateGroup);
1982     this->addChild(combinedGroup);
1983     this->addChild(largeGroup);
1984 
1985     // .separate
1986     {
1987         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
1988             m_context, "drawarrays_compute_cmd", "Command from compute shader",
1989             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, false, false, gridSize, 1));
1990         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
1991             m_context, "drawarrays_compute_data", "Data from compute shader",
1992             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false, true, false, gridSize, 1));
1993         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
1994             m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader",
1995             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1));
1996 
1997         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
1998             m_context, "drawelements_compute_cmd", "Command from compute shader",
1999             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, false, gridSize, 1));
2000         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2001             m_context, "drawelements_compute_data", "Data from compute shader",
2002             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, false, gridSize, 1));
2003         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2004             m_context, "drawelements_compute_indices", "Indices from compute shader",
2005             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, false, true, gridSize, 1));
2006         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2007             m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader",
2008             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1));
2009         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2010             m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader",
2011             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1));
2012         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2013             m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader",
2014             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1));
2015         separateGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2016             m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader",
2017             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1));
2018     }
2019 
2020     // .combined
2021     {
2022         combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2023             m_context, "drawarrays_compute_cmd_and_data", "Command and data from compute shader",
2024             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true, true, false, gridSize, 1));
2025         combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2026             m_context, "drawelements_compute_cmd_and_data", "Command and data from compute shader",
2027             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, false, gridSize, 1));
2028         combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2029             m_context, "drawelements_compute_cmd_and_indices", "Command and indices from compute shader",
2030             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, false, true, gridSize, 1));
2031         combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2032             m_context, "drawelements_compute_data_and_indices", "Data and indices from compute shader",
2033             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false, true, true, gridSize, 1));
2034         combinedGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2035             m_context, "drawelements_compute_cmd_and_data_and_indices", "Command, data and indices from compute shader",
2036             ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true, true, true, gridSize, 1));
2037     }
2038 
2039     // .large
2040     {
2041         struct TestSpec
2042         {
2043             int gridSize;
2044             int numDrawCommands;
2045         };
2046         struct TestMethod
2047         {
2048             ComputeShaderGeneratedCase::DrawMethod method;
2049             bool separateCompute;
2050         };
2051 
2052         static const TestSpec specs[] = {
2053             {100, 1},  // !< drawArrays array size ~ 1.9 MB
2054             {200, 1},  // !< drawArrays array size ~ 7.7 MB
2055             {500, 1},  // !< drawArrays array size ~ 48 MB
2056             {1000, 1}, // !< drawArrays array size ~ 192 MB
2057             {1200, 1}, // !< drawArrays array size ~ 277 MB
2058             {1500, 1}, // !< drawArrays array size ~ 430 MB
2059 
2060             {100, 8},  // !< drawArrays array size ~ 1.9 MB
2061             {200, 8},  // !< drawArrays array size ~ 7.7 MB
2062             {500, 8},  // !< drawArrays array size ~ 48 MB
2063             {1000, 8}, // !< drawArrays array size ~ 192 MB
2064             {1200, 8}, // !< drawArrays array size ~ 277 MB
2065             {1500, 8}, // !< drawArrays array size ~ 430 MB
2066 
2067             {100, 200},   // !< 50 cells per draw call
2068             {200, 800},   // !< 50 cells per draw call
2069             {500, 2500},  // !< 100 cells per draw call
2070             {1000, 5000}, // !< 250 cells per draw call
2071         };
2072         static const TestMethod methods[] = {
2073             {ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, true},
2074             {ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS, false},
2075             {ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, true},
2076             {ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS, false},
2077         };
2078 
2079         for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(methods); ++methodNdx)
2080             for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); ++specNdx)
2081             {
2082                 const std::string name =
2083                     std::string("") +
2084                     ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ?
2085                          ("drawarrays") :
2086                          ("drawelements")) +
2087                     ((methods[methodNdx].separateCompute) ? ("_separate") : ("_combined")) + "_grid_" +
2088                     de::toString(specs[specNdx].gridSize) + "x" + de::toString(specs[specNdx].gridSize) +
2089                     "_drawcount_" + de::toString(specs[specNdx].numDrawCommands);
2090 
2091                 const std::string desc =
2092                     std::string("Draw grid with ") +
2093                     ((methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWARRAYS) ?
2094                          ("drawarrays indirect") :
2095                          ("drawelements indirect")) +
2096                     " calculating buffers in " + ((methods[methodNdx].separateCompute) ? ("separate") : ("combined")) +
2097                     " compute shader." + " Grid size is " + de::toString(specs[specNdx].gridSize) + "x" +
2098                     de::toString(specs[specNdx].gridSize) + ", draw count is " +
2099                     de::toString(specs[specNdx].numDrawCommands);
2100 
2101                 const bool computeIndices =
2102                     (methods[methodNdx].method == ComputeShaderGeneratedCase::DRAWMETHOD_DRAWELEMENTS);
2103 
2104                 if (methods[methodNdx].separateCompute)
2105                     largeGroup->addChild(new ComputeShaderGeneratedSeparateCase(
2106                         m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices,
2107                         specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2108                 else
2109                     largeGroup->addChild(new ComputeShaderGeneratedCombinedCase(
2110                         m_context, name.c_str(), desc.c_str(), methods[methodNdx].method, false, true, computeIndices,
2111                         specs[specNdx].gridSize, specs[specNdx].numDrawCommands));
2112             }
2113     }
2114 }
2115 
2116 class RandomGroup : public TestCaseGroup
2117 {
2118 public:
2119     RandomGroup(Context &context, const char *name, const char *descr);
2120     ~RandomGroup(void);
2121 
2122     void init(void);
2123 };
2124 
2125 template <int SIZE>
2126 struct UniformWeightArray
2127 {
2128     float weights[SIZE];
2129 
UniformWeightArraydeqp::gles31::Functional::__anone7c694fc0111::UniformWeightArray2130     UniformWeightArray(void)
2131     {
2132         for (int i = 0; i < SIZE; ++i)
2133             weights[i] = 1.0f;
2134     }
2135 };
2136 
RandomGroup(Context & context,const char * name,const char * descr)2137 RandomGroup::RandomGroup(Context &context, const char *name, const char *descr) : TestCaseGroup(context, name, descr)
2138 {
2139 }
2140 
~RandomGroup(void)2141 RandomGroup::~RandomGroup(void)
2142 {
2143 }
2144 
init(void)2145 void RandomGroup::init(void)
2146 {
2147     const int numAttempts = 100;
2148 
2149     const int attribCounts[]            = {1, 2, 5};
2150     const float attribWeights[]         = {30, 10, 1};
2151     const int primitiveCounts[]         = {1, 5, 64};
2152     const float primitiveCountWeights[] = {20, 10, 1};
2153     const int indexOffsets[]            = {0, 7, 13};
2154     const float indexOffsetWeights[]    = {20, 20, 1};
2155     const int firsts[]                  = {0, 7, 13};
2156     const float firstWeights[]          = {20, 20, 1};
2157 
2158     const int instanceCounts[]           = {1, 2, 16, 17};
2159     const float instanceWeights[]        = {20, 10, 5, 1};
2160     const int indexMins[]                = {0, 1, 3, 8};
2161     const int indexMaxs[]                = {4, 8, 128, 257};
2162     const float indexWeights[]           = {50, 50, 50, 50};
2163     const int offsets[]                  = {0, 1, 5, 12};
2164     const float offsetWeights[]          = {50, 10, 10, 10};
2165     const int strides[]                  = {0, 7, 16, 17};
2166     const float strideWeights[]          = {50, 10, 10, 10};
2167     const int instanceDivisors[]         = {0, 1, 3, 129};
2168     const float instanceDivisorWeights[] = {70, 30, 10, 10};
2169 
2170     const int indirectOffsets[]         = {0, 1, 2};
2171     const float indirectOffsetWeigths[] = {2, 1, 1};
2172     const int baseVertices[]            = {0, 1, -2, 4, 3};
2173     const float baseVertexWeigths[]     = {4, 1, 1, 1, 1};
2174 
2175     gls::DrawTestSpec::Primitive primitives[] = {
2176         gls::DrawTestSpec::PRIMITIVE_POINTS,       gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
2177         gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
2178         gls::DrawTestSpec::PRIMITIVE_LINES,        gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
2179         gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
2180     const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
2181 
2182     gls::DrawTestSpec::DrawMethod drawMethods[] = {
2183         gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2184         gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2185     };
2186     const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
2187 
2188     gls::DrawTestSpec::IndexType indexTypes[] = {
2189         gls::DrawTestSpec::INDEXTYPE_BYTE,
2190         gls::DrawTestSpec::INDEXTYPE_SHORT,
2191         gls::DrawTestSpec::INDEXTYPE_INT,
2192     };
2193     const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
2194 
2195     gls::DrawTestSpec::InputType inputTypes[] = {
2196         gls::DrawTestSpec::INPUTTYPE_FLOAT,
2197         gls::DrawTestSpec::INPUTTYPE_FIXED,
2198         gls::DrawTestSpec::INPUTTYPE_BYTE,
2199         gls::DrawTestSpec::INPUTTYPE_SHORT,
2200         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
2201         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
2202         gls::DrawTestSpec::INPUTTYPE_INT,
2203         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
2204         gls::DrawTestSpec::INPUTTYPE_HALF,
2205         gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2206         gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
2207     };
2208     const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
2209 
2210     gls::DrawTestSpec::OutputType outputTypes[] = {
2211         gls::DrawTestSpec::OUTPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2,  gls::DrawTestSpec::OUTPUTTYPE_VEC3,
2212         gls::DrawTestSpec::OUTPUTTYPE_VEC4,  gls::DrawTestSpec::OUTPUTTYPE_INT,   gls::DrawTestSpec::OUTPUTTYPE_UINT,
2213         gls::DrawTestSpec::OUTPUTTYPE_IVEC2, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
2214         gls::DrawTestSpec::OUTPUTTYPE_UVEC2, gls::DrawTestSpec::OUTPUTTYPE_UVEC3, gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
2215     };
2216     const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
2217 
2218     gls::DrawTestSpec::Usage usages[] = {
2219         gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, gls::DrawTestSpec::USAGE_STATIC_DRAW,
2220         gls::DrawTestSpec::USAGE_STREAM_DRAW,  gls::DrawTestSpec::USAGE_STREAM_READ,
2221         gls::DrawTestSpec::USAGE_STREAM_COPY,  gls::DrawTestSpec::USAGE_STATIC_READ,
2222         gls::DrawTestSpec::USAGE_STATIC_COPY,  gls::DrawTestSpec::USAGE_DYNAMIC_READ,
2223         gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
2224     };
2225     const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
2226 
2227     std::set<uint32_t> insertedHashes;
2228     size_t insertedCount         = 0;
2229     glu::ContextType contextType = m_context.getRenderContext().getType();
2230     glu::ApiType apiType         = glu::isContextTypeES(contextType) ? glu::ApiType::es(3, 1) : contextType.getAPI();
2231 
2232     for (int ndx = 0; ndx < numAttempts; ++ndx)
2233     {
2234         de::Random random(0xc551393 + ndx); // random does not depend on previous cases
2235 
2236         int attributeCount = random.chooseWeighted<int, const int *, const float *>(
2237             DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
2238         int drawCommandSize;
2239         gls::DrawTestSpec spec;
2240 
2241         spec.apiType   = apiType;
2242         spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive>(
2243             DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights);
2244         spec.primitiveCount = random.chooseWeighted<int, const int *, const float *>(
2245             DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights);
2246         spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod>(
2247             DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights);
2248 
2249         if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
2250             drawCommandSize = sizeof(uint32_t[4]);
2251         else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2252             drawCommandSize = sizeof(uint32_t[5]);
2253         else
2254         {
2255             DE_ASSERT(false);
2256             return;
2257         }
2258 
2259         spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType>(
2260             DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights);
2261         spec.indexPointerOffset = random.chooseWeighted<int, const int *, const float *>(
2262             DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights);
2263         spec.indexStorage  = gls::DrawTestSpec::STORAGE_BUFFER;
2264         spec.first         = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(firsts),
2265                                                                             DE_ARRAY_END(firsts), firstWeights);
2266         spec.indexMin      = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMins),
2267                                                                                DE_ARRAY_END(indexMins), indexWeights);
2268         spec.indexMax      = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMaxs),
2269                                                                                DE_ARRAY_END(indexMaxs), indexWeights);
2270         spec.instanceCount = random.chooseWeighted<int, const int *, const float *>(
2271             DE_ARRAY_BEGIN(instanceCounts), DE_ARRAY_END(instanceCounts), instanceWeights);
2272         spec.indirectOffset = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indirectOffsets),
2273                                                                                      DE_ARRAY_END(indirectOffsets),
2274                                                                                      indirectOffsetWeigths) *
2275                               drawCommandSize;
2276         spec.baseVertex = random.chooseWeighted<int, const int *, const float *>(
2277             DE_ARRAY_BEGIN(baseVertices), DE_ARRAY_END(baseVertices), baseVertexWeigths);
2278 
2279         // check spec is legal
2280         if (!spec.valid())
2281             continue;
2282 
2283         for (int attrNdx = 0; attrNdx < attributeCount;)
2284         {
2285             bool valid;
2286             gls::DrawTestSpec::AttributeSpec attribSpec;
2287 
2288             attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType>(
2289                 DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights);
2290             attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType>(
2291                 DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights);
2292             attribSpec.storage = gls::DrawTestSpec::STORAGE_BUFFER;
2293             attribSpec.usage   = random.chooseWeighted<gls::DrawTestSpec::Usage>(
2294                 DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights);
2295             attribSpec.componentCount = random.getInt(1, 4);
2296             attribSpec.offset         = random.chooseWeighted<int, const int *, const float *>(
2297                 DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
2298             attribSpec.stride = random.chooseWeighted<int, const int *, const float *>(
2299                 DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
2300             attribSpec.normalize       = random.getBool();
2301             attribSpec.instanceDivisor = random.chooseWeighted<int, const int *, const float *>(
2302                 DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
2303             attribSpec.useDefaultAttribute = random.getBool();
2304 
2305             // check spec is legal
2306             valid = attribSpec.valid(spec.apiType);
2307 
2308             // we do not want interleaved elements. (Might result in some weird floating point values)
2309             if (attribSpec.stride &&
2310                 attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
2311                 valid = false;
2312 
2313             // try again if not valid
2314             if (valid)
2315             {
2316                 spec.attribs.push_back(attribSpec);
2317                 ++attrNdx;
2318             }
2319         }
2320 
2321         // Do not collapse all vertex positions to a single positions
2322         if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2323             spec.attribs[0].instanceDivisor = 0;
2324 
2325         // Is render result meaningful?
2326         {
2327             // Only one vertex
2328             if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
2329                 spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2330                 continue;
2331             if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
2332                 continue;
2333 
2334             // Triangle only on one axis
2335             if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES ||
2336                 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN ||
2337                 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
2338             {
2339                 if (spec.attribs[0].componentCount == 1)
2340                     continue;
2341                 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT ||
2342                     spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT ||
2343                     spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT)
2344                     continue;
2345                 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
2346                     (spec.indexMax - spec.indexMin) < 2)
2347                     continue;
2348             }
2349         }
2350 
2351         // Add case
2352         {
2353             uint32_t hash = spec.hash();
2354             for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
2355                 hash = (hash << 2) ^ (uint32_t)spec.attribs[attrNdx].hash();
2356 
2357             if (insertedHashes.find(hash) == insertedHashes.end())
2358             {
2359                 // Only aligned cases
2360                 if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET &&
2361                     spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
2362                     this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec,
2363                                                      de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
2364                 insertedHashes.insert(hash);
2365 
2366                 ++insertedCount;
2367             }
2368         }
2369     }
2370 }
2371 
2372 class BadCommandBufferCase : public TestCase
2373 {
2374 public:
2375     enum
2376     {
2377         CommandSize = 20
2378     };
2379 
2380     BadCommandBufferCase(Context &context, const char *name, const char *desc, uint32_t alignment, uint32_t bufferSize,
2381                          bool writeCommandToBuffer, uint32_t m_expectedError);
2382     ~BadCommandBufferCase(void);
2383 
2384     IterateResult iterate(void);
2385 
2386 private:
2387     const uint32_t m_alignment;
2388     const uint32_t m_bufferSize;
2389     const bool m_writeCommandToBuffer;
2390     const uint32_t m_expectedError;
2391 };
2392 
BadCommandBufferCase(Context & context,const char * name,const char * desc,uint32_t alignment,uint32_t bufferSize,bool writeCommandToBuffer,uint32_t expectedError)2393 BadCommandBufferCase::BadCommandBufferCase(Context &context, const char *name, const char *desc, uint32_t alignment,
2394                                            uint32_t bufferSize, bool writeCommandToBuffer, uint32_t expectedError)
2395     : TestCase(context, name, desc)
2396     , m_alignment(alignment)
2397     , m_bufferSize(bufferSize)
2398     , m_writeCommandToBuffer(writeCommandToBuffer)
2399     , m_expectedError(expectedError)
2400 {
2401 }
2402 
~BadCommandBufferCase(void)2403 BadCommandBufferCase::~BadCommandBufferCase(void)
2404 {
2405 }
2406 
iterate(void)2407 BadCommandBufferCase::IterateResult BadCommandBufferCase::iterate(void)
2408 {
2409     const tcu::Vec4 vertexPositions[] = {
2410         tcu::Vec4(0, 0, 0, 1),
2411         tcu::Vec4(1, 0, 0, 1),
2412         tcu::Vec4(0, 1, 0, 1),
2413     };
2414 
2415     const uint16_t indices[] = {
2416         0,
2417         2,
2418         1,
2419     };
2420 
2421     DE_STATIC_ASSERT(CommandSize == sizeof(DrawElementsCommand));
2422 
2423     sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS,
2424                        tcu::IVec4(0, 0, 1, 1));
2425 
2426     uint32_t vaoID           = 0;
2427     uint32_t positionBuf     = 0;
2428     uint32_t indexBuf        = 0;
2429     uint32_t drawIndirectBuf = 0;
2430     uint32_t error;
2431 
2432     glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
2433                                                                  << glu::VertexSource(s_commonVertexShaderSource)
2434                                                                  << glu::FragmentSource(s_commonFragmentShaderSource));
2435     uint32_t programID  = program.getProgram();
2436     int32_t posLocation = gl.getAttribLocation(programID, "a_position");
2437 
2438     DrawElementsCommand drawCommand;
2439     drawCommand.count              = 3;
2440     drawCommand.primCount          = 1;
2441     drawCommand.firstIndex         = 0;
2442     drawCommand.baseVertex         = 0;
2443     drawCommand.reservedMustBeZero = 0;
2444 
2445     std::vector<int8_t> drawCommandBuffer;
2446     drawCommandBuffer.resize(m_bufferSize);
2447 
2448     deMemset(&drawCommandBuffer[0], 0, (int)drawCommandBuffer.size());
2449 
2450     if (m_writeCommandToBuffer)
2451     {
2452         DE_ASSERT(drawCommandBuffer.size() >= sizeof(drawCommand) + m_alignment);
2453         deMemcpy(&drawCommandBuffer[m_alignment], &drawCommand, sizeof(drawCommand));
2454     }
2455 
2456     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2457     gl.genVertexArrays(1, &vaoID);
2458     gl.bindVertexArray(vaoID);
2459 
2460     gl.genBuffers(1, &positionBuf);
2461     gl.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
2462     gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2463     gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2464     gl.vertexAttribDivisor(posLocation, 0);
2465     gl.enableVertexAttribArray(posLocation);
2466     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2467 
2468     gl.genBuffers(1, &indexBuf);
2469     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
2470     gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2471     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2472 
2473     gl.genBuffers(1, &drawIndirectBuf);
2474     gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuf);
2475     gl.bufferData(GL_DRAW_INDIRECT_BUFFER, drawCommandBuffer.size(), &drawCommandBuffer[0], GL_STATIC_DRAW);
2476     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2477 
2478     gl.viewport(0, 0, 1, 1);
2479 
2480     gl.useProgram(programID);
2481     gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void *)(uintptr_t)m_alignment);
2482 
2483     error = gl.getError();
2484 
2485     gl.useProgram(0);
2486 
2487     gl.deleteBuffers(1, &drawIndirectBuf);
2488     gl.deleteBuffers(1, &indexBuf);
2489     gl.deleteBuffers(1, &positionBuf);
2490     gl.deleteVertexArrays(1, &vaoID);
2491 
2492     m_testCtx.getLog() << tcu::TestLog::Message << "drawElementsIndirect generated " << glu::getErrorStr(error)
2493                        << ", expecting " << glu::getErrorStr(m_expectedError) << "." << tcu::TestLog::EndMessage;
2494 
2495     if (error == m_expectedError)
2496         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2497     else
2498     {
2499         m_testCtx.getLog() << tcu::TestLog::Message << "\tUnexpected error." << tcu::TestLog::EndMessage;
2500         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2501     }
2502 
2503     return STOP;
2504 }
2505 
2506 class BadAlignmentCase : public BadCommandBufferCase
2507 {
2508 public:
2509     BadAlignmentCase(Context &context, const char *name, const char *desc, uint32_t alignment);
2510     ~BadAlignmentCase(void);
2511 };
2512 
BadAlignmentCase(Context & context,const char * name,const char * desc,uint32_t alignment)2513 BadAlignmentCase::BadAlignmentCase(Context &context, const char *name, const char *desc, uint32_t alignment)
2514     : BadCommandBufferCase(context, name, desc, alignment, CommandSize + alignment, true, GL_INVALID_VALUE)
2515 {
2516 }
2517 
~BadAlignmentCase(void)2518 BadAlignmentCase::~BadAlignmentCase(void)
2519 {
2520 }
2521 
2522 class BadBufferRangeCase : public BadCommandBufferCase
2523 {
2524 public:
2525     BadBufferRangeCase(Context &context, const char *name, const char *desc, uint32_t offset);
2526     ~BadBufferRangeCase(void);
2527 };
2528 
BadBufferRangeCase(Context & context,const char * name,const char * desc,uint32_t offset)2529 BadBufferRangeCase::BadBufferRangeCase(Context &context, const char *name, const char *desc, uint32_t offset)
2530     : BadCommandBufferCase(context, name, desc, offset, CommandSize, false, GL_INVALID_OPERATION)
2531 {
2532 }
2533 
~BadBufferRangeCase(void)2534 BadBufferRangeCase::~BadBufferRangeCase(void)
2535 {
2536 }
2537 
2538 class BadStateCase : public TestCase
2539 {
2540 public:
2541     enum CaseType
2542     {
2543         CASE_CLIENT_BUFFER_VERTEXATTR = 0,
2544         CASE_CLIENT_BUFFER_COMMAND,
2545         CASE_DEFAULT_VAO,
2546 
2547         CASE_CLIENT_LAST
2548     };
2549 
2550     BadStateCase(Context &context, const char *name, const char *desc, CaseType type);
2551     ~BadStateCase(void);
2552 
2553     void init(void);
2554     void deinit(void);
2555     IterateResult iterate(void);
2556 
2557 private:
2558     const CaseType m_caseType;
2559 };
2560 
BadStateCase(Context & context,const char * name,const char * desc,CaseType type)2561 BadStateCase::BadStateCase(Context &context, const char *name, const char *desc, CaseType type)
2562     : TestCase(context, name, desc)
2563     , m_caseType(type)
2564 {
2565     DE_ASSERT(type < CASE_CLIENT_LAST);
2566 }
2567 
~BadStateCase(void)2568 BadStateCase::~BadStateCase(void)
2569 {
2570     deinit();
2571 }
2572 
init(void)2573 void BadStateCase::init(void)
2574 {
2575     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
2576     {
2577         if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR)
2578             throw tcu::NotSupportedError(
2579                 "The negative test for vertex attrib array in the client memory is not supported in the GL context");
2580         if (m_caseType == CASE_DEFAULT_VAO)
2581             throw tcu::NotSupportedError(
2582                 "The negative test for use with default vao is not supported in the GL context");
2583     }
2584 }
2585 
deinit(void)2586 void BadStateCase::deinit(void)
2587 {
2588 }
2589 
iterate(void)2590 BadStateCase::IterateResult BadStateCase::iterate(void)
2591 {
2592     const tcu::Vec4 vertexPositions[] = {
2593         tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2594         tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2595         tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2596     };
2597 
2598     const uint16_t indices[] = {
2599         0,
2600         2,
2601         1,
2602     };
2603 
2604     sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS,
2605                        tcu::IVec4(0, 0, 1, 1));
2606 
2607     uint32_t error;
2608     glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
2609                                                                  << glu::VertexSource(s_commonVertexShaderSource)
2610                                                                  << glu::FragmentSource(s_commonFragmentShaderSource));
2611     uint32_t vaoID         = 0;
2612     uint32_t dataBufferID  = 0;
2613     uint32_t indexBufferID = 0;
2614     uint32_t cmdBufferID   = 0;
2615 
2616     const uint32_t programID  = program.getProgram();
2617     const int32_t posLocation = gl.getAttribLocation(programID, "a_position");
2618 
2619     DrawElementsCommand drawCommand;
2620     drawCommand.count              = 3;
2621     drawCommand.primCount          = 1;
2622     drawCommand.firstIndex         = 0;
2623     drawCommand.baseVertex         = 0;
2624     drawCommand.reservedMustBeZero = 0;
2625 
2626     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2627 
2628     if (m_caseType == CASE_CLIENT_BUFFER_VERTEXATTR)
2629     {
2630         // \note We use default VAO since we use client pointers. Trying indirect draw with default VAO is also an error. => This test does two illegal operations
2631 
2632         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, vertexPositions);
2633         gl.enableVertexAttribArray(posLocation);
2634         glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2635     }
2636     else if (m_caseType == CASE_CLIENT_BUFFER_COMMAND)
2637     {
2638         gl.genVertexArrays(1, &vaoID);
2639         gl.bindVertexArray(vaoID);
2640 
2641         gl.genBuffers(1, &dataBufferID);
2642         gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2643         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2644         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2645         gl.enableVertexAttribArray(posLocation);
2646         glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2647     }
2648     else if (m_caseType == CASE_DEFAULT_VAO)
2649     {
2650         gl.genBuffers(1, &dataBufferID);
2651         gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2652         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2653         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2654         gl.enableVertexAttribArray(posLocation);
2655         glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2656     }
2657     else
2658         DE_ASSERT(false);
2659 
2660     gl.genBuffers(1, &indexBufferID);
2661     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2662     gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2663     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2664 
2665     if (m_caseType != CASE_CLIENT_BUFFER_COMMAND)
2666     {
2667         gl.genBuffers(1, &cmdBufferID);
2668         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2669         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2670         glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2671     }
2672 
2673     gl.viewport(0, 0, 1, 1);
2674 
2675     gl.useProgram(programID);
2676     gl.drawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT,
2677                             (m_caseType != CASE_CLIENT_BUFFER_COMMAND) ? (DE_NULL) : (&drawCommand));
2678 
2679     error = gl.getError();
2680 
2681     gl.bindVertexArray(0);
2682     gl.useProgram(0);
2683 
2684     if (error == GL_INVALID_OPERATION)
2685         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2686     else
2687     {
2688         m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_OPERATION, got "
2689                            << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2690         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2691     }
2692 
2693     return STOP;
2694 }
2695 
2696 class BadDrawModeCase : public TestCase
2697 {
2698 public:
2699     enum DrawType
2700     {
2701         DRAW_ARRAYS = 0,
2702         DRAW_ELEMENTS,
2703         DRAW_ELEMENTS_BAD_INDEX,
2704 
2705         DRAW_LAST
2706     };
2707 
2708     BadDrawModeCase(Context &context, const char *name, const char *desc, DrawType type);
2709     ~BadDrawModeCase(void);
2710 
2711     void init(void);
2712     void deinit(void);
2713     IterateResult iterate(void);
2714 
2715 private:
2716     const DrawType m_drawType;
2717 };
2718 
BadDrawModeCase(Context & context,const char * name,const char * desc,DrawType type)2719 BadDrawModeCase::BadDrawModeCase(Context &context, const char *name, const char *desc, DrawType type)
2720     : TestCase(context, name, desc)
2721     , m_drawType(type)
2722 {
2723     DE_ASSERT(type < DRAW_LAST);
2724 }
2725 
~BadDrawModeCase(void)2726 BadDrawModeCase::~BadDrawModeCase(void)
2727 {
2728     deinit();
2729 }
2730 
init(void)2731 void BadDrawModeCase::init(void)
2732 {
2733 }
2734 
deinit(void)2735 void BadDrawModeCase::deinit(void)
2736 {
2737 }
2738 
iterate(void)2739 BadDrawModeCase::IterateResult BadDrawModeCase::iterate(void)
2740 {
2741     const tcu::Vec4 vertexPositions[] = {
2742         tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
2743         tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2744         tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2745     };
2746 
2747     const uint16_t indices[] = {
2748         0,
2749         2,
2750         1,
2751     };
2752 
2753     sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS,
2754                        tcu::IVec4(0, 0, 1, 1));
2755 
2756     uint32_t error;
2757     glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
2758                                                                  << glu::VertexSource(s_commonVertexShaderSource)
2759                                                                  << glu::FragmentSource(s_commonFragmentShaderSource));
2760     uint32_t vaoID         = 0;
2761     uint32_t dataBufferID  = 0;
2762     uint32_t indexBufferID = 0;
2763     uint32_t cmdBufferID   = 0;
2764 
2765     const uint32_t programID    = program.getProgram();
2766     const int32_t posLocation   = gl.getAttribLocation(programID, "a_position");
2767     const glw::GLenum mode      = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (GL_TRIANGLES) : (0x123);
2768     const glw::GLenum indexType = (m_drawType == DRAW_ELEMENTS_BAD_INDEX) ? (0x123) : (GL_UNSIGNED_SHORT);
2769 
2770     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2771 
2772     // vao
2773 
2774     gl.genVertexArrays(1, &vaoID);
2775     gl.bindVertexArray(vaoID);
2776 
2777     // va
2778 
2779     gl.genBuffers(1, &dataBufferID);
2780     gl.bindBuffer(GL_ARRAY_BUFFER, dataBufferID);
2781     gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
2782     gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2783     gl.enableVertexAttribArray(posLocation);
2784     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2785 
2786     // index
2787 
2788     if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2789     {
2790         gl.genBuffers(1, &indexBufferID);
2791         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
2792         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2793         glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2794     }
2795 
2796     // cmd
2797 
2798     gl.genBuffers(1, &cmdBufferID);
2799     gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBufferID);
2800     if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2801     {
2802         DrawElementsCommand drawCommand;
2803         drawCommand.count              = 3;
2804         drawCommand.primCount          = 1;
2805         drawCommand.firstIndex         = 0;
2806         drawCommand.baseVertex         = 0;
2807         drawCommand.reservedMustBeZero = 0;
2808 
2809         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2810     }
2811     else if (m_drawType == DRAW_ARRAYS)
2812     {
2813         DrawArraysCommand drawCommand;
2814         drawCommand.count              = 3;
2815         drawCommand.primCount          = 1;
2816         drawCommand.first              = 0;
2817         drawCommand.reservedMustBeZero = 0;
2818 
2819         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
2820     }
2821     else
2822         DE_ASSERT(false);
2823     glu::checkError(gl.getError(), "", __FILE__, __LINE__);
2824 
2825     gl.viewport(0, 0, 1, 1);
2826     gl.useProgram(programID);
2827     if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
2828         gl.drawElementsIndirect(mode, indexType, DE_NULL);
2829     else if (m_drawType == DRAW_ARRAYS)
2830         gl.drawArraysIndirect(mode, DE_NULL);
2831     else
2832         DE_ASSERT(false);
2833 
2834     error = gl.getError();
2835     gl.useProgram(0);
2836 
2837     if (error == GL_INVALID_ENUM)
2838         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2839     else
2840     {
2841         m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error. Expected GL_INVALID_ENUM, got "
2842                            << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
2843         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error.");
2844     }
2845 
2846     return STOP;
2847 }
2848 
2849 class NegativeGroup : public TestCaseGroup
2850 {
2851 public:
2852     NegativeGroup(Context &context, const char *name, const char *descr);
2853     ~NegativeGroup(void);
2854 
2855     void init(void);
2856 };
2857 
NegativeGroup(Context & context,const char * name,const char * descr)2858 NegativeGroup::NegativeGroup(Context &context, const char *name, const char *descr)
2859     : TestCaseGroup(context, name, descr)
2860 {
2861 }
2862 
~NegativeGroup(void)2863 NegativeGroup::~NegativeGroup(void)
2864 {
2865 }
2866 
init(void)2867 void NegativeGroup::init(void)
2868 {
2869     // invalid alignment
2870     addChild(new BadAlignmentCase(m_context, "command_bad_alignment_1", "Bad command alignment", 1));
2871     addChild(new BadAlignmentCase(m_context, "command_bad_alignment_2", "Bad command alignment", 2));
2872     addChild(new BadAlignmentCase(m_context, "command_bad_alignment_3", "Bad command alignment", 3));
2873 
2874     // command only partially or not at all in the buffer
2875     addChild(new BadBufferRangeCase(m_context, "command_offset_partially_in_buffer",
2876                                     "Command not fully in the buffer range", BadBufferRangeCase::CommandSize - 16));
2877     addChild(new BadBufferRangeCase(m_context, "command_offset_not_in_buffer", "Command not in the buffer range",
2878                                     BadBufferRangeCase::CommandSize));
2879     addChild(new BadBufferRangeCase(m_context, "command_offset_not_in_buffer_unsigned32_wrap",
2880                                     "Command not in the buffer range", 0xFFFFFFFC));
2881     addChild(new BadBufferRangeCase(m_context, "command_offset_not_in_buffer_signed32_wrap",
2882                                     "Command not in the buffer range", 0x7FFFFFFC));
2883 
2884     // use with client data and default vao
2885     addChild(new BadStateCase(m_context, "client_vertex_attrib_array", "Vertex attrib array in the client memory",
2886                               BadStateCase::CASE_CLIENT_BUFFER_VERTEXATTR));
2887     addChild(new BadStateCase(m_context, "client_command_array", "Command array in the client memory",
2888                               BadStateCase::CASE_CLIENT_BUFFER_COMMAND));
2889     addChild(new BadStateCase(m_context, "default_vao", "Use with default vao", BadStateCase::CASE_DEFAULT_VAO));
2890 
2891     // invalid mode & type
2892     addChild(new BadDrawModeCase(m_context, "invalid_mode_draw_arrays", "Call DrawArraysIndirect with bad mode",
2893                                  BadDrawModeCase::DRAW_ARRAYS));
2894     addChild(new BadDrawModeCase(m_context, "invalid_mode_draw_elements", "Call DrawelementsIndirect with bad mode",
2895                                  BadDrawModeCase::DRAW_ELEMENTS));
2896     addChild(new BadDrawModeCase(m_context, "invalid_type_draw_elements", "Call DrawelementsIndirect with bad type",
2897                                  BadDrawModeCase::DRAW_ELEMENTS_BAD_INDEX));
2898 }
2899 
2900 } // namespace
2901 
DrawTests(Context & context)2902 DrawTests::DrawTests(Context &context) : TestCaseGroup(context, "draw_indirect", "Indirect drawing tests")
2903 {
2904 }
2905 
~DrawTests(void)2906 DrawTests::~DrawTests(void)
2907 {
2908 }
2909 
init(void)2910 void DrawTests::init(void)
2911 {
2912     // Basic
2913     {
2914         const gls::DrawTestSpec::DrawMethod basicMethods[] = {
2915             gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
2916             gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
2917         };
2918 
2919         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
2920         {
2921             const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2922             const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
2923 
2924             this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
2925         }
2926     }
2927 
2928     // extreme instancing
2929 
2930     this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count."));
2931 
2932     // compute shader generated commands
2933 
2934     this->addChild(new ComputeShaderGeneratedGroup(m_context, "compute_interop",
2935                                                    "draw tests with a draw command generated in compute shader."));
2936 
2937     // Random
2938 
2939     this->addChild(new RandomGroup(m_context, "random", "random draw commands."));
2940 
2941     // negative
2942 
2943     this->addChild(new NegativeGroup(m_context, "negative", "invalid draw commands with defined error codes."));
2944 }
2945 
2946 } // namespace Functional
2947 } // namespace gles31
2948 } // namespace deqp
2949