Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fInstancedRenderingTests.cpp
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
77         VarComp(float v)        : f32(v) {}
78         VarComp(deUint32 v)     : u32(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
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
152 InstancedRenderingCase::~InstancedRenderingCase (void)
153 {
154         InstancedRenderingCase::deinit();
155 }
156
157 // Helper function that does biasing and scaling when converting float to integer.
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
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((deUint16)ndx00);
340                                 m_gridIndices.push_back((deUint16)ndx10);
341                                 m_gridIndices.push_back((deUint16)ndx01);
342
343                                 // Upper-right triangle of a quad.
344                                 m_gridIndices.push_back((deUint16)ndx11);
345                                 m_gridIndices.push_back((deUint16)ndx01);
346                                 m_gridIndices.push_back((deUint16)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
428 void InstancedRenderingCase::deinit (void)
429 {
430         delete m_program;
431         m_program = DE_NULL;
432 }
433
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
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*(int)sizeof(float), attrPtr);
499                 }
500                 else
501                         DE_ASSERT(DE_FALSE);
502         }
503 }
504
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
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
611 InstancedRenderingTests::InstancedRenderingTests (Context& context)
612         : TestCaseGroup(context, "instanced", "Instanced rendering tests")
613 {
614 }
615
616 InstancedRenderingTests::~InstancedRenderingTests (void)
617 {
618 }
619
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