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