1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Instanced rendering tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fInstancedRenderingTests.hpp"
25 #include "gluPixelTransfer.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluShaderUtil.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuSurface.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuVector.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "deRandom.hpp"
34 #include "deStringUtil.hpp"
35 #include "deString.h"
36
37 #include "glw.h"
38
39 using std::vector;
40 using std::string;
41
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Functional
47 {
48
49 static const int MAX_RENDER_WIDTH = 128;
50 static const int MAX_RENDER_HEIGHT = 128;
51
52 static const int QUAD_GRID_SIZE = 127;
53
54 // Attribute divisors for the attributes defining the color's RGB components.
55 static const int ATTRIB_DIVISOR_R = 3;
56 static const int ATTRIB_DIVISOR_G = 2;
57 static const int ATTRIB_DIVISOR_B = 1;
58
59 static const int OFFSET_COMPONENTS = 3; // \note Affects whether a float or a vecN is used in shader, but only first component is non-zero.
60
61 // Scale and bias values when converting float to integer, when attribute is of integer type.
62 static const float FLOAT_INT_SCALE = 100.0f;
63 static const float FLOAT_INT_BIAS = -50.0f;
64 static const float FLOAT_UINT_SCALE = 100.0f;
65 static const float FLOAT_UINT_BIAS = 0.0f;
66
67 // \note Non-anonymous namespace needed; VarComp is used as a template parameter.
68 namespace vcns
69 {
70
71 union VarComp
72 {
73 float f32;
74 deUint32 u32;
75 deInt32 i32;
76
VarComp(float v)77 VarComp(float v) : f32(v) {}
VarComp(deUint32 v)78 VarComp(deUint32 v) : u32(v) {}
VarComp(deInt32 v)79 VarComp(deInt32 v) : i32(v) {}
80 };
81 DE_STATIC_ASSERT(sizeof(VarComp) == sizeof(deUint32));
82
83 } // vcns
84
85 using namespace vcns;
86
87 class InstancedRenderingCase : public TestCase
88 {
89 public:
90 enum DrawFunction
91 {
92 FUNCTION_DRAW_ARRAYS_INSTANCED = 0,
93 FUNCTION_DRAW_ELEMENTS_INSTANCED,
94
95 FUNCTION_LAST
96 };
97
98 enum InstancingType
99 {
100 TYPE_INSTANCE_ID = 0,
101 TYPE_ATTRIB_DIVISOR,
102 TYPE_MIXED,
103
104 TYPE_LAST
105 };
106
107 InstancedRenderingCase (Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances);
108 ~InstancedRenderingCase (void);
109
110 void init (void);
111 void deinit (void);
112 IterateResult iterate (void);
113
114 private:
115 InstancedRenderingCase (const InstancedRenderingCase& other);
116 InstancedRenderingCase& operator= (const InstancedRenderingCase& other);
117
118 void pushVarCompAttrib (vector<VarComp>& vec, float val);
119
120 void setupVarAttribPointer (const void* attrPtr, int startLocation, int divisor);
121 void setupAndRender (void);
122 void computeReference (tcu::Surface& dst);
123
124 DrawFunction m_function;
125 InstancingType m_instancingType;
126 glu::DataType m_rgbAttrType; // \note Instance attribute types, color components only. Position offset attribute is always float/vecN.
127 int m_numInstances;
128
129 vector<float> m_gridVertexPositions; // X and Y components per vertex.
130 vector<deUint16> m_gridIndices; // \note Only used if m_function is FUNCTION_DRAW_ELEMENTS_INSTANCED.
131
132 // \note Some or all of the following instance attribute parameters may be unused with TYPE_INSTANCE_ID or TYPE_MIXED.
133 vector<float> m_instanceOffsets; // Position offsets. OFFSET_COMPONENTS components per offset.
134 // Attribute data for float, int or uint (or respective vector types) color components.
135 vector<VarComp> m_instanceColorR;
136 vector<VarComp> m_instanceColorG;
137 vector<VarComp> m_instanceColorB;
138
139 glu::ShaderProgram* m_program;
140 };
141
InstancedRenderingCase(Context & context,const char * name,const char * description,DrawFunction function,InstancingType instancingType,glu::DataType rgbAttrType,int numInstances)142 InstancedRenderingCase::InstancedRenderingCase (Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances)
143 : TestCase (context, name, description)
144 , m_function (function)
145 , m_instancingType (instancingType)
146 , m_rgbAttrType (rgbAttrType)
147 , m_numInstances (numInstances)
148 , m_program (DE_NULL)
149 {
150 }
151
~InstancedRenderingCase(void)152 InstancedRenderingCase::~InstancedRenderingCase (void)
153 {
154 InstancedRenderingCase::deinit();
155 }
156
157 // Helper function that does biasing and scaling when converting float to integer.
pushVarCompAttrib(vector<VarComp> & vec,float val)158 void InstancedRenderingCase::pushVarCompAttrib (vector<VarComp>& vec, float val)
159 {
160 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType);
161 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType);
162 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType);
163 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType);
164
165 if (isFloatCase || isMatCase)
166 vec.push_back(VarComp(val));
167 else if (isIntCase)
168 vec.push_back(VarComp((deInt32)(val*FLOAT_INT_SCALE + FLOAT_INT_BIAS)));
169 else if (isUintCase)
170 vec.push_back(VarComp((deUint32)(val*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS)));
171 else
172 DE_ASSERT(DE_FALSE);
173 }
174
init(void)175 void InstancedRenderingCase::init (void)
176 {
177 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType);
178 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType);
179 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType);
180 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType);
181 int typeSize = glu::getDataTypeScalarSize(m_rgbAttrType);
182 bool isScalarCase = typeSize == 1;
183 string swizzleFirst = isScalarCase ? "" : ".x";
184 string typeName = glu::getDataTypeName(m_rgbAttrType);
185
186 string floatIntScaleStr = "(" + de::floatToString(FLOAT_INT_SCALE, 3) + ")";
187 string floatIntBiasStr = "(" + de::floatToString(FLOAT_INT_BIAS, 3) + ")";
188 string floatUintScaleStr = "(" + de::floatToString(FLOAT_UINT_SCALE, 3) + ")";
189 string floatUintBiasStr = "(" + de::floatToString(FLOAT_UINT_BIAS, 3) + ")";
190
191 DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase);
192
193 // Generate shader.
194 // \note For case TYPE_MIXED, vertex position offset and color red component get their values from instance id, while green and blue get their values from instanced attributes.
195
196 string numInstancesStr = de::toString(m_numInstances) + ".0";
197
198 string instanceAttribs;
199 string posExpression;
200 string colorRExpression;
201 string colorGExpression;
202 string colorBExpression;
203
204 if (m_instancingType == TYPE_INSTANCE_ID || m_instancingType == TYPE_MIXED)
205 {
206 posExpression = "a_position + vec4(float(gl_InstanceID) * 2.0 / " + numInstancesStr + ", 0.0, 0.0, 0.0)";
207 colorRExpression = "float(gl_InstanceID)/" + numInstancesStr;
208
209 if (m_instancingType == TYPE_INSTANCE_ID)
210 {
211 colorGExpression = "float(gl_InstanceID)*2.0/" + numInstancesStr;
212 colorBExpression = "1.0 - float(gl_InstanceID)/" + numInstancesStr;
213 }
214 }
215
216 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
217 {
218 if (m_instancingType == TYPE_ATTRIB_DIVISOR)
219 {
220 posExpression = "a_position + vec4(a_instanceOffset";
221
222 DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4);
223
224 for (int i = 0; i < 4-OFFSET_COMPONENTS; i++)
225 posExpression += ", 0.0";
226 posExpression += ")";
227
228 if (isFloatCase)
229 colorRExpression = "a_instanceR" + swizzleFirst;
230 else if (isIntCase)
231 colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
232 else if (isUintCase)
233 colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
234 else if (isMatCase)
235 colorRExpression = "a_instanceR[0][0]";
236 else
237 DE_ASSERT(DE_FALSE);
238
239 instanceAttribs += "in highp " + (OFFSET_COMPONENTS == 1 ? string("float") : "vec" + de::toString(OFFSET_COMPONENTS)) + " a_instanceOffset;\n";
240 instanceAttribs += "in mediump " + typeName + " a_instanceR;\n";
241 }
242
243 if (isFloatCase)
244 {
245 colorGExpression = "a_instanceG" + swizzleFirst;
246 colorBExpression = "a_instanceB" + swizzleFirst;
247 }
248 else if (isIntCase)
249 {
250 colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
251 colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
252 }
253 else if (isUintCase)
254 {
255 colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
256 colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
257 }
258 else if (isMatCase)
259 {
260 colorGExpression = "a_instanceG[0][0]";
261 colorBExpression = "a_instanceB[0][0]";
262 }
263 else
264 DE_ASSERT(DE_FALSE);
265
266 instanceAttribs += "in mediump " + typeName + " a_instanceG;\n";
267 instanceAttribs += "in mediump " + typeName + " a_instanceB;\n";
268 }
269
270 DE_ASSERT(!posExpression.empty());
271 DE_ASSERT(!colorRExpression.empty());
272 DE_ASSERT(!colorGExpression.empty());
273 DE_ASSERT(!colorBExpression.empty());
274
275 std::string vertShaderSourceStr =
276 "#version 300 es\n"
277 "in highp vec4 a_position;\n" +
278 instanceAttribs +
279 "out mediump vec4 v_color;\n"
280 "\n"
281 "void main()\n"
282 "{\n"
283 " gl_Position = " + posExpression + ";\n"
284 " v_color.r = " + colorRExpression + ";\n"
285 " v_color.g = " + colorGExpression + ";\n"
286 " v_color.b = " + colorBExpression + ";\n"
287 " v_color.a = 1.0;\n"
288 "}\n";
289
290 static const char* fragShaderSource =
291 "#version 300 es\n"
292 "layout(location = 0) out mediump vec4 o_color;\n"
293 "in mediump vec4 v_color;\n"
294 "\n"
295 "void main()\n"
296 "{\n"
297 " o_color = v_color;\n"
298 "}\n";
299
300 // Create shader program and log it.
301
302 DE_ASSERT(!m_program);
303 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSourceStr, fragShaderSource));
304
305 tcu::TestLog& log = m_testCtx.getLog();
306
307 log << *m_program;
308
309 if(!m_program->isOk())
310 TCU_FAIL("Failed to compile shader");
311
312 // Vertex shader attributes.
313
314 if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED)
315 {
316 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
317
318 for (int y = 0; y < QUAD_GRID_SIZE + 1; y++)
319 for (int x = 0; x < QUAD_GRID_SIZE + 1; x++)
320 {
321 float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
322 float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f;
323
324 m_gridVertexPositions.push_back(fx);
325 m_gridVertexPositions.push_back(fy);
326 }
327
328 // Indices.
329
330 for (int y = 0; y < QUAD_GRID_SIZE; y++)
331 for (int x = 0; x < QUAD_GRID_SIZE; x++)
332 {
333 int ndx00 = y*(QUAD_GRID_SIZE + 1) + x;
334 int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1;
335 int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x;
336 int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1;
337
338 // Lower-left triangle of a quad.
339 m_gridIndices.push_back(ndx00);
340 m_gridIndices.push_back(ndx10);
341 m_gridIndices.push_back(ndx01);
342
343 // Upper-right triangle of a quad.
344 m_gridIndices.push_back(ndx11);
345 m_gridIndices.push_back(ndx01);
346 m_gridIndices.push_back(ndx10);
347 }
348 }
349 else
350 {
351 DE_ASSERT(m_function == FUNCTION_DRAW_ARRAYS_INSTANCED);
352
353 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
354
355 for (int y = 0; y < QUAD_GRID_SIZE; y++)
356 for (int x = 0; x < QUAD_GRID_SIZE; x++)
357 {
358 float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
359 float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
360 float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f;
361 float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f;
362
363 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
364 m_gridVertexPositions.push_back(fx0);
365 m_gridVertexPositions.push_back(fy0);
366 m_gridVertexPositions.push_back(fx1);
367 m_gridVertexPositions.push_back(fy0);
368 m_gridVertexPositions.push_back(fx0);
369 m_gridVertexPositions.push_back(fy1);
370
371 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
372 m_gridVertexPositions.push_back(fx1);
373 m_gridVertexPositions.push_back(fy1);
374 m_gridVertexPositions.push_back(fx0);
375 m_gridVertexPositions.push_back(fy1);
376 m_gridVertexPositions.push_back(fx1);
377 m_gridVertexPositions.push_back(fy0);
378 }
379 }
380
381 // Instanced attributes: position offset and color RGB components.
382
383 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
384 {
385 if (m_instancingType == TYPE_ATTRIB_DIVISOR)
386 {
387 // Offsets are such that the vertical bars are drawn next to each other.
388 for (int i = 0; i < m_numInstances; i++)
389 {
390 m_instanceOffsets.push_back((float)i * 2.0f / (float)m_numInstances);
391
392 DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4);
393
394 for (int j = 0; j < OFFSET_COMPONENTS-1; j++)
395 m_instanceOffsets.push_back(0.0f);
396 }
397
398 int rInstances = m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1);
399 for (int i = 0; i < rInstances; i++)
400 {
401 pushVarCompAttrib(m_instanceColorR, (float)i / (float)rInstances);
402
403 for (int j = 0; j < typeSize - 1; j++)
404 pushVarCompAttrib(m_instanceColorR, 0.0f);
405 }
406 }
407
408 int gInstances = m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1);
409 for (int i = 0; i < gInstances; i++)
410 {
411 pushVarCompAttrib(m_instanceColorG, (float)i*2.0f / (float)gInstances);
412
413 for (int j = 0; j < typeSize - 1; j++)
414 pushVarCompAttrib(m_instanceColorG, 0.0f);
415 }
416
417 int bInstances = m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1);
418 for (int i = 0; i < bInstances; i++)
419 {
420 pushVarCompAttrib(m_instanceColorB, 1.0f - (float)i / (float)bInstances);
421
422 for (int j = 0; j < typeSize - 1; j++)
423 pushVarCompAttrib(m_instanceColorB, 0.0f);
424 }
425 }
426 }
427
deinit(void)428 void InstancedRenderingCase::deinit (void)
429 {
430 delete m_program;
431 m_program = DE_NULL;
432 }
433
iterate(void)434 InstancedRenderingCase::IterateResult InstancedRenderingCase::iterate (void)
435 {
436 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
437 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
438
439 int xOffsetMax = m_context.getRenderTarget().getWidth() - width;
440 int yOffsetMax = m_context.getRenderTarget().getHeight() - height;
441
442 de::Random rnd (deStringHash(getName()));
443
444 int xOffset = rnd.getInt(0, xOffsetMax);
445 int yOffset = rnd.getInt(0, yOffsetMax);
446 tcu::Surface referenceImg (width, height);
447 tcu::Surface resultImg (width, height);
448
449 // Draw result.
450
451 glViewport(xOffset, yOffset, width, height);
452
453 setupAndRender();
454
455 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
456
457 // Compute reference.
458
459 computeReference(referenceImg);
460
461 // Compare.
462
463 bool testOk = tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, 0.05f, tcu::COMPARE_LOG_RESULT);
464
465 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
466 testOk ? "Pass" : "Fail");
467
468 return STOP;
469 }
470
setupVarAttribPointer(const void * attrPtr,int location,int divisor)471 void InstancedRenderingCase::setupVarAttribPointer (const void* attrPtr, int location, int divisor)
472 {
473 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType);
474 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType);
475 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType);
476 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType);
477 int typeSize = glu::getDataTypeScalarSize(m_rgbAttrType);
478 int numSlots = isMatCase ? glu::getDataTypeMatrixNumColumns(m_rgbAttrType) : 1; // Matrix uses as many attribute slots as it has columns.
479
480 for (int slotNdx = 0; slotNdx < numSlots; slotNdx++)
481 {
482 int curLoc = location + slotNdx;
483
484 glEnableVertexAttribArray(curLoc);
485 glVertexAttribDivisor(curLoc, divisor);
486
487 if (isFloatCase)
488 glVertexAttribPointer(curLoc, typeSize, GL_FLOAT, GL_FALSE, 0, attrPtr);
489 else if (isIntCase)
490 glVertexAttribIPointer(curLoc, typeSize, GL_INT, 0, attrPtr);
491 else if (isUintCase)
492 glVertexAttribIPointer(curLoc, typeSize, GL_UNSIGNED_INT, 0, attrPtr);
493 else if (isMatCase)
494 {
495 int numRows = glu::getDataTypeMatrixNumRows(m_rgbAttrType);
496 int numCols = glu::getDataTypeMatrixNumColumns(m_rgbAttrType);
497
498 glVertexAttribPointer(curLoc, numRows, GL_FLOAT, GL_FALSE, numCols*numRows*sizeof(float), attrPtr);
499 }
500 else
501 DE_ASSERT(DE_FALSE);
502 }
503 }
504
setupAndRender(void)505 void InstancedRenderingCase::setupAndRender (void)
506 {
507 deUint32 program = m_program->getProgram();
508
509 glUseProgram(program);
510
511 {
512 // Setup attributes.
513
514 // Position attribute is non-instanced.
515 int positionLoc = glGetAttribLocation(program, "a_position");
516 glEnableVertexAttribArray(positionLoc);
517 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &m_gridVertexPositions[0]);
518
519 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
520 {
521 if (m_instancingType == TYPE_ATTRIB_DIVISOR)
522 {
523 // Position offset attribute is instanced with separate offset for every instance.
524 int offsetLoc = glGetAttribLocation(program, "a_instanceOffset");
525 glEnableVertexAttribArray(offsetLoc);
526 glVertexAttribDivisor(offsetLoc, 1);
527 glVertexAttribPointer(offsetLoc, OFFSET_COMPONENTS, GL_FLOAT, GL_FALSE, 0, &m_instanceOffsets[0]);
528
529 int rLoc = glGetAttribLocation(program, "a_instanceR");
530 setupVarAttribPointer((void*)&m_instanceColorR[0].u32, rLoc, ATTRIB_DIVISOR_R);
531 }
532
533 int gLoc = glGetAttribLocation(program, "a_instanceG");
534 setupVarAttribPointer((void*)&m_instanceColorG[0].u32, gLoc, ATTRIB_DIVISOR_G);
535
536 int bLoc = glGetAttribLocation(program, "a_instanceB");
537 setupVarAttribPointer((void*)&m_instanceColorB[0].u32, bLoc, ATTRIB_DIVISOR_B);
538 }
539 }
540
541 // Draw using appropriate function.
542
543 if (m_function == FUNCTION_DRAW_ARRAYS_INSTANCED)
544 {
545 const int numPositionComponents = 2;
546 glDrawArraysInstanced(GL_TRIANGLES, 0, ((int)m_gridVertexPositions.size() / numPositionComponents), m_numInstances);
547 }
548 else
549 glDrawElementsInstanced(GL_TRIANGLES, (int)m_gridIndices.size(), GL_UNSIGNED_SHORT, &m_gridIndices[0], m_numInstances);
550
551 glUseProgram(0);
552 }
553
computeReference(tcu::Surface & dst)554 void InstancedRenderingCase::computeReference (tcu::Surface& dst)
555 {
556 int wid = dst.getWidth();
557 int hei = dst.getHeight();
558
559 // Draw a rectangle (vertical bar) for each instance.
560
561 for (int instanceNdx = 0; instanceNdx < m_numInstances; instanceNdx++)
562 {
563 int xStart = instanceNdx * wid / m_numInstances;
564 int xEnd = (instanceNdx + 1) * wid / m_numInstances;
565
566 // Emulate attribute divisors if that is the case.
567
568 int clrNdxR = m_instancingType == TYPE_ATTRIB_DIVISOR ? instanceNdx / ATTRIB_DIVISOR_R : instanceNdx;
569 int clrNdxG = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? instanceNdx / ATTRIB_DIVISOR_G : instanceNdx;
570 int clrNdxB = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? instanceNdx / ATTRIB_DIVISOR_B : instanceNdx;
571
572 int rInstances = m_instancingType == TYPE_ATTRIB_DIVISOR ? m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1) : m_numInstances;
573 int gInstances = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1) : m_numInstances;
574 int bInstances = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1) : m_numInstances;
575
576 // Calculate colors.
577
578 float r = (float)clrNdxR / (float)rInstances;
579 float g = (float)clrNdxG * 2.0f / (float)gInstances;
580 float b = 1.0f - (float)clrNdxB / (float)bInstances;
581
582 // Convert to integer and back if shader inputs are integers.
583
584 if (glu::isDataTypeIntOrIVec(m_rgbAttrType))
585 {
586 deInt32 intR = (deInt32)(r*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
587 deInt32 intG = (deInt32)(g*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
588 deInt32 intB = (deInt32)(b*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
589 r = (float)(intR - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
590 g = (float)(intG - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
591 b = (float)(intB - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
592 }
593 else if(glu::isDataTypeUintOrUVec(m_rgbAttrType))
594 {
595 deUint32 uintR = (deInt32)(r*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
596 deUint32 uintG = (deInt32)(g*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
597 deUint32 uintB = (deInt32)(b*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
598 r = (float)(uintR - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
599 g = (float)(uintG - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
600 b = (float)(uintB - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
601 }
602
603 // Draw rectangle.
604
605 for (int y = 0; y < hei; y++)
606 for (int x = xStart; x < xEnd; x++)
607 dst.setPixel(x, y, tcu::RGBA(tcu::Vec4(r, g, b, 1.0f)));
608 }
609 }
610
InstancedRenderingTests(Context & context)611 InstancedRenderingTests::InstancedRenderingTests (Context& context)
612 : TestCaseGroup(context, "instanced", "Instanced rendering tests")
613 {
614 }
615
~InstancedRenderingTests(void)616 InstancedRenderingTests::~InstancedRenderingTests (void)
617 {
618 }
619
init(void)620 void InstancedRenderingTests::init (void)
621 {
622 // Cases testing function, instancing method and instance count.
623
624 static const int instanceCounts[] = { 1, 2, 4, 20 };
625
626 for (int function = 0; function < (int)InstancedRenderingCase::FUNCTION_LAST; function++)
627 {
628 const char* functionName = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED ? "draw_arrays_instanced"
629 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "draw_elements_instanced"
630 : DE_NULL;
631
632 const char* functionDesc = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED ? "Use glDrawArraysInstanced()"
633 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "Use glDrawElementsInstanced()"
634 : DE_NULL;
635
636 DE_ASSERT(functionName != DE_NULL);
637 DE_ASSERT(functionDesc != DE_NULL);
638
639 TestCaseGroup* functionGroup = new TestCaseGroup(m_context, functionName, functionDesc);
640 addChild(functionGroup);
641
642 for (int instancingType = 0; instancingType < (int)InstancedRenderingCase::TYPE_LAST; instancingType++)
643 {
644 const char* instancingTypeName = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID ? "instance_id"
645 : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR ? "attribute_divisor"
646 : instancingType == (int)InstancedRenderingCase::TYPE_MIXED ? "mixed"
647 : DE_NULL;
648
649 const char* instancingTypeDesc = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID ? "Use gl_InstanceID for instancing"
650 : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR ? "Use vertex attribute divisors for instancing"
651 : instancingType == (int)InstancedRenderingCase::TYPE_MIXED ? "Use both gl_InstanceID and vertex attribute divisors for instancing"
652 : DE_NULL;
653
654 DE_ASSERT(instancingTypeName != DE_NULL);
655 DE_ASSERT(instancingTypeDesc != DE_NULL);
656
657 TestCaseGroup* instancingTypeGroup = new TestCaseGroup(m_context, instancingTypeName, instancingTypeDesc);
658 functionGroup->addChild(instancingTypeGroup);
659
660 for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(instanceCounts); countNdx++)
661 {
662 std::string countName = de::toString(instanceCounts[countNdx]) + "_instances";
663
664 instancingTypeGroup->addChild(new InstancedRenderingCase(m_context, countName.c_str(), "",
665 (InstancedRenderingCase::DrawFunction)function,
666 (InstancedRenderingCase::InstancingType)instancingType,
667 glu::TYPE_FLOAT,
668 instanceCounts[countNdx]));
669 }
670 }
671 }
672
673 // Data type specific cases.
674
675 static const glu::DataType s_testTypes[] =
676 {
677 glu::TYPE_FLOAT,
678 glu::TYPE_FLOAT_VEC2,
679 glu::TYPE_FLOAT_VEC3,
680 glu::TYPE_FLOAT_VEC4,
681 glu::TYPE_FLOAT_MAT2,
682 glu::TYPE_FLOAT_MAT2X3,
683 glu::TYPE_FLOAT_MAT2X4,
684 glu::TYPE_FLOAT_MAT3X2,
685 glu::TYPE_FLOAT_MAT3,
686 glu::TYPE_FLOAT_MAT3X4,
687 glu::TYPE_FLOAT_MAT4X2,
688 glu::TYPE_FLOAT_MAT4X3,
689 glu::TYPE_FLOAT_MAT4,
690
691 glu::TYPE_INT,
692 glu::TYPE_INT_VEC2,
693 glu::TYPE_INT_VEC3,
694 glu::TYPE_INT_VEC4,
695
696 glu::TYPE_UINT,
697 glu::TYPE_UINT_VEC2,
698 glu::TYPE_UINT_VEC3,
699 glu::TYPE_UINT_VEC4
700 };
701
702 const int typeTestNumInstances = 4;
703
704 TestCaseGroup* typesGroup = new TestCaseGroup(m_context, "types", "Tests for instanced attributes of particular data types");
705 addChild(typesGroup);
706
707 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_testTypes); typeNdx++)
708 {
709 glu::DataType type = s_testTypes[typeNdx];
710
711 typesGroup->addChild(new InstancedRenderingCase(m_context, glu::getDataTypeName(type), "",
712 InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED,
713 InstancedRenderingCase::TYPE_ATTRIB_DIVISOR,
714 type,
715 typeTestNumInstances));
716 }
717 }
718
719 } // Functional
720 } // gles3
721 } // deqp
722