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