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