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