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