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