Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fTransformFeedbackTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Transform feedback tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fTransformFeedbackTests.hpp"
25 #include "tcuTestLog.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuImageCompare.hpp"
28 #include "tcuVector.hpp"
29 #include "tcuFormatUtil.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "gluShaderUtil.hpp"
32 #include "gluVarType.hpp"
33 #include "gluVarTypeUtil.hpp"
34 #include "gluPixelTransfer.hpp"
35 #include "gluRenderContext.hpp"
36 #include "gluShaderProgram.hpp"
37 #include "gluObjectWrapper.hpp"
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40 #include "deRandom.hpp"
41 #include "deStringUtil.hpp"
42 #include "deMemory.h"
43 #include "deString.h"
44
45 #include <set>
46 #include <map>
47 #include <algorithm>
48
49 using std::string;
50 using std::vector;
51 using std::set;
52
53 using std::map;
54 using std::set;
55
56 using tcu::TestLog;
57
58 namespace deqp
59 {
60 namespace gles3
61 {
62 namespace Functional
63 {
64 namespace TransformFeedback
65 {
66
67 enum
68 {
69         VIEWPORT_WIDTH                  = 128,
70         VIEWPORT_HEIGHT                 = 128,
71         BUFFER_GUARD_MULTIPLIER = 2             //!< stride*BUFFER_GUARD_MULTIPLIER bytes are added to the end of tf buffer and used to check for overruns.
72 };
73
74 enum Interpolation
75 {
76         INTERPOLATION_SMOOTH = 0,
77         INTERPOLATION_FLAT,
78         INTERPOLATION_CENTROID,
79
80         INTERPOLATION_LAST
81 };
82
83 static const char* getInterpolationName (Interpolation interp)
84 {
85         switch (interp)
86         {
87                 case INTERPOLATION_SMOOTH:              return "smooth";
88                 case INTERPOLATION_FLAT:                return "flat";
89                 case INTERPOLATION_CENTROID:    return "centroid";
90                 default:
91                         DE_ASSERT(false);
92                         return DE_NULL;
93         }
94 }
95
96 struct Varying
97 {
98                                                 Varying                         (const char* name_, const glu::VarType& type_, Interpolation interp_)
99                                                         : name                  (name_)
100                                                         , type                  (type_)
101                                                         , interpolation (interp_)
102                                                 {
103                                                 }
104
105         std::string                     name;                           //!< Variable name.
106         glu::VarType            type;                           //!< Variable type.
107         Interpolation           interpolation;          //!< Interpolation mode (smooth, flat, centroid).
108 };
109
110 struct VaryingNameEquals
111 {
112                                         VaryingNameEquals       (const std::string& name_) : name(name_) {}
113         bool                    operator()                      (const Varying& var) const { return var.name == name; }
114
115         std::string             name;
116 };
117
118 struct Attribute
119 {
120         Attribute (const std::string& name_, const glu::VarType& type_, int offset_)
121                 : name          (name_)
122                 , type          (type_)
123                 , offset        (offset_)
124         {
125         }
126
127         std::string                     name;
128         glu::VarType            type;
129         int                                     offset;
130 };
131
132 struct AttributeNameEquals
133 {
134                                         AttributeNameEquals     (const std::string& name_) : name(name_) {}
135         bool                    operator()                      (const Attribute& attr) const { return attr.name == name; }
136
137         std::string             name;
138 };
139
140 struct Output
141 {
142         Output (void)
143                 : bufferNdx     (0)
144                 , offset        (0)
145         {
146         }
147
148         std::string                                     name;
149         glu::VarType                            type;
150         int                                                     bufferNdx;
151         int                                                     offset;
152         vector<const Attribute*>        inputs;
153 };
154
155 struct DrawCall
156 {
157                                 DrawCall (int numElements_, bool tfEnabled_)
158                                         : numElements                           (numElements_)
159                                         , transformFeedbackEnabled      (tfEnabled_)
160                                 {
161                                 }
162
163                                 DrawCall (void)
164                                         : numElements                           (0)
165                                         , transformFeedbackEnabled      (false)
166                                 {
167                                 }
168
169         int                     numElements;
170         bool            transformFeedbackEnabled;
171 };
172
173 std::ostream& operator<< (std::ostream& str, const DrawCall& call)
174 {
175         return str << "(" << call.numElements << ", " << (call.transformFeedbackEnabled ? "resumed" : "paused") << ")";
176 }
177
178 class ProgramSpec
179 {
180 public:
181                                                                         ProgramSpec                                             (void);
182                                                                         ~ProgramSpec                                    (void);
183
184         glu::StructType*                                createStruct                                    (const char* name);
185         void                                                    addVarying                                              (const char* name, const glu::VarType& type, Interpolation interp);
186         void                                                    addTransformFeedbackVarying             (const char* name);
187
188         const vector<glu::StructType*>& getStructs                                              (void) const { return m_structs;        }
189         const vector<Varying>&                  getVaryings                                             (void) const { return m_varyings;       }
190         const vector<string>&                   getTransformFeedbackVaryings    (void) const { return m_transformFeedbackVaryings; }
191         bool                                                    isPointSizeUsed                                 (void) const;
192
193 private:
194                                                                         ProgramSpec                                             (const ProgramSpec& other);
195         ProgramSpec&                                    operator=                                               (const ProgramSpec& other);
196
197         vector<glu::StructType*>                m_structs;
198         vector<Varying>                                 m_varyings;
199         vector<string>                                  m_transformFeedbackVaryings;
200 };
201
202 // ProgramSpec
203
204 ProgramSpec::ProgramSpec (void)
205 {
206 }
207
208 ProgramSpec::~ProgramSpec (void)
209 {
210         for (vector<glu::StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
211                 delete *i;
212 }
213
214 glu::StructType* ProgramSpec::createStruct (const char* name)
215 {
216         m_structs.reserve(m_structs.size()+1);
217         m_structs.push_back(new glu::StructType(name));
218         return m_structs.back();
219 }
220
221 void ProgramSpec::addVarying (const char* name, const glu::VarType& type, Interpolation interp)
222 {
223         m_varyings.push_back(Varying(name, type, interp));
224 }
225
226 void ProgramSpec::addTransformFeedbackVarying (const char* name)
227 {
228         m_transformFeedbackVaryings.push_back(name);
229 }
230
231 bool ProgramSpec::isPointSizeUsed (void) const
232 {
233         return std::find(m_transformFeedbackVaryings.begin(), m_transformFeedbackVaryings.end(), "gl_PointSize") != m_transformFeedbackVaryings.end();
234 }
235
236 static bool isProgramSupported (const glw::Functions& gl, const ProgramSpec& spec, deUint32 tfMode)
237 {
238         int             maxVertexAttribs                        = 0;
239         int             maxTfInterleavedComponents      = 0;
240         int             maxTfSeparateAttribs            = 0;
241         int             maxTfSeparateComponents         = 0;
242
243         gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS,                                                           &maxVertexAttribs);
244         gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,        &maxTfInterleavedComponents);
245         gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,                      &maxTfSeparateAttribs);
246         gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,           &maxTfSeparateComponents);
247
248         // Check vertex attribs.
249         int totalVertexAttribs  = 1 /* a_position */ + (spec.isPointSizeUsed() ? 1 : 0);
250         for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
251         {
252                 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++)
253                         totalVertexAttribs += 1;
254         }
255
256         if (totalVertexAttribs > maxVertexAttribs)
257                 return false; // Vertex attribute count exceeded.
258
259         // Check varyings.
260         int totalTfComponents   = 0;
261         int totalTfAttribs              = 0;
262         for (vector<string>::const_iterator iter = spec.getTransformFeedbackVaryings().begin(); iter != spec.getTransformFeedbackVaryings().end(); iter++)
263         {
264                 const string&   name                    = *iter;
265                 int                             numComponents   = 0;
266
267                 if (name == "gl_Position")
268                         numComponents = 4;
269                 else if (name == "gl_PointSize")
270                         numComponents = 1;
271                 else
272                 {
273                         string                                          varName         = glu::parseVariableName(name.c_str());
274                         const Varying&                          varying         = *std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName));
275                         glu::TypeComponentVector        varPath;
276
277                         glu::parseTypePath(name.c_str(), varying.type, varPath);
278                         numComponents = glu::getVarType(varying.type, varPath).getScalarSize();
279                 }
280
281                 if (tfMode == GL_SEPARATE_ATTRIBS && numComponents > maxTfSeparateComponents)
282                         return false; // Per-attribute component count exceeded.
283
284                 totalTfComponents       += numComponents;
285                 totalTfAttribs          += 1;
286         }
287
288         if (tfMode == GL_SEPARATE_ATTRIBS && totalTfAttribs > maxTfSeparateAttribs)
289                 return false;
290
291         if (tfMode == GL_INTERLEAVED_ATTRIBS && totalTfComponents > maxTfInterleavedComponents)
292                 return false;
293
294         return true;
295 }
296
297 // Program
298
299 static std::string getAttributeName (const char* varyingName, const glu::TypeComponentVector& path)
300 {
301         std::ostringstream str;
302
303         str << "a_" << (deStringBeginsWith(varyingName, "v_") ? varyingName+2 : varyingName);
304
305         for (glu::TypeComponentVector::const_iterator iter = path.begin(); iter != path.end(); iter++)
306         {
307                 const char* prefix = DE_NULL;
308
309                 switch (iter->type)
310                 {
311                         case glu::VarTypeComponent::STRUCT_MEMBER:              prefix = "_m";  break;
312                         case glu::VarTypeComponent::ARRAY_ELEMENT:              prefix = "_e";  break;
313                         case glu::VarTypeComponent::MATRIX_COLUMN:              prefix = "_c";  break;
314                         case glu::VarTypeComponent::VECTOR_COMPONENT:   prefix = "_s";  break;
315                         default:
316                                 DE_ASSERT(false);
317                 }
318
319                 str << prefix << iter->index;
320         }
321
322         return str.str();
323 }
324
325 static void genShaderSources (const ProgramSpec& spec, std::string& vertSource, std::string& fragSource, bool pointSizeRequired)
326 {
327         std::ostringstream      vtx;
328         std::ostringstream      frag;
329         bool                            addPointSize    = spec.isPointSizeUsed();
330
331         vtx << "#version 300 es\n"
332                 << "in highp vec4 a_position;\n";
333         frag << "#version 300 es\n"
334                  << "layout(location = 0) out mediump vec4 o_color;\n"
335                  << "uniform highp vec4 u_scale;\n"
336                  << "uniform highp vec4 u_bias;\n";
337
338         if (addPointSize)
339                 vtx << "in highp float a_pointSize;\n";
340
341         // Declare attributes.
342         for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
343         {
344                 const char*                     name    = var->name.c_str();
345                 const glu::VarType&     type    = var->type;
346
347                 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++)
348                 {
349                         glu::VarType    attribType      = glu::getVarType(type, vecIter.getPath());
350                         string                  attribName      = getAttributeName(name, vecIter.getPath());
351
352                         vtx << "in " << glu::declare(attribType, attribName.c_str()) << ";\n";
353                 }
354         }
355
356         // Declare vayrings.
357         for (int ndx = 0; ndx < 2; ndx++)
358         {
359                 const char*                     inout   = ndx ? "in" : "out";
360                 std::ostringstream&     str             = ndx ? frag : vtx;
361
362                 // Declare structs that have type name.
363                 for (vector<glu::StructType*>::const_iterator structIter = spec.getStructs().begin(); structIter != spec.getStructs().end(); structIter++)
364                 {
365                         const glu::StructType* structPtr = *structIter;
366                         if (structPtr->hasTypeName())
367                                 str << glu::declare(structPtr) << ";\n";
368                 }
369
370                 for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
371                         str << getInterpolationName(var->interpolation) << " " << inout << " " << glu::declare(var->type, var->name.c_str()) << ";\n";
372         }
373
374         vtx << "\nvoid main (void)\n{\n"
375                 << "\tgl_Position = a_position;\n";
376         frag << "\nvoid main (void)\n{\n"
377                  << "\thighp vec4 res = vec4(0.0);\n";
378
379         if (addPointSize)
380                 vtx << "\tgl_PointSize = a_pointSize;\n";
381         else if (pointSizeRequired)
382                 vtx << "\tgl_PointSize = 1.0;\n";
383
384         // Generate assignments / usage.
385         for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
386         {
387                 const char*                     name    = var->name.c_str();
388                 const glu::VarType&     type    = var->type;
389
390                 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++)
391                 {
392                         glu::VarType    subType         = glu::getVarType(type, vecIter.getPath());
393                         string                  attribName      = getAttributeName(name, vecIter.getPath());
394
395                         DE_ASSERT(subType.isBasicType() && glu::isDataTypeScalarOrVector(subType.getBasicType()));
396
397                         // Vertex: assign from attribute.
398                         vtx << "\t" << name << vecIter << " = " << attribName << ";\n";
399
400                         // Fragment: add to res variable.
401                         int scalarSize = glu::getDataTypeScalarSize(subType.getBasicType());
402
403                         frag << "\tres += ";
404                         if (scalarSize == 1)            frag << "vec4(" << name << vecIter << ")";
405                         else if (scalarSize == 2)       frag << "vec2(" << name << vecIter << ").xxyy";
406                         else if (scalarSize == 3)       frag << "vec3(" << name << vecIter << ").xyzx";
407                         else if (scalarSize == 4)       frag << "vec4(" << name << vecIter << ")";
408
409                         frag << ";\n";
410                 }
411         }
412
413         frag << "\to_color = res * u_scale + u_bias;\n";
414
415         vtx << "}\n";
416         frag << "}\n";
417
418         vertSource = vtx.str();
419         fragSource = frag.str();
420 }
421
422 static glu::ShaderProgram* createVertexCaptureProgram (const glu::RenderContext& context, const ProgramSpec& spec, deUint32 bufferMode, deUint32 primitiveType)
423 {
424         std::string vertSource, fragSource;
425
426         genShaderSources(spec, vertSource, fragSource, primitiveType == GL_POINTS /* Is point size required? */);
427
428         return new glu::ShaderProgram(context, glu::ProgramSources()
429                                                                                    << glu::VertexSource(vertSource)
430                                                                                    << glu::FragmentSource(fragSource)
431                                                                                    << glu::TransformFeedbackVaryings<vector<string>::const_iterator>(spec.getTransformFeedbackVaryings().begin(), spec.getTransformFeedbackVaryings().end())
432                                                                                    << glu::TransformFeedbackMode(bufferMode));
433 }
434
435 // Helpers.
436
437 static void computeInputLayout (vector<Attribute>& attributes, int& inputStride, const vector<Varying>& varyings, bool usePointSize)
438 {
439         inputStride = 0;
440
441         // Add position.
442         attributes.push_back(Attribute("a_position", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), inputStride));
443         inputStride += 4*(int)sizeof(deUint32);
444
445         if (usePointSize)
446         {
447                 attributes.push_back(Attribute("a_pointSize", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), inputStride));
448                 inputStride += 1*(int)sizeof(deUint32);
449         }
450
451         // Compute attribute vector.
452         for (vector<Varying>::const_iterator var = varyings.begin(); var != varyings.end(); var++)
453         {
454                 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++)
455                 {
456                         glu::VarType    type    = vecIter.getType();
457                         string                  name    = getAttributeName(var->name.c_str(), vecIter.getPath());
458
459                         attributes.push_back(Attribute(name, type, inputStride));
460                         inputStride += glu::getDataTypeScalarSize(type.getBasicType())*(int)sizeof(deUint32);
461                 }
462         }
463 }
464
465 static void computeTransformFeedbackOutputs (vector<Output>& transformFeedbackOutputs, const vector<Attribute>& attributes, const vector<Varying>& varyings, const vector<string>& transformFeedbackVaryings, deUint32 bufferMode)
466 {
467         int accumulatedSize = 0;
468
469         transformFeedbackOutputs.resize(transformFeedbackVaryings.size());
470         for (int varNdx = 0; varNdx < (int)transformFeedbackVaryings.size(); varNdx++)
471         {
472                 const string&   name            = transformFeedbackVaryings[varNdx];
473                 int                             bufNdx          = (bufferMode == GL_SEPARATE_ATTRIBS ? varNdx : 0);
474                 int                             offset          = (bufferMode == GL_SEPARATE_ATTRIBS ? 0 : accumulatedSize);
475                 Output&                 output          = transformFeedbackOutputs[varNdx];
476
477                 output.name                     = name;
478                 output.bufferNdx        = bufNdx;
479                 output.offset           = offset;
480
481                 if (name == "gl_Position")
482                 {
483                         const Attribute* posIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position")));
484                         output.type = posIn->type;
485                         output.inputs.push_back(posIn);
486                 }
487                 else if (name == "gl_PointSize")
488                 {
489                         const Attribute* sizeIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize")));
490                         output.type = sizeIn->type;
491                         output.inputs.push_back(sizeIn);
492                 }
493                 else
494                 {
495                         string                                          varName         = glu::parseVariableName(name.c_str());
496                         const Varying&                          varying         = *std::find_if(varyings.begin(), varyings.end(), VaryingNameEquals(varName));
497                         glu::TypeComponentVector        varPath;
498
499                         glu::parseTypePath(name.c_str(), varying.type, varPath);
500
501                         output.type = glu::getVarType(varying.type, varPath);
502
503                         // Add all vectorized attributes as inputs.
504                         for (glu::VectorTypeIterator iter = glu::VectorTypeIterator::begin(&output.type); iter != glu::VectorTypeIterator::end(&output.type); iter++)
505                         {
506                                 // Full path.
507                                 glu::TypeComponentVector fullPath(varPath.size() + iter.getPath().size());
508
509                                 std::copy(varPath.begin(), varPath.end(), fullPath.begin());
510                                 std::copy(iter.getPath().begin(), iter.getPath().end(), fullPath.begin()+varPath.size());
511
512                                 string                          attribName      = getAttributeName(varName.c_str(), fullPath);
513                                 const Attribute*        attrib          = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals(attribName)));
514
515                                 output.inputs.push_back(attrib);
516                         }
517                 }
518
519                 accumulatedSize += output.type.getScalarSize()*(int)sizeof(deUint32);
520         }
521 }
522
523 static deUint32 signExtend (deUint32 value, deUint32 numBits)
524 {
525         DE_ASSERT(numBits >= 1u && numBits <= 32u);
526         if (numBits == 32u)
527                 return value;
528         else if ((value & (1u << (numBits-1u))) == 0u)
529                 return value;
530         else
531                 return value | ~((1u << numBits) - 1u);
532 }
533
534 static void genAttributeData (const Attribute& attrib, deUint8* basePtr, int stride, int numElements, de::Random& rnd)
535 {
536         const int                               elementSize     = (int)sizeof(deUint32);
537         const bool                              isFloat         = glu::isDataTypeFloatOrVec(attrib.type.getBasicType());
538         const bool                              isInt           = glu::isDataTypeIntOrIVec(attrib.type.getBasicType());
539         const bool                              isUint          = glu::isDataTypeUintOrUVec(attrib.type.getBasicType());
540         const glu::Precision    precision       = attrib.type.getPrecision();
541         const int                               numComps        = glu::getDataTypeScalarSize(attrib.type.getBasicType());
542
543         for (int elemNdx = 0; elemNdx < numElements; elemNdx++)
544         {
545                 for (int compNdx = 0; compNdx < numComps; compNdx++)
546                 {
547                         int offset = attrib.offset+elemNdx*stride+compNdx*elementSize;
548                         if (isFloat)
549                         {
550                                 float* comp = (float*)(basePtr+offset);
551                                 switch (precision)
552                                 {
553                                         case glu::PRECISION_LOWP:               *comp = 0.0f + 0.25f*(float)rnd.getInt(0, 4);   break;
554                                         case glu::PRECISION_MEDIUMP:    *comp = rnd.getFloat(-1e3f, 1e3f);                              break;
555                                         case glu::PRECISION_HIGHP:              *comp = rnd.getFloat(-1e5f, 1e5f);                              break;
556                                         default:
557                                                 DE_ASSERT(false);
558                                 }
559                         }
560                         else if (isInt)
561                         {
562                                 int* comp = (int*)(basePtr+offset);
563                                 switch (precision)
564                                 {
565                                         case glu::PRECISION_LOWP:               *comp = (int)signExtend(rnd.getUint32()&0xff, 8);               break;
566                                         case glu::PRECISION_MEDIUMP:    *comp = (int)signExtend(rnd.getUint32()&0xffff, 16);    break;
567                                         case glu::PRECISION_HIGHP:              *comp = (int)rnd.getUint32();                                                   break;
568                                         default:
569                                                 DE_ASSERT(false);
570                                 }
571                         }
572                         else if (isUint)
573                         {
574                                 deUint32* comp = (deUint32*)(basePtr+offset);
575                                 switch (precision)
576                                 {
577                                         case glu::PRECISION_LOWP:               *comp = rnd.getUint32()&0xff;   break;
578                                         case glu::PRECISION_MEDIUMP:    *comp = rnd.getUint32()&0xffff; break;
579                                         case glu::PRECISION_HIGHP:              *comp = rnd.getUint32();                break;
580                                         default:
581                                                 DE_ASSERT(false);
582                                 }
583                         }
584                         else
585                                 DE_ASSERT(false);
586                 }
587         }
588 }
589
590 static void genInputData (const vector<Attribute>& attributes, int numInputs, int inputStride, deUint8* inputBasePtr, de::Random& rnd)
591 {
592         // Random positions.
593         const Attribute& position = *std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position"));
594
595         for (int ndx = 0; ndx < numInputs; ndx++)
596         {
597                 deUint8* ptr = inputBasePtr + position.offset + inputStride*ndx;
598                 *((float*)(ptr+ 0)) = rnd.getFloat(-1.2f, 1.2f);
599                 *((float*)(ptr+ 4)) = rnd.getFloat(-1.2f, 1.2f);
600                 *((float*)(ptr+ 8)) = rnd.getFloat(-1.2f, 1.2f);
601                 *((float*)(ptr+12)) = rnd.getFloat(0.1f, 2.0f);
602         }
603
604         // Point size.
605         vector<Attribute>::const_iterator pointSizePos = std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize"));
606         if (pointSizePos != attributes.end())
607         {
608                 for (int ndx = 0; ndx < numInputs; ndx++)
609                 {
610                         deUint8* ptr = inputBasePtr + pointSizePos->offset + inputStride*ndx;
611                         *((float*)ptr) = rnd.getFloat(1.0f, 8.0f);
612                 }
613         }
614
615         // Random data for rest of components.
616         for (vector<Attribute>::const_iterator attrib = attributes.begin(); attrib != attributes.end(); attrib++)
617         {
618                 if (attrib->name == "a_position" || attrib->name == "a_pointSize")
619                         continue;
620
621                 genAttributeData(*attrib, inputBasePtr, inputStride, numInputs, rnd);
622         }
623 }
624
625 static deUint32 getTransformFeedbackOutputCount (deUint32 primitiveType, int numElements)
626 {
627         switch (primitiveType)
628         {
629                 case GL_TRIANGLES:                      return numElements - numElements%3;
630                 case GL_TRIANGLE_STRIP:         return de::max(0, numElements-2)*3;
631                 case GL_TRIANGLE_FAN:           return de::max(0, numElements-2)*3;
632                 case GL_LINES:                          return numElements - numElements%2;
633                 case GL_LINE_STRIP:                     return de::max(0, numElements-1)*2;
634                 case GL_LINE_LOOP:                      return numElements > 1 ? numElements*2 : 0;
635                 case GL_POINTS:                         return numElements;
636
637                 default:
638                         DE_ASSERT(false);
639                         return 0;
640         }
641 }
642
643 static deUint32 getTransformFeedbackPrimitiveCount (deUint32 primitiveType, int numElements)
644 {
645         switch (primitiveType)
646         {
647                 case GL_TRIANGLES:                      return numElements/3;
648                 case GL_TRIANGLE_STRIP:         return de::max(0, numElements-2);
649                 case GL_TRIANGLE_FAN:           return de::max(0, numElements-2);
650                 case GL_LINES:                          return numElements/2;
651                 case GL_LINE_STRIP:                     return de::max(0, numElements-1);
652                 case GL_LINE_LOOP:                      return numElements > 1 ? numElements : 0;
653                 case GL_POINTS:                         return numElements;
654
655                 default:
656                         DE_ASSERT(false);
657                         return 0;
658         }
659 }
660
661 static deUint32 getTransformFeedbackPrimitiveMode (deUint32 primitiveType)
662 {
663         switch (primitiveType)
664         {
665                 case GL_TRIANGLES:
666                 case GL_TRIANGLE_STRIP:
667                 case GL_TRIANGLE_FAN:
668                         return GL_TRIANGLES;
669
670                 case GL_LINES:
671                 case GL_LINE_LOOP:
672                 case GL_LINE_STRIP:
673                         return GL_LINES;
674
675                 case GL_POINTS:
676                         return GL_POINTS;
677
678                 default:
679                         DE_ASSERT(false);
680                         return 0;
681         }
682 }
683
684 static int getAttributeIndex (deUint32 primitiveType, int numInputs, int outNdx)
685 {
686         switch (primitiveType)
687         {
688                 case GL_TRIANGLES:                      return outNdx;
689                 case GL_LINES:                          return outNdx;
690                 case GL_POINTS:                         return outNdx;
691
692                 case GL_TRIANGLE_STRIP:
693                 {
694                         int triNdx = outNdx/3;
695                         int vtxNdx = outNdx%3;
696                         return (triNdx%2 != 0 && vtxNdx < 2) ? (triNdx+1-vtxNdx) : (triNdx+vtxNdx);
697                 }
698
699                 case GL_TRIANGLE_FAN:
700                         return (outNdx%3 != 0) ? (outNdx/3 + outNdx%3) : 0;
701
702                 case GL_LINE_STRIP:
703                         return outNdx/2 + outNdx%2;
704
705                 case GL_LINE_LOOP:
706                 {
707                         int inNdx = outNdx/2 + outNdx%2;
708                         return inNdx < numInputs ? inNdx : 0;
709                 }
710
711                 default:
712                         DE_ASSERT(false);
713                         return 0;
714         }
715 }
716
717 static bool compareTransformFeedbackOutput (tcu::TestLog& log, deUint32 primitiveType, const Output& output, int numInputs, const deUint8* inBasePtr, int inStride, const deUint8* outBasePtr, int outStride)
718 {
719         bool            isOk            = true;
720         int                     outOffset       = output.offset;
721
722         for (int attrNdx = 0; attrNdx < (int)output.inputs.size(); attrNdx++)
723         {
724                 const Attribute&        attribute               = *output.inputs[attrNdx];
725                 glu::DataType           type                    = attribute.type.getBasicType();
726                 int                                     numComponents   = glu::getDataTypeScalarSize(type);
727                 glu::Precision          precision               = attribute.type.getPrecision();
728                 glu::DataType           scalarType              = glu::getDataTypeScalarType(type);
729                 int                                     numOutputs              = getTransformFeedbackOutputCount(primitiveType, numInputs);
730
731                 for (int outNdx = 0; outNdx < numOutputs; outNdx++)
732                 {
733                         int inNdx = getAttributeIndex(primitiveType, numInputs, outNdx);
734
735                         for (int compNdx = 0; compNdx < numComponents; compNdx++)
736                         {
737                                 const deUint8*  inPtr   = inBasePtr + inStride*inNdx + attribute.offset + compNdx*sizeof(deUint32);
738                                 const deUint8*  outPtr  = outBasePtr + outStride*outNdx + outOffset + compNdx*sizeof(deUint32);
739                                 deUint32                inVal   = *(const deUint32*)inPtr;
740                                 deUint32                outVal  = *(const deUint32*)outPtr;
741                                 bool                    isEqual = false;
742
743                                 if (scalarType == glu::TYPE_FLOAT)
744                                 {
745                                         // ULP comparison is used for highp and mediump. Lowp uses threshold-comparison.
746                                         switch (precision)
747                                         {
748                                                 case glu::PRECISION_HIGHP:              isEqual = de::abs((int)inVal - (int)outVal) < 2;                                break;
749                                                 case glu::PRECISION_MEDIUMP:    isEqual = de::abs((int)inVal - (int)outVal) < 2+(1<<13);                break;
750                                                 case glu::PRECISION_LOWP:
751                                                 {
752                                                         float inF       = *(const float*)inPtr;
753                                                         float outF      = *(const float*)outPtr;
754                                                         isEqual = de::abs(inF - outF) < 0.1f;
755                                                         break;
756                                                 }
757                                                 default:
758                                                         DE_ASSERT(false);
759                                         }
760                                 }
761                                 else
762                                         isEqual = (inVal == outVal); // Bit-exact match required for integer types.
763
764                                 if (!isEqual)
765                                 {
766                                         log << TestLog::Message << "Mismatch in " << output.name << " (" << attribute.name << "), output = " << outNdx << ", input = " << inNdx << ", component = " << compNdx << TestLog::EndMessage;
767                                         isOk = false;
768                                         break;
769                                 }
770                         }
771
772                         if (!isOk)
773                                 break;
774                 }
775
776                 if (!isOk)
777                         break;
778
779                 outOffset += numComponents*(int)sizeof(deUint32);
780         }
781
782         return isOk;
783 }
784
785 static int computeTransformFeedbackPrimitiveCount (deUint32 primitiveType, const DrawCall* first, const DrawCall* end)
786 {
787         int primCount = 0;
788
789         for (const DrawCall* call = first; call != end; ++call)
790         {
791                 if (call->transformFeedbackEnabled)
792                         primCount += getTransformFeedbackPrimitiveCount(primitiveType, call->numElements);
793         }
794
795         return primCount;
796 }
797
798 static void writeBufferGuard (const glw::Functions& gl, deUint32 target, int bufferSize, int guardSize)
799 {
800         deUint8* ptr = (deUint8*)gl.mapBufferRange(target, bufferSize, guardSize, GL_MAP_WRITE_BIT);
801         if (ptr)
802                 deMemset(ptr, 0xcd, guardSize);
803         gl.unmapBuffer(target);
804         GLU_EXPECT_NO_ERROR(gl.getError(), "guardband write");
805 }
806
807 static bool verifyGuard (const deUint8* ptr, int guardSize)
808 {
809         for (int ndx = 0; ndx < guardSize; ndx++)
810         {
811                 if (ptr[ndx] != 0xcd)
812                         return false;
813         }
814         return true;
815 }
816
817 static void logTransformFeedbackVaryings (TestLog& log, const glw::Functions& gl, deUint32 program)
818 {
819         int numTfVaryings       = 0;
820         int     maxNameLen              = 0;
821
822         gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &numTfVaryings);
823         gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &maxNameLen);
824         GLU_EXPECT_NO_ERROR(gl.getError(), "Query TF varyings");
825
826         log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_VARYINGS = " << numTfVaryings << TestLog::EndMessage;
827
828         vector<char> nameBuf(maxNameLen+1);
829
830         for (int ndx = 0; ndx < numTfVaryings; ndx++)
831         {
832                 glw::GLsizei    size    = 0;
833                 glw::GLenum             type    = 0;
834
835                 gl.getTransformFeedbackVarying(program, ndx, (glw::GLsizei)nameBuf.size(), DE_NULL, &size, &type, &nameBuf[0]);
836                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbackVarying()");
837
838                 const glu::DataType     dataType        = glu::getDataTypeFromGLType(type);
839                 const std::string       typeName        = dataType != glu::TYPE_LAST ? std::string(glu::getDataTypeName(dataType))
840                                                                                                                                          : (std::string("unknown(") + tcu::toHex(type).toString() + ")");
841
842                 log << TestLog::Message << (const char*)&nameBuf[0] << ": " << typeName << "[" << size << "]" << TestLog::EndMessage;
843         }
844 }
845
846 class TransformFeedbackCase : public TestCase
847 {
848 public:
849                                                                 TransformFeedbackCase           (Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType);
850                                                                 ~TransformFeedbackCase          (void);
851
852         void                                            init                                            (void);
853         void                                            deinit                                          (void);
854         IterateResult                           iterate                                         (void);
855
856 protected:
857         ProgramSpec                                     m_progSpec;
858         deUint32                                        m_bufferMode;
859         deUint32                                        m_primitiveType;
860
861 private:
862                                                                 TransformFeedbackCase           (const TransformFeedbackCase& other);
863         TransformFeedbackCase&          operator=                                       (const TransformFeedbackCase& other);
864
865         bool                                            runTest                                         (const DrawCall* first, const DrawCall* end, deUint32 seed);
866
867         // Derived from ProgramSpec in init()
868         int                                                     m_inputStride;
869         vector<Attribute>                       m_attributes;
870         vector<Output>                          m_transformFeedbackOutputs;
871         vector<int>                                     m_bufferStrides;
872
873         // GL state.
874         glu::ShaderProgram*                     m_program;
875         glu::TransformFeedback*         m_transformFeedback;
876         vector<deUint32>                        m_outputBuffers;
877
878         int                                                     m_iterNdx;
879 };
880
881 TransformFeedbackCase::TransformFeedbackCase (Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType)
882         : TestCase                              (context, name, desc)
883         , m_bufferMode                  (bufferMode)
884         , m_primitiveType               (primitiveType)
885         , m_inputStride                 (0)
886         , m_program                             (DE_NULL)
887         , m_transformFeedback   (DE_NULL)
888         , m_iterNdx                             (0)
889 {
890 }
891
892 TransformFeedbackCase::~TransformFeedbackCase (void)
893 {
894         TransformFeedbackCase::deinit();
895 }
896
897 static bool hasArraysInTFVaryings (const ProgramSpec& spec)
898 {
899         for (vector<string>::const_iterator tfVar = spec.getTransformFeedbackVaryings().begin(); tfVar != spec.getTransformFeedbackVaryings().end(); ++tfVar)
900         {
901                 string                                                  varName = glu::parseVariableName(tfVar->c_str());
902                 vector<Varying>::const_iterator varIter = std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName));
903
904                 if (varName == "gl_Position" || varName == "gl_PointSize")
905                         continue;
906
907                 DE_ASSERT(varIter != spec.getVaryings().end());
908
909                 if (varIter->type.isArrayType())
910                         return true;
911         }
912
913         return false;
914 }
915
916 void TransformFeedbackCase::init (void)
917 {
918         TestLog&                                log     = m_testCtx.getLog();
919         const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
920
921         DE_ASSERT(!m_program);
922         m_program = createVertexCaptureProgram(m_context.getRenderContext(), m_progSpec, m_bufferMode, m_primitiveType);
923
924         log << *m_program;
925         if (!m_program->isOk())
926         {
927                 const bool linkFail = m_program->getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk &&
928                                                           m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk &&
929                                                           !m_program->getProgramInfo().linkOk;
930
931                 if (linkFail)
932                 {
933                         if (!isProgramSupported(gl, m_progSpec, m_bufferMode))
934                                 throw tcu::NotSupportedError("Implementation limits execeeded", "", __FILE__, __LINE__);
935                         else if (hasArraysInTFVaryings(m_progSpec))
936                                 throw tcu::NotSupportedError("Capturing arrays is not supported (undefined in specification)", "", __FILE__, __LINE__);
937                         else
938                                 throw tcu::TestError("Link failed", "", __FILE__, __LINE__);
939                 }
940                 else
941                         throw tcu::TestError("Compile failed", "", __FILE__, __LINE__);
942         }
943
944         log << TestLog::Message << "Transform feedback varyings: " << tcu::formatArray(m_progSpec.getTransformFeedbackVaryings().begin(), m_progSpec.getTransformFeedbackVaryings().end()) << TestLog::EndMessage;
945
946         // Print out transform feedback points reported by GL.
947         log << TestLog::Message << "Transform feedback varyings reported by compiler:" << TestLog::EndMessage;
948         logTransformFeedbackVaryings(log, gl, m_program->getProgram());
949
950         // Compute input specification.
951         computeInputLayout(m_attributes, m_inputStride, m_progSpec.getVaryings(), m_progSpec.isPointSizeUsed());
952
953         // Build list of varyings used in transform feedback.
954         computeTransformFeedbackOutputs(m_transformFeedbackOutputs, m_attributes, m_progSpec.getVaryings(), m_progSpec.getTransformFeedbackVaryings(), m_bufferMode);
955         DE_ASSERT(!m_transformFeedbackOutputs.empty());
956
957         // Buffer strides.
958         DE_ASSERT(m_bufferStrides.empty());
959         if (m_bufferMode == GL_SEPARATE_ATTRIBS)
960         {
961                 for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++)
962                         m_bufferStrides.push_back(outIter->type.getScalarSize()*(int)sizeof(deUint32));
963         }
964         else
965         {
966                 int totalSize = 0;
967                 for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++)
968                         totalSize += outIter->type.getScalarSize()*(int)sizeof(deUint32);
969
970                 m_bufferStrides.push_back(totalSize);
971         }
972
973         // \note Actual storage is allocated in iterate().
974         m_outputBuffers.resize(m_bufferStrides.size());
975         gl.genBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]);
976
977         DE_ASSERT(!m_transformFeedback);
978         m_transformFeedback = new glu::TransformFeedback(m_context.getRenderContext());
979
980         GLU_EXPECT_NO_ERROR(gl.getError(), "init");
981
982         m_iterNdx = 0;
983         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
984 }
985
986 void TransformFeedbackCase::deinit (void)
987 {
988         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
989
990         if (!m_outputBuffers.empty())
991         {
992                 gl.deleteBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]);
993                 m_outputBuffers.clear();
994         }
995
996         delete m_transformFeedback;
997         m_transformFeedback = DE_NULL;
998
999         delete m_program;
1000         m_program = DE_NULL;
1001
1002         // Clean up state.
1003         m_attributes.clear();
1004         m_transformFeedbackOutputs.clear();
1005         m_bufferStrides.clear();
1006         m_inputStride = 0;
1007 }
1008
1009 TransformFeedbackCase::IterateResult TransformFeedbackCase::iterate (void)
1010 {
1011         // Test cases.
1012         static const DrawCall s_elemCount1[]    = { DrawCall(1, true) };
1013         static const DrawCall s_elemCount2[]    = { DrawCall(2, true) };
1014         static const DrawCall s_elemCount3[]    = { DrawCall(3, true) };
1015         static const DrawCall s_elemCount4[]    = { DrawCall(4, true) };
1016         static const DrawCall s_elemCount123[]  = { DrawCall(123, true) };
1017         static const DrawCall s_basicPause1[]   = { DrawCall(64, true), DrawCall(64, false), DrawCall(64, true) };
1018         static const DrawCall s_basicPause2[]   = { DrawCall(13, true), DrawCall(5, true), DrawCall(17, false), DrawCall(3, true), DrawCall(7, false) };
1019         static const DrawCall s_startPaused[]   = { DrawCall(123, false), DrawCall(123, true) };
1020         static const DrawCall s_random1[]               = { DrawCall(65, true), DrawCall(135, false), DrawCall(74, true), DrawCall(16, false), DrawCall(226, false), DrawCall(9, true), DrawCall(174, false) };
1021         static const DrawCall s_random2[]               = { DrawCall(217, true), DrawCall(171, true), DrawCall(147, true), DrawCall(152, false), DrawCall(55, true) };
1022
1023         static const struct
1024         {
1025                 const DrawCall*         calls;
1026                 int                                     numCalls;
1027         } s_iterations[] =
1028         {
1029 #define ITER(ARR) { ARR, DE_LENGTH_OF_ARRAY(ARR) }
1030                 ITER(s_elemCount1),
1031                 ITER(s_elemCount2),
1032                 ITER(s_elemCount3),
1033                 ITER(s_elemCount4),
1034                 ITER(s_elemCount123),
1035                 ITER(s_basicPause1),
1036                 ITER(s_basicPause2),
1037                 ITER(s_startPaused),
1038                 ITER(s_random1),
1039                 ITER(s_random2)
1040 #undef ITER
1041         };
1042
1043         TestLog&                                log                             = m_testCtx.getLog();
1044         bool                                    isOk                    = true;
1045         deUint32                                seed                    = deStringHash(getName()) ^ deInt32Hash(m_iterNdx);
1046         int                                             numIterations   = DE_LENGTH_OF_ARRAY(s_iterations);
1047         const DrawCall*                 first                   = s_iterations[m_iterNdx].calls;
1048         const DrawCall*                 end                             = s_iterations[m_iterNdx].calls + s_iterations[m_iterNdx].numCalls;
1049
1050         std::string                             sectionName             = std::string("Iteration") + de::toString(m_iterNdx+1);
1051         std::string                             sectionDesc             = std::string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations);
1052         tcu::ScopedLogSection   section                 (log, sectionName, sectionDesc);
1053
1054         log << TestLog::Message << "Testing " << s_iterations[m_iterNdx].numCalls << " draw calls, (element count, TF state): " << tcu::formatArray(first, end) << TestLog::EndMessage;
1055
1056         isOk = runTest(first, end, seed);
1057
1058         if (!isOk)
1059                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
1060
1061         m_iterNdx += 1;
1062         return (isOk && m_iterNdx < numIterations) ? CONTINUE : STOP;
1063 }
1064
1065 bool TransformFeedbackCase::runTest (const DrawCall* first, const DrawCall* end, deUint32 seed)
1066 {
1067         TestLog&                                log                             = m_testCtx.getLog();
1068         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
1069         de::Random                              rnd                             (seed);
1070         int                                             numInputs               = 0;            //!< Sum of element counts in calls.
1071         int                                             numOutputs              = 0;            //!< Sum of output counts for calls that have transform feedback enabled.
1072         int                                             width                   = m_context.getRenderContext().getRenderTarget().getWidth();
1073         int                                             height                  = m_context.getRenderContext().getRenderTarget().getHeight();
1074         int                                             viewportW               = de::min((int)VIEWPORT_WIDTH, width);
1075         int                                             viewportH               = de::min((int)VIEWPORT_HEIGHT, height);
1076         int                                             viewportX               = rnd.getInt(0, width-viewportW);
1077         int                                             viewportY               = rnd.getInt(0, height-viewportH);
1078         tcu::Surface                    frameWithTf             (viewportW, viewportH);
1079         tcu::Surface                    frameWithoutTf  (viewportW, viewportH);
1080         glu::Query                              primitiveQuery  (m_context.getRenderContext());
1081         bool                                    outputsOk               = true;
1082         bool                                    imagesOk                = true;
1083         bool                                    queryOk                 = true;
1084
1085         // Compute totals.
1086         for (const DrawCall* call = first; call != end; call++)
1087         {
1088                 numInputs       += call->numElements;
1089                 numOutputs      += call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0;
1090         }
1091
1092         // Input data.
1093         vector<deUint8> inputData(m_inputStride*numInputs);
1094         genInputData(m_attributes, numInputs, m_inputStride, &inputData[0], rnd);
1095
1096         gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transformFeedback->get());
1097         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback()");
1098
1099         // Allocate storage for transform feedback output buffers and bind to targets.
1100         for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++)
1101         {
1102                 deUint32                buffer          = m_outputBuffers[bufNdx];
1103                 int                             stride          = m_bufferStrides[bufNdx];
1104                 int                             target          = bufNdx;
1105                 int                             size            = stride*numOutputs;
1106                 int                             guardSize       = stride*BUFFER_GUARD_MULTIPLIER;
1107                 const deUint32  usage           = GL_DYNAMIC_READ;
1108
1109                 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
1110                 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size+guardSize, DE_NULL, usage);
1111                 writeBufferGuard(gl, GL_TRANSFORM_FEEDBACK_BUFFER, size, guardSize);
1112
1113                 // \todo [2012-07-30 pyry] glBindBufferRange()?
1114                 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, target, buffer);
1115
1116                 GLU_EXPECT_NO_ERROR(gl.getError(), "transform feedback buffer setup");
1117         }
1118
1119         // Setup attributes.
1120         for (vector<Attribute>::const_iterator attrib = m_attributes.begin(); attrib != m_attributes.end(); attrib++)
1121         {
1122                 int                             loc                             = gl.getAttribLocation(m_program->getProgram(), attrib->name.c_str());
1123                 glu::DataType   scalarType              = glu::getDataTypeScalarType(attrib->type.getBasicType());
1124                 int                             numComponents   = glu::getDataTypeScalarSize(attrib->type.getBasicType());
1125                 const void*             ptr                             = &inputData[0] + attrib->offset;
1126
1127                 if (loc >= 0)
1128                 {
1129                         gl.enableVertexAttribArray(loc);
1130
1131                         if (scalarType == glu::TYPE_FLOAT)              gl.vertexAttribPointer  (loc, numComponents, GL_FLOAT, GL_FALSE, m_inputStride, ptr);
1132                         else if (scalarType == glu::TYPE_INT)   gl.vertexAttribIPointer (loc, numComponents, GL_INT, m_inputStride, ptr);
1133                         else if (scalarType == glu::TYPE_UINT)  gl.vertexAttribIPointer (loc, numComponents, GL_UNSIGNED_INT, m_inputStride, ptr);
1134                 }
1135         }
1136
1137         // Setup viewport.
1138         gl.viewport(viewportX, viewportY, viewportW, viewportH);
1139
1140         // Setup program.
1141         gl.useProgram(m_program->getProgram());
1142
1143         gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_scale"),        1, tcu::Vec4(0.01f).getPtr());
1144         gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_bias"),         1, tcu::Vec4(0.5f).getPtr());
1145
1146         // Enable query.
1147         gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, *primitiveQuery);
1148         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)");
1149
1150         // Draw.
1151         {
1152                 int             offset          = 0;
1153                 bool    tfEnabled       = true;
1154
1155                 gl.clear(GL_COLOR_BUFFER_BIT);
1156
1157                 gl.beginTransformFeedback(getTransformFeedbackPrimitiveMode(m_primitiveType));
1158
1159                 for (const DrawCall* call = first; call != end; call++)
1160                 {
1161                         // Pause or resume transform feedback if necessary.
1162                         if (call->transformFeedbackEnabled != tfEnabled)
1163                         {
1164                                 if (call->transformFeedbackEnabled)
1165                                         gl.resumeTransformFeedback();
1166                                 else
1167                                         gl.pauseTransformFeedback();
1168                                 tfEnabled = call->transformFeedbackEnabled;
1169                         }
1170
1171                         gl.drawArrays(m_primitiveType, offset, call->numElements);
1172                         offset += call->numElements;
1173                 }
1174
1175                 // Resume feedback before finishing it.
1176                 if (!tfEnabled)
1177                         gl.resumeTransformFeedback();
1178
1179                 gl.endTransformFeedback();
1180                 GLU_EXPECT_NO_ERROR(gl.getError(), "render");
1181         }
1182
1183         gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
1184         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)");
1185
1186         // Check and log query status right after submit
1187         {
1188                 deUint32 available = GL_FALSE;
1189                 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available);
1190                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()");
1191
1192                 log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN status after submit: " << (available != GL_FALSE ? "GL_TRUE" : "GL_FALSE") << TestLog::EndMessage;
1193         }
1194
1195         // Compare result buffers.
1196         for (int bufferNdx = 0; bufferNdx < (int)m_outputBuffers.size(); bufferNdx++)
1197         {
1198                 deUint32                buffer          = m_outputBuffers[bufferNdx];
1199                 int                             stride          = m_bufferStrides[bufferNdx];
1200                 int                             size            = stride*numOutputs;
1201                 int                             guardSize       = stride*BUFFER_GUARD_MULTIPLIER;
1202                 const void*             bufPtr          = DE_NULL;
1203
1204                 // Bind buffer for reading.
1205                 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
1206                 bufPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, size+guardSize, GL_MAP_READ_BIT);
1207                 GLU_EXPECT_NO_ERROR(gl.getError(), "mapping buffer");
1208
1209                 // Verify all output variables that are written to this buffer.
1210                 for (vector<Output>::const_iterator out = m_transformFeedbackOutputs.begin(); out != m_transformFeedbackOutputs.end(); out++)
1211                 {
1212                         if (out->bufferNdx != bufferNdx)
1213                                 continue;
1214
1215                         int inputOffset         = 0;
1216                         int     outputOffset    = 0;
1217
1218                         // Process all draw calls and check ones with transform feedback enabled.
1219                         for (const DrawCall* call = first; call != end; call++)
1220                         {
1221                                 if (call->transformFeedbackEnabled)
1222                                 {
1223                                         const deUint8*  inputPtr        = &inputData[0] + inputOffset*m_inputStride;
1224                                         const deUint8*  outputPtr       = (const deUint8*)bufPtr + outputOffset*stride;
1225
1226                                         if (!compareTransformFeedbackOutput(log, m_primitiveType, *out, call->numElements, inputPtr, m_inputStride, outputPtr, stride))
1227                                         {
1228                                                 outputsOk = false;
1229                                                 break;
1230                                         }
1231                                 }
1232
1233                                 inputOffset             += call->numElements;
1234                                 outputOffset    += call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0;
1235                         }
1236                 }
1237
1238                 // Verify guardband.
1239                 if (!verifyGuard((const deUint8*)bufPtr + size, guardSize))
1240                 {
1241                         log << TestLog::Message << "Error: Transform feedback buffer overrun detected" << TestLog::EndMessage;
1242                         outputsOk = false;
1243                 }
1244
1245                 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1246         }
1247
1248         // Check status after mapping buffers.
1249         {
1250                 const bool      mustBeReady             = !m_outputBuffers.empty(); // Mapping buffer forces synchronization.
1251                 const int       expectedCount   = computeTransformFeedbackPrimitiveCount(m_primitiveType, first, end);
1252                 deUint32        available               = GL_FALSE;
1253                 deUint32        numPrimitives   = 0;
1254
1255                 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available);
1256                 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT, &numPrimitives);
1257                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()");
1258
1259                 if (!mustBeReady && available == GL_FALSE)
1260                 {
1261                         log << TestLog::Message << "ERROR: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN result not available after mapping buffers!" << TestLog::EndMessage;
1262                         queryOk = false;
1263                 }
1264
1265                 log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = " << numPrimitives << TestLog::EndMessage;
1266
1267                 if ((int)numPrimitives != expectedCount)
1268                 {
1269                         log << TestLog::Message << "ERROR: Expected " << expectedCount << " primitives!" << TestLog::EndMessage;
1270                         queryOk = false;
1271                 }
1272         }
1273
1274         // Clear transform feedback state.
1275         gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1276         for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++)
1277         {
1278                 gl.bindBuffer           (GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1279                 gl.bindBufferBase       (GL_TRANSFORM_FEEDBACK_BUFFER, bufNdx, 0);
1280         }
1281
1282         // Read back rendered image.
1283         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithTf.getAccess());
1284
1285         // Render without transform feedback.
1286         {
1287                 int offset = 0;
1288
1289                 gl.clear(GL_COLOR_BUFFER_BIT);
1290
1291                 for (const DrawCall* call = first; call != end; call++)
1292                 {
1293                         gl.drawArrays(m_primitiveType, offset, call->numElements);
1294                         offset += call->numElements;
1295                 }
1296
1297                 GLU_EXPECT_NO_ERROR(gl.getError(), "render");
1298                 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithoutTf.getAccess());
1299         }
1300
1301         // Compare images with and without transform feedback.
1302         imagesOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", frameWithoutTf, frameWithTf, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_ON_ERROR);
1303
1304         if (imagesOk)
1305                 m_testCtx.getLog() << TestLog::Message << "Rendering result comparison between TF enabled and TF disabled passed." << TestLog::EndMessage;
1306         else
1307                 m_testCtx.getLog() << TestLog::Message << "ERROR: Rendering result comparison between TF enabled and TF disabled failed!" << TestLog::EndMessage;
1308
1309         return outputsOk && imagesOk && queryOk;
1310 }
1311
1312 // Test cases.
1313
1314 class PositionCase : public TransformFeedbackCase
1315 {
1316 public:
1317         PositionCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType)
1318                 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
1319         {
1320                 m_progSpec.addTransformFeedbackVarying("gl_Position");
1321         }
1322 };
1323
1324 class PointSizeCase : public TransformFeedbackCase
1325 {
1326 public:
1327         PointSizeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType)
1328                 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
1329         {
1330                 m_progSpec.addTransformFeedbackVarying("gl_PointSize");
1331         }
1332 };
1333
1334 class BasicTypeCase : public TransformFeedbackCase
1335 {
1336 public:
1337         BasicTypeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
1338                 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
1339         {
1340                 m_progSpec.addVarying("v_varA", glu::VarType(type, precision), interpolation);
1341                 m_progSpec.addVarying("v_varB", glu::VarType(type, precision), interpolation);
1342
1343                 m_progSpec.addTransformFeedbackVarying("v_varA");
1344                 m_progSpec.addTransformFeedbackVarying("v_varB");
1345         }
1346 };
1347
1348 class BasicArrayCase : public TransformFeedbackCase
1349 {
1350 public:
1351         BasicArrayCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
1352                 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
1353         {
1354                 if (glu::isDataTypeMatrix(type) || m_bufferMode == GL_SEPARATE_ATTRIBS)
1355                 {
1356                         // \note For matrix types we need to use reduced array sizes or otherwise we will exceed maximum attribute (16)
1357                         //               or transform feedback component count (64).
1358                         //               On separate attribs mode maximum component count per varying is 4.
1359                         m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 1), interpolation);
1360                         m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 2), interpolation);
1361                 }
1362                 else
1363                 {
1364                         m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation);
1365                         m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation);
1366                 }
1367
1368                 m_progSpec.addTransformFeedbackVarying("v_varA");
1369                 m_progSpec.addTransformFeedbackVarying("v_varB");
1370         }
1371 };
1372
1373 class ArrayElementCase : public TransformFeedbackCase
1374 {
1375 public:
1376         ArrayElementCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
1377                 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
1378         {
1379                 m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation);
1380                 m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation);
1381
1382                 m_progSpec.addTransformFeedbackVarying("v_varA[1]");
1383                 m_progSpec.addTransformFeedbackVarying("v_varB[0]");
1384                 m_progSpec.addTransformFeedbackVarying("v_varB[3]");
1385         }
1386 };
1387
1388 class RandomCase : public TransformFeedbackCase
1389 {
1390 public:
1391         RandomCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, deUint32 seed)
1392                 : TransformFeedbackCase (context, name, desc, bufferType, primitiveType)
1393                 , m_seed                                (seed)
1394         {
1395         }
1396
1397         void init (void)
1398         {
1399                 // \note Hard-coded indices and hackery are used when indexing this, beware.
1400                 static const glu::DataType typeCandidates[] =
1401                 {
1402                         glu::TYPE_FLOAT,
1403                         glu::TYPE_FLOAT_VEC2,
1404                         glu::TYPE_FLOAT_VEC3,
1405                         glu::TYPE_FLOAT_VEC4,
1406                         glu::TYPE_INT,
1407                         glu::TYPE_INT_VEC2,
1408                         glu::TYPE_INT_VEC3,
1409                         glu::TYPE_INT_VEC4,
1410                         glu::TYPE_UINT,
1411                         glu::TYPE_UINT_VEC2,
1412                         glu::TYPE_UINT_VEC3,
1413                         glu::TYPE_UINT_VEC4,
1414
1415                         glu::TYPE_FLOAT_MAT2,
1416                         glu::TYPE_FLOAT_MAT2X3,
1417                         glu::TYPE_FLOAT_MAT2X4,
1418
1419                         glu::TYPE_FLOAT_MAT3X2,
1420                         glu::TYPE_FLOAT_MAT3,
1421                         glu::TYPE_FLOAT_MAT3X4,
1422
1423                         glu::TYPE_FLOAT_MAT4X2,
1424                         glu::TYPE_FLOAT_MAT4X3,
1425                         glu::TYPE_FLOAT_MAT4
1426                 };
1427
1428                 static const glu::Precision precisions[] =
1429                 {
1430                         glu::PRECISION_LOWP,
1431                         glu::PRECISION_MEDIUMP,
1432                         glu::PRECISION_HIGHP
1433                 };
1434
1435                 static const Interpolation interpModes[] =
1436                 {
1437                         INTERPOLATION_FLAT,
1438                         INTERPOLATION_SMOOTH,
1439                         INTERPOLATION_CENTROID
1440                 };
1441
1442                 const int       maxAttributeVectors                                     = 16;
1443 //              const int       maxTransformFeedbackComponents          = 64; // \note It is enough to limit attribute set size.
1444                 bool            isSeparateMode                                          = m_bufferMode == GL_SEPARATE_ATTRIBS;
1445                 int                     maxTransformFeedbackVars                        = isSeparateMode ? 4 : maxAttributeVectors;
1446                 const float     arrayWeight                                                     = 0.3f;
1447                 const float     positionWeight                                          = 0.7f;
1448                 const float     pointSizeWeight                                         = 0.1f;
1449                 const float     captureFullArrayWeight                          = 0.5f;
1450
1451                 de::Random      rnd                                                                     (m_seed);
1452                 bool            usePosition                                                     = rnd.getFloat() < positionWeight;
1453                 bool            usePointSize                                            = rnd.getFloat() < pointSizeWeight;
1454                 int                     numAttribVectorsToUse                           = rnd.getInt(1, maxAttributeVectors - 1/*position*/ - (usePointSize ? 1 : 0));
1455
1456                 int                     numAttributeVectors                                     = 0;
1457                 int                     varNdx                                                          = 0;
1458
1459                 // Generate varyings.
1460                 while (numAttributeVectors < numAttribVectorsToUse)
1461                 {
1462                         int                                             maxVecs         = isSeparateMode ? de::min(2 /*at most 2*mat2*/, numAttribVectorsToUse-numAttributeVectors) : numAttribVectorsToUse-numAttributeVectors;
1463                         const glu::DataType*    begin           = &typeCandidates[0];
1464                         const glu::DataType*    end                     = begin + (maxVecs >= 4 ? 21 :
1465                                                                                                                    maxVecs >= 3 ? 18 :
1466                                                                                                                    maxVecs >= 2 ? (isSeparateMode ? 13 : 15) : 12);
1467
1468                         glu::DataType                   type            = rnd.choose<glu::DataType>(begin, end);
1469                         glu::Precision                  precision       = rnd.choose<glu::Precision>(&precisions[0], &precisions[0]+DE_LENGTH_OF_ARRAY(precisions));
1470                         Interpolation                   interp          = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT
1471                                                                                                 ? rnd.choose<Interpolation>(&interpModes[0], &interpModes[0]+DE_LENGTH_OF_ARRAY(interpModes))
1472                                                                                                 : INTERPOLATION_FLAT;
1473                         int                                             numVecs         = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : 1;
1474                         int                                             numComps        = glu::getDataTypeScalarSize(type);
1475                         int                                             maxArrayLen     = de::max(1, isSeparateMode ? 4/numComps : maxVecs/numVecs);
1476                         bool                                    useArray        = rnd.getFloat() < arrayWeight;
1477                         int                                             arrayLen        = useArray ? rnd.getInt(1, maxArrayLen) : 1;
1478                         std::string                             name            = "v_var" + de::toString(varNdx);
1479
1480                         if (useArray)
1481                                 m_progSpec.addVarying(name.c_str(), glu::VarType(glu::VarType(type, precision), arrayLen), interp);
1482                         else
1483                                 m_progSpec.addVarying(name.c_str(), glu::VarType(type, precision), interp);
1484
1485                         numAttributeVectors     += arrayLen*numVecs;
1486                         varNdx                          += 1;
1487                 }
1488
1489                 // Generate transform feedback candidate set.
1490                 vector<string> tfCandidates;
1491
1492                 if (usePosition)        tfCandidates.push_back("gl_Position");
1493                 if (usePointSize)       tfCandidates.push_back("gl_PointSize");
1494
1495                 for (int ndx = 0; ndx < varNdx /* num varyings */; ndx++)
1496                 {
1497                         const Varying& var = m_progSpec.getVaryings()[ndx];
1498
1499                         if (var.type.isArrayType())
1500                         {
1501                                 const bool captureFull = rnd.getFloat() < captureFullArrayWeight;
1502
1503                                 if (captureFull)
1504                                         tfCandidates.push_back(var.name);
1505                                 else
1506                                 {
1507                                         const int numElem = var.type.getArraySize();
1508                                         for (int elemNdx = 0; elemNdx < numElem; elemNdx++)
1509                                                 tfCandidates.push_back(var.name + "[" + de::toString(elemNdx) + "]");
1510                                 }
1511                         }
1512                         else
1513                                 tfCandidates.push_back(var.name);
1514                 }
1515
1516                 // Pick random selection.
1517                 vector<string> tfVaryings(de::min((int)tfCandidates.size(), maxTransformFeedbackVars));
1518                 rnd.choose(tfCandidates.begin(), tfCandidates.end(), tfVaryings.begin(), (int)tfVaryings.size());
1519                 rnd.shuffle(tfVaryings.begin(), tfVaryings.end());
1520
1521                 for (vector<string>::const_iterator var = tfVaryings.begin(); var != tfVaryings.end(); var++)
1522                         m_progSpec.addTransformFeedbackVarying(var->c_str());
1523
1524                 TransformFeedbackCase::init();
1525         }
1526
1527 private:
1528         deUint32 m_seed;
1529 };
1530
1531 } // TransformFeedback
1532
1533 using namespace TransformFeedback;
1534
1535 TransformFeedbackTests::TransformFeedbackTests (Context& context)
1536         : TestCaseGroup(context, "transform_feedback", "Transform feedback tests")
1537 {
1538 }
1539
1540 TransformFeedbackTests::~TransformFeedbackTests (void)
1541 {
1542 }
1543
1544 void TransformFeedbackTests::init (void)
1545 {
1546         static const struct
1547         {
1548                 const char*             name;
1549                 deUint32                mode;
1550         } bufferModes[] =
1551         {
1552                 { "separate",           GL_SEPARATE_ATTRIBS             },
1553                 { "interleaved",        GL_INTERLEAVED_ATTRIBS  }
1554         };
1555
1556         static const struct
1557         {
1558                 const char*             name;
1559                 deUint32                type;
1560         } primitiveTypes[] =
1561         {
1562                 { "points",                     GL_POINTS                       },
1563                 { "lines",                      GL_LINES                        },
1564                 { "triangles",          GL_TRIANGLES            }
1565
1566                 // Not supported by GLES3.
1567 //              { "line_strip",         GL_LINE_STRIP           },
1568 //              { "line_loop",          GL_LINE_LOOP            },
1569 //              { "triangle_fan",       GL_TRIANGLE_FAN         },
1570 //              { "triangle_strip",     GL_TRIANGLE_STRIP       }
1571         };
1572
1573         static const glu::DataType basicTypes[] =
1574         {
1575                 glu::TYPE_FLOAT,
1576                 glu::TYPE_FLOAT_VEC2,
1577                 glu::TYPE_FLOAT_VEC3,
1578                 glu::TYPE_FLOAT_VEC4,
1579                 glu::TYPE_FLOAT_MAT2,
1580                 glu::TYPE_FLOAT_MAT2X3,
1581                 glu::TYPE_FLOAT_MAT2X4,
1582                 glu::TYPE_FLOAT_MAT3X2,
1583                 glu::TYPE_FLOAT_MAT3,
1584                 glu::TYPE_FLOAT_MAT3X4,
1585                 glu::TYPE_FLOAT_MAT4X2,
1586                 glu::TYPE_FLOAT_MAT4X3,
1587                 glu::TYPE_FLOAT_MAT4,
1588                 glu::TYPE_INT,
1589                 glu::TYPE_INT_VEC2,
1590                 glu::TYPE_INT_VEC3,
1591                 glu::TYPE_INT_VEC4,
1592                 glu::TYPE_UINT,
1593                 glu::TYPE_UINT_VEC2,
1594                 glu::TYPE_UINT_VEC3,
1595                 glu::TYPE_UINT_VEC4
1596         };
1597
1598         static const glu::Precision precisions[] =
1599         {
1600                 glu::PRECISION_LOWP,
1601                 glu::PRECISION_MEDIUMP,
1602                 glu::PRECISION_HIGHP
1603         };
1604
1605         static const struct
1606         {
1607                 const char*             name;
1608                 Interpolation   interp;
1609         } interpModes[] =
1610         {
1611                 { "smooth",             INTERPOLATION_SMOOTH    },
1612                 { "flat",               INTERPOLATION_FLAT              },
1613                 { "centroid",   INTERPOLATION_CENTROID  }
1614         };
1615
1616         // .position
1617         {
1618                 tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_Position capture using transform feedback");
1619                 addChild(positionGroup);
1620
1621                 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
1622                 {
1623                         for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
1624                         {
1625                                 string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name;
1626                                 positionGroup->addChild(new PositionCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type));
1627                         }
1628                 }
1629         }
1630
1631         // .point_size
1632         {
1633                 tcu::TestCaseGroup* pointSizeGroup = new tcu::TestCaseGroup(m_testCtx, "point_size", "gl_PointSize capture using transform feedback");
1634                 addChild(pointSizeGroup);
1635
1636                 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
1637                 {
1638                         for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
1639                         {
1640                                 string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name;
1641                                 pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type));
1642                         }
1643                 }
1644         }
1645
1646         // .basic_type
1647         {
1648                 tcu::TestCaseGroup* basicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "basic_types", "Basic types in transform feedback");
1649                 addChild(basicTypeGroup);
1650
1651                 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
1652                 {
1653                         tcu::TestCaseGroup* modeGroup   = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
1654                         deUint32                        bufferMode      = bufferModes[bufferModeNdx].mode;
1655                         basicTypeGroup->addChild(modeGroup);
1656
1657                         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
1658                         {
1659                                 tcu::TestCaseGroup* primitiveGroup      = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
1660                                 deUint32                        primitiveType   = primitiveTypes[primitiveTypeNdx].type;
1661                                 modeGroup->addChild(primitiveGroup);
1662
1663                                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
1664                                 {
1665                                         glu::DataType           type            = basicTypes[typeNdx];
1666                                         bool                            isFloat         = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
1667
1668                                         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1669                                         {
1670                                                 glu::Precision precision = precisions[precNdx];
1671
1672                                                 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
1673                                                 primitiveGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
1674                                         }
1675                                 }
1676                         }
1677                 }
1678         }
1679
1680         // .array
1681         {
1682                 tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Capturing whole array in TF");
1683                 addChild(arrayGroup);
1684
1685                 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
1686                 {
1687                         tcu::TestCaseGroup* modeGroup   = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
1688                         deUint32                        bufferMode      = bufferModes[bufferModeNdx].mode;
1689                         arrayGroup->addChild(modeGroup);
1690
1691                         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
1692                         {
1693                                 tcu::TestCaseGroup* primitiveGroup      = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
1694                                 deUint32                        primitiveType   = primitiveTypes[primitiveTypeNdx].type;
1695                                 modeGroup->addChild(primitiveGroup);
1696
1697                                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
1698                                 {
1699                                         glu::DataType           type            = basicTypes[typeNdx];
1700                                         bool                            isFloat         = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
1701
1702                                         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1703                                         {
1704                                                 glu::Precision precision = precisions[precNdx];
1705
1706                                                 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
1707                                                 primitiveGroup->addChild(new BasicArrayCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
1708                                         }
1709                                 }
1710                         }
1711                 }
1712         }
1713
1714         // .array_element
1715         {
1716                 tcu::TestCaseGroup* arrayElemGroup = new tcu::TestCaseGroup(m_testCtx, "array_element", "Capturing single array element in TF");
1717                 addChild(arrayElemGroup);
1718
1719                 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
1720                 {
1721                         tcu::TestCaseGroup* modeGroup   = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
1722                         deUint32                        bufferMode      = bufferModes[bufferModeNdx].mode;
1723                         arrayElemGroup->addChild(modeGroup);
1724
1725                         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
1726                         {
1727                                 tcu::TestCaseGroup* primitiveGroup      = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
1728                                 deUint32                        primitiveType   = primitiveTypes[primitiveTypeNdx].type;
1729                                 modeGroup->addChild(primitiveGroup);
1730
1731                                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
1732                                 {
1733                                         glu::DataType           type            = basicTypes[typeNdx];
1734                                         bool                            isFloat         = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
1735
1736                                         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1737                                         {
1738                                                 glu::Precision precision = precisions[precNdx];
1739
1740                                                 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
1741                                                 primitiveGroup->addChild(new ArrayElementCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
1742                                         }
1743                                 }
1744                         }
1745                 }
1746         }
1747
1748         // .interpolation
1749         {
1750                 tcu::TestCaseGroup* interpolationGroup = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Different interpolation modes in transform feedback varyings");
1751                 addChild(interpolationGroup);
1752
1753                 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(interpModes); modeNdx++)
1754                 {
1755                         Interpolation           interp          = interpModes[modeNdx].interp;
1756                         tcu::TestCaseGroup*     modeGroup       = new tcu::TestCaseGroup(m_testCtx, interpModes[modeNdx].name, "");
1757
1758                         interpolationGroup->addChild(modeGroup);
1759
1760                         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1761                         {
1762                                 glu::Precision precision = precisions[precNdx];
1763
1764                                 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
1765                                 {
1766                                         for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
1767                                         {
1768                                                 string name = string(glu::getPrecisionName(precision)) + "_vec4_" + primitiveTypes[primitiveType].name + "_" + bufferModes[bufferMode].name;
1769                                                 modeGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type, glu::TYPE_FLOAT_VEC4, precision, interp));
1770                                         }
1771                                 }
1772                         }
1773                 }
1774         }
1775
1776         // .random
1777         {
1778                 tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized transform feedback cases");
1779                 addChild(randomGroup);
1780
1781                 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
1782                 {
1783                         tcu::TestCaseGroup* modeGroup   = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
1784                         deUint32                        bufferMode      = bufferModes[bufferModeNdx].mode;
1785                         randomGroup->addChild(modeGroup);
1786
1787                         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
1788                         {
1789                                 tcu::TestCaseGroup* primitiveGroup      = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
1790                                 deUint32                        primitiveType   = primitiveTypes[primitiveTypeNdx].type;
1791                                 modeGroup->addChild(primitiveGroup);
1792
1793                                 for (int ndx = 0; ndx < 10; ndx++)
1794                                 {
1795                                         deUint32 seed = deInt32Hash(bufferMode) ^ deInt32Hash(primitiveType) ^ deInt32Hash(ndx);
1796                                         primitiveGroup->addChild(new RandomCase(m_context, de::toString(ndx+1).c_str(), "", bufferMode, primitiveType, seed));
1797                                 }
1798                         }
1799                 }
1800         }
1801 }
1802
1803 } // Functional
1804 } // gles3
1805 } // deqp