1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Drawing tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fDrawTests.hpp"
25 #include "glsDrawTest.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "sglrGLContext.hpp"
28 #include "glwEnums.hpp"
29 #include "deRandom.hpp"
30 #include "deStringUtil.hpp"
31 #include "deUniquePtr.hpp"
32 #include "deSTLUtil.hpp"
33
34 #include <set>
35
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 namespace
43 {
44
45 enum TestIterationType
46 {
47 TYPE_DRAW_COUNT, // !< test with 1, 5, and 25 primitives
48 TYPE_INSTANCE_COUNT, // !< test with 1, 4, and 11 instances
49 TYPE_INDEX_RANGE, // !< test with index range of [0, 23], [23, 40], and [5, 5]
50
51 TYPE_LAST
52 };
53
addTestIterations(gls::DrawTest * test,const gls::DrawTestSpec & baseSpec,TestIterationType type)54 static void addTestIterations(gls::DrawTest *test, const gls::DrawTestSpec &baseSpec, TestIterationType type)
55 {
56 gls::DrawTestSpec spec(baseSpec);
57
58 if (type == TYPE_DRAW_COUNT)
59 {
60 spec.primitiveCount = 1;
61 test->addIteration(spec, "draw count = 1");
62
63 spec.primitiveCount = 5;
64 test->addIteration(spec, "draw count = 5");
65
66 spec.primitiveCount = 25;
67 test->addIteration(spec, "draw count = 25");
68 }
69 else if (type == TYPE_INSTANCE_COUNT)
70 {
71 spec.instanceCount = 1;
72 test->addIteration(spec, "instance count = 1");
73
74 spec.instanceCount = 4;
75 test->addIteration(spec, "instance count = 4");
76
77 spec.instanceCount = 11;
78 test->addIteration(spec, "instance count = 11");
79 }
80 else if (type == TYPE_INDEX_RANGE)
81 {
82 spec.indexMin = 0;
83 spec.indexMax = 23;
84 test->addIteration(spec, "index range = [0, 23]");
85
86 spec.indexMin = 23;
87 spec.indexMax = 40;
88 test->addIteration(spec, "index range = [23, 40]");
89
90 // Only makes sense with points
91 if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_POINTS)
92 {
93 spec.indexMin = 5;
94 spec.indexMax = 5;
95 test->addIteration(spec, "index range = [5, 5]");
96 }
97 }
98 else
99 DE_ASSERT(false);
100 }
101
genBasicSpec(gls::DrawTestSpec & spec,gls::DrawTestSpec::DrawMethod method)102 static void genBasicSpec(gls::DrawTestSpec &spec, gls::DrawTestSpec::DrawMethod method)
103 {
104 spec.apiType = glu::ApiType::es(3, 0);
105 spec.primitive = gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
106 spec.primitiveCount = 5;
107 spec.drawMethod = method;
108 spec.indexType = gls::DrawTestSpec::INDEXTYPE_LAST;
109 spec.indexPointerOffset = 0;
110 spec.indexStorage = gls::DrawTestSpec::STORAGE_LAST;
111 spec.first = 0;
112 spec.indexMin = 0;
113 spec.indexMax = 0;
114 spec.instanceCount = 1;
115
116 spec.attribs.resize(2);
117
118 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
119 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
120 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER;
121 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
122 spec.attribs[0].componentCount = 4;
123 spec.attribs[0].offset = 0;
124 spec.attribs[0].stride = 0;
125 spec.attribs[0].normalize = false;
126 spec.attribs[0].instanceDivisor = 0;
127 spec.attribs[0].useDefaultAttribute = false;
128
129 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
130 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
131 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER;
132 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
133 spec.attribs[1].componentCount = 2;
134 spec.attribs[1].offset = 0;
135 spec.attribs[1].stride = 0;
136 spec.attribs[1].normalize = false;
137 spec.attribs[1].instanceDivisor = 0;
138 spec.attribs[1].useDefaultAttribute = false;
139 }
140
141 class AttributeGroup : public TestCaseGroup
142 {
143 public:
144 AttributeGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod,
145 gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType,
146 gls::DrawTestSpec::Storage indexStorage);
147 ~AttributeGroup(void);
148
149 void init(void);
150
151 private:
152 gls::DrawTestSpec::DrawMethod m_method;
153 gls::DrawTestSpec::Primitive m_primitive;
154 gls::DrawTestSpec::IndexType m_indexType;
155 gls::DrawTestSpec::Storage m_indexStorage;
156 };
157
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)158 AttributeGroup::AttributeGroup(Context &context, const char *name, const char *descr,
159 gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive,
160 gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage)
161 : TestCaseGroup(context, name, descr)
162 , m_method(drawMethod)
163 , m_primitive(primitive)
164 , m_indexType(indexType)
165 , m_indexStorage(indexStorage)
166 {
167 }
168
~AttributeGroup(void)169 AttributeGroup::~AttributeGroup(void)
170 {
171 }
172
init(void)173 void AttributeGroup::init(void)
174 {
175 // select test type
176 const bool instanced = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED) ||
177 (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED);
178 const bool ranged = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
179 const TestIterationType testType =
180 (instanced) ? (TYPE_INSTANCE_COUNT) : ((ranged) ? (TYPE_INDEX_RANGE) : (TYPE_DRAW_COUNT));
181
182 // Single attribute
183 {
184 gls::DrawTest *test =
185 new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
186 gls::DrawTestSpec spec;
187
188 spec.apiType = glu::ApiType::es(3, 0);
189 spec.primitive = m_primitive;
190 spec.primitiveCount = 5;
191 spec.drawMethod = m_method;
192 spec.indexType = m_indexType;
193 spec.indexPointerOffset = 0;
194 spec.indexStorage = m_indexStorage;
195 spec.first = 0;
196 spec.indexMin = 0;
197 spec.indexMax = 0;
198 spec.instanceCount = 1;
199
200 spec.attribs.resize(1);
201
202 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
203 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
204 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER;
205 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
206 spec.attribs[0].componentCount = 2;
207 spec.attribs[0].offset = 0;
208 spec.attribs[0].stride = 0;
209 spec.attribs[0].normalize = false;
210 spec.attribs[0].instanceDivisor = 0;
211 spec.attribs[0].useDefaultAttribute = false;
212
213 addTestIterations(test, spec, testType);
214
215 this->addChild(test);
216 }
217
218 // Multiple attribute
219 {
220 gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes",
221 "Multiple attribute arrays.");
222 gls::DrawTestSpec spec;
223
224 spec.apiType = glu::ApiType::es(3, 0);
225 spec.primitive = m_primitive;
226 spec.primitiveCount = 5;
227 spec.drawMethod = m_method;
228 spec.indexType = m_indexType;
229 spec.indexPointerOffset = 0;
230 spec.indexStorage = m_indexStorage;
231 spec.first = 0;
232 spec.indexMin = 0;
233 spec.indexMax = 0;
234 spec.instanceCount = 1;
235
236 spec.attribs.resize(2);
237
238 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
239 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
240 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER;
241 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
242 spec.attribs[0].componentCount = 4;
243 spec.attribs[0].offset = 0;
244 spec.attribs[0].stride = 0;
245 spec.attribs[0].normalize = false;
246 spec.attribs[0].instanceDivisor = 0;
247 spec.attribs[0].useDefaultAttribute = false;
248
249 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
250 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
251 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER;
252 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
253 spec.attribs[1].componentCount = 2;
254 spec.attribs[1].offset = 0;
255 spec.attribs[1].stride = 0;
256 spec.attribs[1].normalize = false;
257 spec.attribs[1].instanceDivisor = 0;
258 spec.attribs[1].useDefaultAttribute = false;
259
260 addTestIterations(test, spec, testType);
261
262 this->addChild(test);
263 }
264
265 // Multiple attribute, second one divided
266 {
267 gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes",
268 "Instanced attribute array.");
269 gls::DrawTestSpec spec;
270
271 spec.apiType = glu::ApiType::es(3, 0);
272 spec.primitive = m_primitive;
273 spec.primitiveCount = 5;
274 spec.drawMethod = m_method;
275 spec.indexType = m_indexType;
276 spec.indexPointerOffset = 0;
277 spec.indexStorage = m_indexStorage;
278 spec.first = 0;
279 spec.indexMin = 0;
280 spec.indexMax = 0;
281 spec.instanceCount = 1;
282
283 spec.attribs.resize(3);
284
285 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
286 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
287 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER;
288 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
289 spec.attribs[0].componentCount = 4;
290 spec.attribs[0].offset = 0;
291 spec.attribs[0].stride = 0;
292 spec.attribs[0].normalize = false;
293 spec.attribs[0].instanceDivisor = 0;
294 spec.attribs[0].useDefaultAttribute = false;
295
296 // Add another position component so the instances wont be drawn on each other
297 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
298 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
299 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER;
300 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
301 spec.attribs[1].componentCount = 2;
302 spec.attribs[1].offset = 0;
303 spec.attribs[1].stride = 0;
304 spec.attribs[1].normalize = false;
305 spec.attribs[1].instanceDivisor = 1;
306 spec.attribs[1].useDefaultAttribute = false;
307 spec.attribs[1].additionalPositionAttribute = true;
308
309 // Instanced color
310 spec.attribs[2].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
311 spec.attribs[2].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
312 spec.attribs[2].storage = gls::DrawTestSpec::STORAGE_BUFFER;
313 spec.attribs[2].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
314 spec.attribs[2].componentCount = 3;
315 spec.attribs[2].offset = 0;
316 spec.attribs[2].stride = 0;
317 spec.attribs[2].normalize = false;
318 spec.attribs[2].instanceDivisor = 1;
319 spec.attribs[2].useDefaultAttribute = false;
320
321 addTestIterations(test, spec, testType);
322
323 this->addChild(test);
324 }
325
326 // Multiple attribute, second one default
327 {
328 gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute",
329 "Attribute specified with glVertexAttrib*.");
330 gls::DrawTestSpec spec;
331
332 spec.apiType = glu::ApiType::es(3, 0);
333 spec.primitive = m_primitive;
334 spec.primitiveCount = 5;
335 spec.drawMethod = m_method;
336 spec.indexType = m_indexType;
337 spec.indexPointerOffset = 0;
338 spec.indexStorage = m_indexStorage;
339 spec.first = 0;
340 spec.indexMin = 0;
341 spec.indexMax =
342 20; // \note addTestIterations is not called for the spec, so we must ensure [indexMin, indexMax] is a good range
343 spec.instanceCount = 1;
344
345 spec.attribs.resize(2);
346
347 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT;
348 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2;
349 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER;
350 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
351 spec.attribs[0].componentCount = 2;
352 spec.attribs[0].offset = 0;
353 spec.attribs[0].stride = 0;
354 spec.attribs[0].normalize = false;
355 spec.attribs[0].instanceDivisor = 0;
356 spec.attribs[0].useDefaultAttribute = false;
357
358 struct IOPair
359 {
360 gls::DrawTestSpec::InputType input;
361 gls::DrawTestSpec::OutputType output;
362 int componentCount;
363 } iopairs[] = {
364 {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, 4},
365 {gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2},
366 {gls::DrawTestSpec::INPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4},
367 {gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4},
368 };
369
370 for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
371 {
372 const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) +
373 de::toString(iopairs[ioNdx].componentCount) + " to " +
374 gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
375
376 spec.attribs[1].inputType = iopairs[ioNdx].input;
377 spec.attribs[1].outputType = iopairs[ioNdx].output;
378 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER;
379 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW;
380 spec.attribs[1].componentCount = iopairs[ioNdx].componentCount;
381 spec.attribs[1].offset = 0;
382 spec.attribs[1].stride = 0;
383 spec.attribs[1].normalize = false;
384 spec.attribs[1].instanceDivisor = 0;
385 spec.attribs[1].useDefaultAttribute = true;
386
387 test->addIteration(spec, desc.c_str());
388 }
389
390 this->addChild(test);
391 }
392 }
393
394 class IndexGroup : public TestCaseGroup
395 {
396 public:
397 IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
398 ~IndexGroup(void);
399
400 void init(void);
401
402 private:
403 gls::DrawTestSpec::DrawMethod m_method;
404 };
405
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)406 IndexGroup::IndexGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod)
407 : TestCaseGroup(context, name, descr)
408 , m_method(drawMethod)
409 {
410 }
411
~IndexGroup(void)412 IndexGroup::~IndexGroup(void)
413 {
414 }
415
init(void)416 void IndexGroup::init(void)
417 {
418 struct IndexTest
419 {
420 gls::DrawTestSpec::Storage storage;
421 gls::DrawTestSpec::IndexType type;
422 bool aligned;
423 int offsets[3];
424 };
425
426 const IndexTest tests[] = {
427 {gls::DrawTestSpec::STORAGE_USER, gls::DrawTestSpec::INDEXTYPE_BYTE, true, {0, 1, -1}},
428 {gls::DrawTestSpec::STORAGE_USER, gls::DrawTestSpec::INDEXTYPE_SHORT, true, {0, 2, -1}},
429 {gls::DrawTestSpec::STORAGE_USER, gls::DrawTestSpec::INDEXTYPE_INT, true, {0, 4, -1}},
430
431 {gls::DrawTestSpec::STORAGE_USER, gls::DrawTestSpec::INDEXTYPE_SHORT, false, {1, 3, -1}},
432 {gls::DrawTestSpec::STORAGE_USER, gls::DrawTestSpec::INDEXTYPE_INT, false, {2, 3, -1}},
433
434 {gls::DrawTestSpec::STORAGE_BUFFER, gls::DrawTestSpec::INDEXTYPE_BYTE, true, {0, 1, -1}},
435 {gls::DrawTestSpec::STORAGE_BUFFER, gls::DrawTestSpec::INDEXTYPE_SHORT, true, {0, 2, -1}},
436 {gls::DrawTestSpec::STORAGE_BUFFER, gls::DrawTestSpec::INDEXTYPE_INT, true, {0, 4, -1}},
437 };
438
439 gls::DrawTestSpec spec;
440
441 tcu::TestCaseGroup *userPtrGroup = new tcu::TestCaseGroup(m_testCtx, "user_ptr", "user pointer");
442 tcu::TestCaseGroup *unalignedUserPtrGroup =
443 new tcu::TestCaseGroup(m_testCtx, "unaligned_user_ptr", "unaligned user pointer");
444 tcu::TestCaseGroup *bufferGroup = new tcu::TestCaseGroup(m_testCtx, "buffer", "buffer");
445
446 genBasicSpec(spec, m_method);
447
448 this->addChild(userPtrGroup);
449 this->addChild(unalignedUserPtrGroup);
450 this->addChild(bufferGroup);
451
452 for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
453 {
454 const IndexTest &indexTest = tests[testNdx];
455 tcu::TestCaseGroup *group = (indexTest.storage == gls::DrawTestSpec::STORAGE_USER) ?
456 ((indexTest.aligned) ? (userPtrGroup) : (unalignedUserPtrGroup)) :
457 ((indexTest.aligned) ? (bufferGroup) : (DE_NULL));
458
459 const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
460 const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " +
461 gls::DrawTestSpec::storageToString(indexTest.storage);
462 de::MovePtr<gls::DrawTest> test(
463 new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()));
464
465 spec.indexType = indexTest.type;
466 spec.indexStorage = indexTest.storage;
467
468 for (int iterationNdx = 0;
469 iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1;
470 ++iterationNdx)
471 {
472 const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]);
473 spec.indexPointerOffset = indexTest.offsets[iterationNdx];
474 test->addIteration(spec, iterationDesc.c_str());
475 }
476
477 DE_ASSERT(spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET);
478 DE_ASSERT(spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE);
479 group->addChild(test.release());
480 }
481 }
482
483 class FirstGroup : public TestCaseGroup
484 {
485 public:
486 FirstGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
487 ~FirstGroup(void);
488
489 void init(void);
490
491 private:
492 gls::DrawTestSpec::DrawMethod m_method;
493 };
494
FirstGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)495 FirstGroup::FirstGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod)
496 : TestCaseGroup(context, name, descr)
497 , m_method(drawMethod)
498 {
499 }
500
~FirstGroup(void)501 FirstGroup::~FirstGroup(void)
502 {
503 }
504
init(void)505 void FirstGroup::init(void)
506 {
507 const int firsts[] = {1, 3, 17};
508
509 gls::DrawTestSpec spec;
510 genBasicSpec(spec, m_method);
511
512 for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); ++firstNdx)
513 {
514 const std::string name = std::string("first_") + de::toString(firsts[firstNdx]);
515 const std::string desc = std::string("first ") + de::toString(firsts[firstNdx]);
516 gls::DrawTest *test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
517
518 spec.first = firsts[firstNdx];
519
520 addTestIterations(test, spec, TYPE_DRAW_COUNT);
521
522 this->addChild(test);
523 }
524 }
525
526 class MethodGroup : public TestCaseGroup
527 {
528 public:
529 MethodGroup(Context &context, const char *name, const char *descr, gls::DrawTestSpec::DrawMethod drawMethod);
530 ~MethodGroup(void);
531
532 void init(void);
533
534 private:
535 gls::DrawTestSpec::DrawMethod m_method;
536 };
537
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)538 MethodGroup::MethodGroup(Context &context, const char *name, const char *descr,
539 gls::DrawTestSpec::DrawMethod drawMethod)
540 : TestCaseGroup(context, name, descr)
541 , m_method(drawMethod)
542 {
543 }
544
~MethodGroup(void)545 MethodGroup::~MethodGroup(void)
546 {
547 }
548
init(void)549 void MethodGroup::init(void)
550 {
551 const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) ||
552 (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) ||
553 (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
554 const bool hasFirst = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS) ||
555 (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED);
556
557 const gls::DrawTestSpec::Primitive primitive[] = {
558 gls::DrawTestSpec::PRIMITIVE_POINTS, gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
559 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
560 gls::DrawTestSpec::PRIMITIVE_LINES, gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
561 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
562
563 if (hasFirst)
564 {
565 // First-tests
566 this->addChild(new FirstGroup(m_context, "first", "First tests", m_method));
567 }
568
569 if (indexed)
570 {
571 // Index-tests
572 if (m_method != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
573 this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
574 }
575
576 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
577 {
578 const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
579 const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
580
581 this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx],
582 gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
583 }
584 }
585
586 class GridProgram : public sglr::ShaderProgram
587 {
588 public:
589 GridProgram(void);
590
591 void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
592 void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
593 const rr::FragmentShadingContext &context) const;
594 };
595
GridProgram(void)596 GridProgram::GridProgram(void)
597 : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
598 << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
599 << sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
600 << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
601 << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
602 << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
603 << sglr::pdec::VertexSource("#version 300 es\n"
604 "in highp vec4 a_position;\n"
605 "in highp vec4 a_offset;\n"
606 "in highp vec4 a_color;\n"
607 "out mediump vec4 v_color;\n"
608 "void main(void)\n"
609 "{\n"
610 " gl_Position = a_position + a_offset;\n"
611 " v_color = a_color;\n"
612 "}\n")
613 << sglr::pdec::FragmentSource("#version 300 es\n"
614 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
615 "in mediump vec4 v_color;\n"
616 "void main(void)\n"
617 "{\n"
618 " dEQP_FragColor = v_color;\n"
619 "}\n"))
620 {
621 }
622
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const623 void GridProgram::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
624 const int numPackets) const
625 {
626 for (int ndx = 0; ndx < numPackets; ++ndx)
627 {
628 packets[ndx]->position =
629 rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
630 rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
631 packets[ndx]->outputs[0] =
632 rr::readVertexAttribFloat(inputs[2], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
633 }
634 }
635
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const636 void GridProgram::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
637 const rr::FragmentShadingContext &context) const
638 {
639 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
640 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
641 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
642 rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
643 }
644
645 class InstancedGridRenderTest : public TestCase
646 {
647 public:
648 InstancedGridRenderTest(Context &context, const char *name, const char *desc, int gridSide, bool useIndices);
649 ~InstancedGridRenderTest(void);
650
651 IterateResult iterate(void);
652
653 private:
654 void renderTo(sglr::Context &ctx, sglr::ShaderProgram &program, tcu::Surface &dst);
655 bool verifyImage(const tcu::Surface &image);
656
657 const int m_gridSide;
658 const bool m_useIndices;
659 };
660
InstancedGridRenderTest(Context & context,const char * name,const char * desc,int gridSide,bool useIndices)661 InstancedGridRenderTest::InstancedGridRenderTest(Context &context, const char *name, const char *desc, int gridSide,
662 bool useIndices)
663 : TestCase(context, name, desc)
664 , m_gridSide(gridSide)
665 , m_useIndices(useIndices)
666 {
667 }
668
~InstancedGridRenderTest(void)669 InstancedGridRenderTest::~InstancedGridRenderTest(void)
670 {
671 }
672
iterate(void)673 InstancedGridRenderTest::IterateResult InstancedGridRenderTest::iterate(void)
674 {
675 const int renderTargetWidth = de::min(1024, m_context.getRenderTarget().getWidth());
676 const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight());
677
678 sglr::GLContext ctx(m_context.getRenderContext(), m_testCtx.getLog(),
679 sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS,
680 tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
681 tcu::Surface surface(renderTargetWidth, renderTargetHeight);
682 GridProgram program;
683
684 // render
685
686 renderTo(ctx, program, surface);
687
688 // verify image
689
690 if (verifyImage(surface))
691 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
692 else
693 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering result");
694 return STOP;
695 }
696
renderTo(sglr::Context & ctx,sglr::ShaderProgram & program,tcu::Surface & dst)697 void InstancedGridRenderTest::renderTo(sglr::Context &ctx, sglr::ShaderProgram &program, tcu::Surface &dst)
698 {
699 const tcu::Vec4 green(0, 1, 0, 1);
700 const tcu::Vec4 yellow(1, 1, 0, 1);
701
702 uint32_t positionBuf = 0;
703 uint32_t offsetBuf = 0;
704 uint32_t colorBuf = 0;
705 uint32_t indexBuf = 0;
706 uint32_t programID = ctx.createProgram(&program);
707 int32_t posLocation = ctx.getAttribLocation(programID, "a_position");
708 int32_t offsetLocation = ctx.getAttribLocation(programID, "a_offset");
709 int32_t colorLocation = ctx.getAttribLocation(programID, "a_color");
710
711 float cellW = 2.0f / (float)m_gridSide;
712 float cellH = 2.0f / (float)m_gridSide;
713 const tcu::Vec4 vertexPositions[] = {
714 tcu::Vec4(0, 0, 0, 1), tcu::Vec4(cellW, 0, 0, 1), tcu::Vec4(0, cellH, 0, 1),
715
716 tcu::Vec4(0, cellH, 0, 1), tcu::Vec4(cellW, 0, 0, 1), tcu::Vec4(cellW, cellH, 0, 1),
717 };
718
719 const uint16_t indices[] = {0, 4, 3, 2, 1, 5};
720
721 std::vector<tcu::Vec4> offsets;
722 for (int x = 0; x < m_gridSide; ++x)
723 for (int y = 0; y < m_gridSide; ++y)
724 offsets.push_back(tcu::Vec4((float)x * cellW - 1.0f, (float)y * cellW - 1.0f, 0, 0));
725
726 std::vector<tcu::Vec4> colors;
727 for (int x = 0; x < m_gridSide; ++x)
728 for (int y = 0; y < m_gridSide; ++y)
729 colors.push_back(((x + y) % 2 == 0) ? (green) : (yellow));
730
731 ctx.genBuffers(1, &positionBuf);
732 ctx.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
733 ctx.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
734 ctx.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
735 ctx.vertexAttribDivisor(posLocation, 0);
736 ctx.enableVertexAttribArray(posLocation);
737
738 ctx.genBuffers(1, &offsetBuf);
739 ctx.bindBuffer(GL_ARRAY_BUFFER, offsetBuf);
740 ctx.bufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(tcu::Vec4), &offsets[0], GL_STATIC_DRAW);
741 ctx.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
742 ctx.vertexAttribDivisor(offsetLocation, 1);
743 ctx.enableVertexAttribArray(offsetLocation);
744
745 ctx.genBuffers(1, &colorBuf);
746 ctx.bindBuffer(GL_ARRAY_BUFFER, colorBuf);
747 ctx.bufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(tcu::Vec4), &colors[0], GL_STATIC_DRAW);
748 ctx.vertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
749 ctx.vertexAttribDivisor(colorLocation, 1);
750 ctx.enableVertexAttribArray(colorLocation);
751
752 if (m_useIndices)
753 {
754 ctx.genBuffers(1, &indexBuf);
755 ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
756 ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
757 }
758
759 ctx.clearColor(0, 0, 0, 1);
760 ctx.clear(GL_COLOR_BUFFER_BIT);
761
762 ctx.viewport(0, 0, dst.getWidth(), dst.getHeight());
763
764 ctx.useProgram(programID);
765 if (m_useIndices)
766 ctx.drawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL, m_gridSide * m_gridSide);
767 else
768 ctx.drawArraysInstanced(GL_TRIANGLES, 0, 6, m_gridSide * m_gridSide);
769 ctx.useProgram(0);
770
771 if (m_useIndices)
772 ctx.deleteBuffers(1, &indexBuf);
773 ctx.deleteBuffers(1, &colorBuf);
774 ctx.deleteBuffers(1, &offsetBuf);
775 ctx.deleteBuffers(1, &positionBuf);
776 ctx.deleteProgram(programID);
777
778 ctx.finish();
779 ctx.readPixels(dst, 0, 0, dst.getWidth(), dst.getHeight());
780
781 glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
782 }
783
verifyImage(const tcu::Surface & image)784 bool InstancedGridRenderTest::verifyImage(const tcu::Surface &image)
785 {
786 // \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.
787 using tcu::TestLog;
788
789 const int colorThreshold = 20;
790
791 tcu::Surface error(image.getWidth(), image.getHeight());
792 bool isOk = true;
793
794 for (int y = 0; y < image.getHeight(); y++)
795 for (int x = 0; x < image.getWidth(); x++)
796 {
797 if (x == 0 || y == 0 || y + 1 == image.getHeight() || x + 1 == image.getWidth())
798 {
799 // Background color might bleed in at the borders with msaa
800 error.setPixel(x, y, tcu::RGBA(0, 255, 0, 255));
801 }
802 else
803 {
804 const tcu::RGBA pixel = image.getPixel(x, y);
805 bool pixelOk = true;
806
807 // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
808 if (de::abs(pixel.getGreen() - 255) > colorThreshold)
809 pixelOk = false;
810
811 // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
812 if (de::abs(pixel.getBlue() - 0) > colorThreshold)
813 pixelOk = false;
814
815 error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
816 isOk = isOk && pixelOk;
817 }
818 }
819
820 if (!isOk)
821 {
822 tcu::TestLog &log = m_testCtx.getLog();
823
824 log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
825 log << TestLog::ImageSet("Verfication result", "Result of rendering")
826 << TestLog::Image("Result", "Result", image) << TestLog::Image("ErrorMask", "Error mask", error)
827 << TestLog::EndImageSet;
828 }
829 else
830 {
831 tcu::TestLog &log = m_testCtx.getLog();
832
833 log << TestLog::ImageSet("Verfication result", "Result of rendering")
834 << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet;
835 }
836
837 return isOk;
838 }
839
840 class InstancingGroup : public TestCaseGroup
841 {
842 public:
843 InstancingGroup(Context &context, const char *name, const char *descr);
844 ~InstancingGroup(void);
845
846 void init(void);
847 };
848
InstancingGroup(Context & context,const char * name,const char * descr)849 InstancingGroup::InstancingGroup(Context &context, const char *name, const char *descr)
850 : TestCaseGroup(context, name, descr)
851 {
852 }
853
~InstancingGroup(void)854 InstancingGroup::~InstancingGroup(void)
855 {
856 }
857
init(void)858 void InstancingGroup::init(void)
859 {
860 const int gridWidths[] = {
861 2, 5, 10, 32, 100,
862 };
863
864 // drawArrays
865 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
866 {
867 const std::string name = std::string("draw_arrays_instanced_grid_") + de::toString(gridWidths[ndx]) + "x" +
868 de::toString(gridWidths[ndx]);
869 const std::string desc = std::string("DrawArraysInstanced, Grid size ") + de::toString(gridWidths[ndx]) + "x" +
870 de::toString(gridWidths[ndx]);
871
872 this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], false));
873 }
874
875 // drawElements
876 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
877 {
878 const std::string name = std::string("draw_elements_instanced_grid_") + de::toString(gridWidths[ndx]) + "x" +
879 de::toString(gridWidths[ndx]);
880 const std::string desc = std::string("DrawElementsInstanced, Grid size ") + de::toString(gridWidths[ndx]) +
881 "x" + de::toString(gridWidths[ndx]);
882
883 this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], true));
884 }
885 }
886
887 class RandomGroup : public TestCaseGroup
888 {
889 public:
890 RandomGroup(Context &context, const char *name, const char *descr);
891 ~RandomGroup(void);
892
893 void init(void);
894 };
895
896 template <int SIZE>
897 struct UniformWeightArray
898 {
899 float weights[SIZE];
900
UniformWeightArraydeqp::gles3::Functional::__anon99d5a21a0111::UniformWeightArray901 UniformWeightArray(void)
902 {
903 for (int i = 0; i < SIZE; ++i)
904 weights[i] = 1.0f;
905 }
906 };
907
RandomGroup(Context & context,const char * name,const char * descr)908 RandomGroup::RandomGroup(Context &context, const char *name, const char *descr) : TestCaseGroup(context, name, descr)
909 {
910 }
911
~RandomGroup(void)912 RandomGroup::~RandomGroup(void)
913 {
914 }
915
init(void)916 void RandomGroup::init(void)
917 {
918 const int numAttempts = 300;
919
920 static const int attribCounts[] = {1, 2, 5};
921 static const float attribWeights[] = {30, 10, 1};
922 static const int primitiveCounts[] = {1, 5, 64};
923 static const float primitiveCountWeights[] = {20, 10, 1};
924 static const int indexOffsets[] = {0, 7, 13};
925 static const float indexOffsetWeights[] = {20, 20, 1};
926 static const int firsts[] = {0, 7, 13};
927 static const float firstWeights[] = {20, 20, 1};
928 static const int instanceCounts[] = {1, 2, 16, 17};
929 static const float instanceWeights[] = {20, 10, 5, 1};
930 static const int indexMins[] = {0, 1, 3, 8};
931 static const int indexMaxs[] = {4, 8, 128, 257};
932 static const float indexWeights[] = {50, 50, 50, 50};
933 static const int offsets[] = {0, 1, 5, 12};
934 static const float offsetWeights[] = {50, 10, 10, 10};
935 static const int strides[] = {0, 7, 16, 17};
936 static const float strideWeights[] = {50, 10, 10, 10};
937 static const int instanceDivisors[] = {0, 1, 3, 129};
938 static const float instanceDivisorWeights[] = {70, 30, 10, 10};
939
940 static const gls::DrawTestSpec::Primitive primitives[] = {
941 gls::DrawTestSpec::PRIMITIVE_POINTS, gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
942 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
943 gls::DrawTestSpec::PRIMITIVE_LINES, gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
944 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP};
945 const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
946
947 static const gls::DrawTestSpec::DrawMethod drawMethods[] = {
948 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS, gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED,
949 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS, gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
950 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED};
951 const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
952
953 static const gls::DrawTestSpec::IndexType indexTypes[] = {
954 gls::DrawTestSpec::INDEXTYPE_BYTE,
955 gls::DrawTestSpec::INDEXTYPE_SHORT,
956 gls::DrawTestSpec::INDEXTYPE_INT,
957 };
958 const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
959
960 static const gls::DrawTestSpec::Storage storages[] = {
961 gls::DrawTestSpec::STORAGE_USER,
962 gls::DrawTestSpec::STORAGE_BUFFER,
963 };
964 const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights;
965
966 static const gls::DrawTestSpec::InputType inputTypes[] = {
967 gls::DrawTestSpec::INPUTTYPE_FLOAT,
968 gls::DrawTestSpec::INPUTTYPE_FIXED,
969 gls::DrawTestSpec::INPUTTYPE_BYTE,
970 gls::DrawTestSpec::INPUTTYPE_SHORT,
971 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
972 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
973 gls::DrawTestSpec::INPUTTYPE_INT,
974 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
975 gls::DrawTestSpec::INPUTTYPE_HALF,
976 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
977 gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
978 };
979 const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
980
981 static const gls::DrawTestSpec::OutputType outputTypes[] = {
982 gls::DrawTestSpec::OUTPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, gls::DrawTestSpec::OUTPUTTYPE_VEC3,
983 gls::DrawTestSpec::OUTPUTTYPE_VEC4, gls::DrawTestSpec::OUTPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_UINT,
984 gls::DrawTestSpec::OUTPUTTYPE_IVEC2, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
985 gls::DrawTestSpec::OUTPUTTYPE_UVEC2, gls::DrawTestSpec::OUTPUTTYPE_UVEC3, gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
986 };
987 const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
988
989 static const gls::DrawTestSpec::Usage usages[] = {
990 gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, gls::DrawTestSpec::USAGE_STATIC_DRAW,
991 gls::DrawTestSpec::USAGE_STREAM_DRAW, gls::DrawTestSpec::USAGE_STREAM_READ,
992 gls::DrawTestSpec::USAGE_STREAM_COPY, gls::DrawTestSpec::USAGE_STATIC_READ,
993 gls::DrawTestSpec::USAGE_STATIC_COPY, gls::DrawTestSpec::USAGE_DYNAMIC_READ,
994 gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
995 };
996 const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
997
998 static const uint32_t disallowedCases[] = {
999 544, //!< extremely narrow triangle
1000 };
1001
1002 std::set<uint32_t> insertedHashes;
1003 size_t insertedCount = 0;
1004
1005 for (int ndx = 0; ndx < numAttempts; ++ndx)
1006 {
1007 de::Random random(0xc551393 + ndx); // random does not depend on previous cases
1008
1009 int attributeCount = random.chooseWeighted<int, const int *, const float *>(
1010 DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
1011 gls::DrawTestSpec spec;
1012
1013 spec.apiType = glu::ApiType::es(3, 0);
1014 spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive>(
1015 DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights);
1016 spec.primitiveCount = random.chooseWeighted<int, const int *, const float *>(
1017 DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights);
1018 spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod>(
1019 DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights);
1020 spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType>(
1021 DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights);
1022 spec.indexPointerOffset = random.chooseWeighted<int, const int *, const float *>(
1023 DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights);
1024 spec.indexStorage = random.chooseWeighted<gls::DrawTestSpec::Storage>(
1025 DE_ARRAY_BEGIN(storages), DE_ARRAY_END(storages), storageWeights.weights);
1026 spec.first = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(firsts),
1027 DE_ARRAY_END(firsts), firstWeights);
1028 spec.indexMin = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMins),
1029 DE_ARRAY_END(indexMins), indexWeights);
1030 spec.indexMax = random.chooseWeighted<int, const int *, const float *>(DE_ARRAY_BEGIN(indexMaxs),
1031 DE_ARRAY_END(indexMaxs), indexWeights);
1032 spec.instanceCount = random.chooseWeighted<int, const int *, const float *>(
1033 DE_ARRAY_BEGIN(instanceCounts), DE_ARRAY_END(instanceCounts), instanceWeights);
1034
1035 // check spec is legal
1036 if (!spec.valid())
1037 continue;
1038
1039 for (int attrNdx = 0; attrNdx < attributeCount;)
1040 {
1041 bool valid;
1042 gls::DrawTestSpec::AttributeSpec attribSpec;
1043
1044 attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType>(
1045 DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights);
1046 attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType>(
1047 DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights);
1048 attribSpec.storage = random.chooseWeighted<gls::DrawTestSpec::Storage>(
1049 DE_ARRAY_BEGIN(storages), DE_ARRAY_END(storages), storageWeights.weights);
1050 attribSpec.usage = random.chooseWeighted<gls::DrawTestSpec::Usage>(
1051 DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights);
1052 attribSpec.componentCount = random.getInt(1, 4);
1053 attribSpec.offset = random.chooseWeighted<int, const int *, const float *>(
1054 DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
1055 attribSpec.stride = random.chooseWeighted<int, const int *, const float *>(
1056 DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
1057 attribSpec.normalize = random.getBool();
1058 attribSpec.instanceDivisor = random.chooseWeighted<int, const int *, const float *>(
1059 DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
1060 attribSpec.useDefaultAttribute = random.getBool();
1061
1062 // check spec is legal
1063 valid = attribSpec.valid(spec.apiType);
1064
1065 // we do not want interleaved elements. (Might result in some weird floating point values)
1066 if (attribSpec.stride &&
1067 attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
1068 valid = false;
1069
1070 // try again if not valid
1071 if (valid)
1072 {
1073 spec.attribs.push_back(attribSpec);
1074 ++attrNdx;
1075 }
1076 }
1077
1078 // Do not collapse all vertex positions to a single positions
1079 if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1080 spec.attribs[0].instanceDivisor = 0;
1081
1082 // Is render result meaningful?
1083 {
1084 // Only one vertex
1085 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
1086 spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1087 continue;
1088 if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1089 continue;
1090
1091 // Triangle only on one axis
1092 if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES ||
1093 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN ||
1094 spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
1095 {
1096 if (spec.attribs[0].componentCount == 1)
1097 continue;
1098 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT ||
1099 spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT ||
1100 spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT)
1101 continue;
1102 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED &&
1103 (spec.indexMax - spec.indexMin) < 2)
1104 continue;
1105 }
1106 }
1107
1108 // Add case
1109 {
1110 uint32_t hash = spec.hash();
1111 for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
1112 hash = (hash << 2) ^ (uint32_t)spec.attribs[attrNdx].hash();
1113
1114 if (insertedHashes.find(hash) == insertedHashes.end())
1115 {
1116 // Only properly aligned and not disallowed cases
1117 if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET &&
1118 spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE &&
1119 !de::contains(DE_ARRAY_BEGIN(disallowedCases), DE_ARRAY_END(disallowedCases), hash))
1120 {
1121 this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec,
1122 de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
1123 }
1124 insertedHashes.insert(hash);
1125
1126 ++insertedCount;
1127 }
1128 }
1129 }
1130 }
1131
1132 } // namespace
1133
DrawTests(Context & context)1134 DrawTests::DrawTests(Context &context) : TestCaseGroup(context, "draw", "Drawing tests")
1135 {
1136 }
1137
~DrawTests(void)1138 DrawTests::~DrawTests(void)
1139 {
1140 }
1141
init(void)1142 void DrawTests::init(void)
1143 {
1144 // Basic
1145 {
1146 const gls::DrawTestSpec::DrawMethod basicMethods[] = {
1147 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS, gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
1148 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED, gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED,
1149 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
1150 };
1151
1152 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
1153 {
1154 const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
1155 const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
1156
1157 this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
1158 }
1159 }
1160
1161 // extreme instancing
1162
1163 this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count."));
1164
1165 // Random
1166
1167 this->addChild(new RandomGroup(m_context, "random", "random draw commands."));
1168 }
1169
1170 } // namespace Functional
1171 } // namespace gles3
1172 } // namespace deqp
1173