[automerger skipped] RESTRICT AUTOMERGE: Relax composite-to-present latency requireme...
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fGeometryShaderTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Geometry shader tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fGeometryShaderTests.hpp"
25
26 #include "gluRenderContext.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "gluObjectWrapper.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluCallLogWrapper.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuStringTemplate.hpp"
38 #include "glsStateQueryUtil.hpp"
39
40 #include "gluStrUtil.hpp"
41 #include "deStringUtil.hpp"
42 #include "deUniquePtr.hpp"
43 #include "deMemory.h"
44
45 #include "sglrContext.hpp"
46 #include "sglrReferenceContext.hpp"
47 #include "sglrGLContext.hpp"
48 #include "sglrReferenceUtils.hpp"
49
50 #include "glwDefs.hpp"
51 #include "glwEnums.hpp"
52 #include "glwFunctions.hpp"
53
54 #include <algorithm>
55
56 using namespace glw;
57
58 namespace deqp
59 {
60 namespace gles31
61 {
62 namespace Functional
63 {
64 namespace
65 {
66
67 using namespace gls::StateQueryUtil;
68
69 const int TEST_CANVAS_SIZE = 256;
70
71 static const char* const s_commonShaderSourceVertex =           "${GLSL_VERSION_DECL}\n"
72                                                                                                                         "in highp vec4 a_position;\n"
73                                                                                                                         "in highp vec4 a_color;\n"
74                                                                                                                         "out highp vec4 v_geom_FragColor;\n"
75                                                                                                                         "void main (void)\n"
76                                                                                                                         "{\n"
77                                                                                                                         "       gl_Position = a_position;\n"
78                                                                                                                         "       gl_PointSize = 1.0;\n"
79                                                                                                                         "       v_geom_FragColor = a_color;\n"
80                                                                                                                         "}\n";
81 static const char* const s_commonShaderSourceFragment =         "${GLSL_VERSION_DECL}\n"
82                                                                                                                         "layout(location = 0) out mediump vec4 fragColor;\n"
83                                                                                                                         "in mediump vec4 v_frag_FragColor;\n"
84                                                                                                                         "void main (void)\n"
85                                                                                                                         "{\n"
86                                                                                                                         "       fragColor = v_frag_FragColor;\n"
87                                                                                                                         "}\n";
88 static const char* const s_expandShaderSourceGeometryBody =     "in highp vec4 v_geom_FragColor[];\n"
89                                                                                                                         "out highp vec4 v_frag_FragColor;\n"
90                                                                                                                         "\n"
91                                                                                                                         "void main (void)\n"
92                                                                                                                         "{\n"
93                                                                                                                         "       const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
94                                                                                                                         "       const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
95                                                                                                                         "       const highp vec4 offset2 = vec4(-0.01,  0.08, 0.0, 0.0);\n"
96                                                                                                                         "             highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
97                                                                                                                         "\n"
98                                                                                                                         "       for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
99                                                                                                                         "       {\n"
100                                                                                                                         "               gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
101                                                                                                                         "               gl_PrimitiveID = gl_PrimitiveIDIn;\n"
102                                                                                                                         "               v_frag_FragColor = v_geom_FragColor[ndx];\n"
103                                                                                                                         "               EmitVertex();\n"
104                                                                                                                         "\n"
105                                                                                                                         "               gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
106                                                                                                                         "               gl_PrimitiveID = gl_PrimitiveIDIn;\n"
107                                                                                                                         "               v_frag_FragColor = v_geom_FragColor[ndx];\n"
108                                                                                                                         "               EmitVertex();\n"
109                                                                                                                         "\n"
110                                                                                                                         "               gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
111                                                                                                                         "               gl_PrimitiveID = gl_PrimitiveIDIn;\n"
112                                                                                                                         "               v_frag_FragColor = v_geom_FragColor[ndx];\n"
113                                                                                                                         "               EmitVertex();\n"
114                                                                                                                         "               EndPrimitive();\n"
115                                                                                                                         "       }\n"
116                                                                                                                         "}\n";
117
118 static std::string specializeShader (const std::string& shaderSource, const glu::ContextType& contextType)
119 {
120         const bool                                                      supportsES32    = glu::contextSupports(contextType, glu::ApiType::es(3, 2));
121         std::map<std::string, std::string>      args;
122         args["GLSL_VERSION_DECL"]                                       = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType));
123         args["GLSL_EXT_GEOMETRY_SHADER"]                        = supportsES32 ? "" : "#extension GL_EXT_geometry_shader : require\n";
124         args["GLSL_OES_TEXTURE_STORAGE_MULTISAMPLE"]= supportsES32 ? "" : "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
125
126         return tcu::StringTemplate(shaderSource).specialize(args);
127 }
128
129 std::string inputTypeToGLString (rr::GeometryShaderInputType inputType)
130 {
131         switch (inputType)
132         {
133                 case rr::GEOMETRYSHADERINPUTTYPE_POINTS:                                return "points";
134                 case rr::GEOMETRYSHADERINPUTTYPE_LINES:                                 return "lines";
135                 case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:               return "lines_adjacency";
136                 case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:                             return "triangles";
137                 case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:   return "triangles_adjacency";
138                 default:
139                         DE_ASSERT(DE_FALSE);
140                         return "error";
141         }
142 }
143
144 std::string outputTypeToGLString (rr::GeometryShaderOutputType outputType)
145 {
146         switch (outputType)
147         {
148                 case rr::GEOMETRYSHADEROUTPUTTYPE_POINTS:                               return "points";
149                 case rr::GEOMETRYSHADEROUTPUTTYPE_LINE_STRIP:                   return "line_strip";
150                 case rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP:               return "triangle_strip";
151                 default:
152                         DE_ASSERT(DE_FALSE);
153                         return "error";
154         }
155 }
156
157 std::string primitiveTypeToString (GLenum primitive)
158 {
159         switch (primitive)
160         {
161                 case GL_POINTS:                                          return "points";
162                 case GL_LINES:                                           return "lines";
163                 case GL_LINE_LOOP:                                       return "line_loop";
164                 case GL_LINE_STRIP:                                      return "line_strip";
165                 case GL_LINES_ADJACENCY:                         return "lines_adjacency";
166                 case GL_LINE_STRIP_ADJACENCY:            return "line_strip_adjacency";
167                 case GL_TRIANGLES:                                       return "triangles";
168                 case GL_TRIANGLE_STRIP:                          return "triangle_strip";
169                 case GL_TRIANGLE_FAN:                            return "triangle_fan";
170                 case GL_TRIANGLES_ADJACENCY:             return "triangles_adjacency";
171                 case GL_TRIANGLE_STRIP_ADJACENCY:        return "triangle_strip_adjacency";
172                 default:
173                         DE_ASSERT(DE_FALSE);
174                         return "error";
175         }
176 }
177
178 struct OutputCountPatternSpec
179 {
180                                                 OutputCountPatternSpec (int count);
181                                                 OutputCountPatternSpec (int count0, int count1);
182
183         std::vector<int>        pattern;
184 };
185
186 OutputCountPatternSpec::OutputCountPatternSpec (int count)
187 {
188         pattern.push_back(count);
189 }
190
191 OutputCountPatternSpec::OutputCountPatternSpec (int count0, int count1)
192 {
193         pattern.push_back(count0);
194         pattern.push_back(count1);
195 }
196
197 class VertexExpanderShader : public sglr::ShaderProgram
198 {
199 public:
200                                 VertexExpanderShader    (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType);
201
202         void            shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
203         void            shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
204         void            shadePrimitives                 (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
205
206 private:
207         size_t          calcOutputVertices              (rr::GeometryShaderInputType inputType) const;
208         std::string     genGeometrySource               (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const;
209 };
210
211 VertexExpanderShader::VertexExpanderShader (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType)
212         : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
213                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
214                                                         << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
215                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
216                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
217                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
218                                                         << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
219                                                         << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
220                                                         << sglr::pdec::GeometryShaderDeclaration(inputType, outputType, calcOutputVertices(inputType))
221                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, inputType, outputType)))
222 {
223 }
224
225 void VertexExpanderShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
226 {
227         for (int ndx = 0; ndx < numPackets; ++ndx)
228         {
229                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
230                 packets[ndx]->pointSize = 1.0f;
231                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
232         }
233 }
234
235 void VertexExpanderShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
236 {
237         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
238         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
239                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
240 }
241
242 void VertexExpanderShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
243 {
244         DE_UNREF(invocationID);
245
246         for (int ndx = 0; ndx < numPackets; ++ndx)
247         for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
248         {
249                 const tcu::Vec4 offsets[] =
250                 {
251                         tcu::Vec4(-0.07f, -0.01f, 0.0f, 0.0f),
252                         tcu::Vec4( 0.03f, -0.03f, 0.0f, 0.0f),
253                         tcu::Vec4(-0.01f,  0.08f, 0.0f, 0.0f)
254                 };
255                 const tcu::Vec4 yoffset = float(packets[ndx].primitiveIDIn) * tcu::Vec4(0.02f, 0.1f, 0, 0);
256
257                 // Create new primitive at every input vertice
258                 const rr::VertexPacket* vertex = packets[ndx].vertices[verticeNdx];
259
260                 output.EmitVertex(vertex->position + offsets[0] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
261                 output.EmitVertex(vertex->position + offsets[1] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
262                 output.EmitVertex(vertex->position + offsets[2] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
263                 output.EndPrimitive();
264         }
265 }
266
267 size_t VertexExpanderShader::calcOutputVertices (rr::GeometryShaderInputType inputType) const
268 {
269         switch (inputType)
270         {
271                 case rr::GEOMETRYSHADERINPUTTYPE_POINTS:                                return 1 * 3;
272                 case rr::GEOMETRYSHADERINPUTTYPE_LINES:                                 return 2 * 3;
273                 case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:               return 4 * 3;
274                 case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:                             return 3 * 3;
275                 case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:   return 6 * 3;
276                 default:
277                         DE_ASSERT(DE_FALSE);
278                         return 0;
279         }
280 }
281
282 std::string     VertexExpanderShader::genGeometrySource (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const
283 {
284         std::ostringstream str;
285
286         str << "${GLSL_VERSION_DECL}\n";
287         str << "${GLSL_EXT_GEOMETRY_SHADER}";
288         str << "layout(" << inputTypeToGLString(inputType) << ") in;\n";
289         str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << calcOutputVertices(inputType) << ") out;";
290         str << "\n";
291         str << s_expandShaderSourceGeometryBody;
292
293         return specializeShader(str.str(), contextType);
294 }
295
296 class VertexEmitterShader : public sglr::ShaderProgram
297 {
298 public:
299                                 VertexEmitterShader             (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType);
300
301         void            shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
302         void            shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
303         void            shadePrimitives                 (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
304
305 private:
306         std::string     genGeometrySource               (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const;
307
308         int                     m_emitCountA;
309         int                     m_endCountA;
310         int                     m_emitCountB;
311         int                     m_endCountB;
312 };
313
314 VertexEmitterShader::VertexEmitterShader (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType)
315         : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
316                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
317                                                         << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
318                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
319                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
320                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
321                                                         << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
322                                                         << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
323                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, outputType, emitCountA + emitCountB)
324                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, emitCountA, endCountA, emitCountB, endCountB, outputType)))
325         , m_emitCountA          (emitCountA)
326         , m_endCountA           (endCountA)
327         , m_emitCountB          (emitCountB)
328         , m_endCountB           (endCountB)
329 {
330 }
331
332 void VertexEmitterShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
333 {
334         for (int ndx = 0; ndx < numPackets; ++ndx)
335         {
336                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
337                 packets[ndx]->pointSize = 1.0f;
338                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
339         }
340 }
341
342 void VertexEmitterShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
343 {
344         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
345         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
346                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
347 }
348
349 void VertexEmitterShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
350 {
351         DE_UNREF(verticesIn);
352         DE_UNREF(invocationID);
353
354         for (int ndx = 0; ndx < numPackets; ++ndx)
355         {
356                 const tcu::Vec4 positions[] =
357                 {
358                         tcu::Vec4(-0.5f,   0.5f, 0.0f, 0.0f),
359                         tcu::Vec4( 0.0f,   0.1f, 0.0f, 0.0f),
360                         tcu::Vec4( 0.5f,   0.5f, 0.0f, 0.0f),
361                         tcu::Vec4( 0.7f,  -0.2f, 0.0f, 0.0f),
362                         tcu::Vec4( 0.2f,   0.2f, 0.0f, 0.0f),
363                         tcu::Vec4( 0.4f,  -0.3f, 0.0f, 0.0f),
364                 };
365
366                 // Create new primitive at this point
367                 const rr::VertexPacket* vertex = packets[ndx].vertices[0];
368
369                 for (int i = 0; i < m_emitCountA; ++i)
370                         output.EmitVertex(vertex->position + positions[i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
371
372                 for (int i = 0; i < m_endCountA; ++i)
373                         output.EndPrimitive();
374
375                 for (int i = 0; i < m_emitCountB; ++i)
376                         output.EmitVertex(vertex->position + positions[m_emitCountA + i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
377
378                 for (int i = 0; i < m_endCountB; ++i)
379                         output.EndPrimitive();
380         }
381 }
382
383 std::string     VertexEmitterShader::genGeometrySource (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const
384 {
385         std::ostringstream str;
386
387         str << "${GLSL_VERSION_DECL}\n";
388         str << "${GLSL_EXT_GEOMETRY_SHADER}";
389         str << "layout(points) in;\n";
390         str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << (emitCountA+emitCountB) << ") out;";
391         str << "\n";
392
393         str <<  "in highp vec4 v_geom_FragColor[];\n"
394                         "out highp vec4 v_frag_FragColor;\n"
395                         "\n"
396                         "void main (void)\n"
397                         "{\n"
398                         "       const highp vec4 position0 = vec4(-0.5,  0.5, 0.0, 0.0);\n"
399                         "       const highp vec4 position1 = vec4( 0.0,  0.1, 0.0, 0.0);\n"
400                         "       const highp vec4 position2 = vec4( 0.5,  0.5, 0.0, 0.0);\n"
401                         "       const highp vec4 position3 = vec4( 0.7, -0.2, 0.0, 0.0);\n"
402                         "       const highp vec4 position4 = vec4( 0.2,  0.2, 0.0, 0.0);\n"
403                         "       const highp vec4 position5 = vec4( 0.4, -0.3, 0.0, 0.0);\n"
404                         "\n";
405
406         for (int i = 0; i < emitCountA; ++i)
407                 str <<  "       gl_Position = gl_in[0].gl_Position + position" << i << ";\n"
408                                 "       gl_PrimitiveID = gl_PrimitiveIDIn;\n"
409                                 "       v_frag_FragColor = v_geom_FragColor[0];\n"
410                                 "       EmitVertex();\n"
411                                 "\n";
412
413         for (int i = 0; i < endCountA; ++i)
414                 str << "        EndPrimitive();\n";
415
416         for (int i = 0; i < emitCountB; ++i)
417                 str <<  "       gl_Position = gl_in[0].gl_Position + position" << (emitCountA + i) << ";\n"
418                                 "       gl_PrimitiveID = gl_PrimitiveIDIn;\n"
419                                 "       v_frag_FragColor = v_geom_FragColor[0];\n"
420                                 "       EmitVertex();\n"
421                                 "\n";
422
423         for (int i = 0; i < endCountB; ++i)
424                 str << "        EndPrimitive();\n";
425
426         str << "}\n";
427
428         return specializeShader(str.str(), contextType);
429 }
430
431 class VertexVaryingShader : public sglr::ShaderProgram
432 {
433 public:
434                                                                                                 VertexVaryingShader             (const glu::ContextType& contextType, int vertexOut, int geometryOut);
435
436         void                                                                            shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
437         void                                                                            shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
438         void                                                                            shadePrimitives                 (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
439
440 private:
441         static sglr::pdec::ShaderProgramDeclaration genProgramDeclaration       (const glu::ContextType& contextType, int vertexOut, int geometryOut);
442
443         const int                                                                       m_vertexOut;
444         const int                                                                       m_geometryOut;
445 };
446
447 VertexVaryingShader::VertexVaryingShader (const glu::ContextType& contextType, int vertexOut, int geometryOut)
448         : sglr::ShaderProgram   (genProgramDeclaration(contextType, vertexOut, geometryOut))
449         , m_vertexOut                   (vertexOut)
450         , m_geometryOut                 (geometryOut)
451 {
452 }
453
454 void VertexVaryingShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
455 {
456         // vertex shader is no-op
457         if (m_vertexOut == -1)
458                 return;
459
460         for (int ndx = 0; ndx < numPackets; ++ndx)
461         {
462                 const tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
463
464                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
465                 packets[ndx]->pointSize = 1.0f;
466
467                 switch (m_vertexOut)
468                 {
469                         case 0:
470                                 break;
471
472                         case 1:
473                                 packets[ndx]->outputs[0] = color;
474                                 break;
475
476                         case 2:
477                                 packets[ndx]->outputs[0] = color * 0.5f;
478                                 packets[ndx]->outputs[1] = color.swizzle(2,1,0,3) * 0.5f;
479                                 break;
480
481                         default:
482                                 DE_ASSERT(DE_FALSE);
483                 }
484         }
485 }
486
487 void VertexVaryingShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
488 {
489         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
490         {
491                 switch (m_geometryOut)
492                 {
493                         case 0:
494                                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
495                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
496                                 break;
497
498                         case 1:
499                                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
500                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
501                                 break;
502
503                         case 2:
504                                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
505                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,   rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx)
506                                                                                                 + rr::readTriangleVarying<float>(packets[packetNdx], context, 1, fragNdx).swizzle(1, 0, 2, 3));
507                                 break;
508
509                         default:
510                                 DE_ASSERT(DE_FALSE);
511                 }
512         }
513 }
514
515 void VertexVaryingShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
516 {
517         DE_UNREF(invocationID);
518
519         const tcu::Vec4 vertexOffset(-0.2f, -0.2f, 0, 0);
520
521         if (m_vertexOut == -1)
522         {
523                 // vertex is a no-op
524                 const tcu::Vec4 inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
525                 rr::GenericVec4 outputs[2];
526
527                 // output color
528                 switch (m_geometryOut)
529                 {
530                         case 0:
531                                 break;
532
533                         case 1:
534                                 outputs[0] = inputColor;
535                                 break;
536
537                         case 2:
538                                 outputs[0] = inputColor * 0.5f;
539                                 outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
540                                 break;
541
542                         default:
543                                 DE_ASSERT(DE_FALSE);
544                 }
545
546                 for (int ndx = 0; ndx < numPackets; ++ndx)
547                 {
548                         output.EmitVertex(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
549                         output.EmitVertex(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
550                         output.EmitVertex(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
551                         output.EndPrimitive();
552                 }
553         }
554         else
555         {
556                 // vertex is not a no-op
557                 for (int ndx = 0; ndx < numPackets; ++ndx)
558                 {
559                         for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
560                         {
561                                 tcu::Vec4               inputColor;
562                                 rr::GenericVec4 outputs[2];
563
564                                 // input color
565                                 switch (m_vertexOut)
566                                 {
567                                         case 0:
568                                                 inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
569                                                 break;
570
571                                         case 1:
572                                                 inputColor = packets[ndx].vertices[verticeNdx]->outputs[0].get<float>();
573                                                 break;
574
575                                         case 2:
576                                                 inputColor = (packets[ndx].vertices[verticeNdx]->outputs[0].get<float>() * 0.5f)
577                                                                    + (packets[ndx].vertices[verticeNdx]->outputs[1].get<float>().swizzle(2, 1, 0, 3) * 0.5f);
578                                                 break;
579
580                                         default:
581                                                 DE_ASSERT(DE_FALSE);
582                                 }
583
584                                 // output color
585                                 switch (m_geometryOut)
586                                 {
587                                         case 0:
588                                                 break;
589
590                                         case 1:
591                                                 outputs[0] = inputColor;
592                                                 break;
593
594                                         case 2:
595                                                 outputs[0] = inputColor * 0.5f;
596                                                 outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
597                                                 break;
598
599                                         default:
600                                                 DE_ASSERT(DE_FALSE);
601                                 }
602
603                                 output.EmitVertex(packets[ndx].vertices[verticeNdx]->position + vertexOffset, packets[ndx].vertices[verticeNdx]->pointSize, outputs, packets[ndx].primitiveIDIn);
604                         }
605                         output.EndPrimitive();
606                 }
607         }
608 }
609
610 sglr::pdec::ShaderProgramDeclaration VertexVaryingShader::genProgramDeclaration (const glu::ContextType& contextType, int vertexOut, int geometryOut)
611 {
612         sglr::pdec::ShaderProgramDeclaration    decl;
613         std::ostringstream                                              vertexSource;
614         std::ostringstream                                              fragmentSource;
615         std::ostringstream                                              geometrySource;
616
617         decl
618                 << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
619                 << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT);
620
621         for (int i = 0; i < vertexOut; ++i)
622                 decl << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT);
623         for (int i = 0; i < geometryOut; ++i)
624                 decl << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
625
626         decl
627                 << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
628                 << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, 3);
629
630         // vertexSource
631
632         vertexSource << "${GLSL_VERSION_DECL}\n"
633                                         "in highp vec4 a_position;\n"
634                                         "in highp vec4 a_color;\n";
635
636         // no-op case?
637         if (vertexOut == -1)
638         {
639                 vertexSource << "void main (void)\n"
640                                                 "{\n"
641                                                 "}\n";
642         }
643         else
644         {
645                 for (int i = 0; i < vertexOut; ++i)
646                         vertexSource << "out highp vec4 v_geom_" << i << ";\n";
647
648                 vertexSource << "void main (void)\n"
649                                                 "{\n"
650                                                 "\tgl_Position = a_position;\n"
651                                                 "\tgl_PointSize = 1.0;\n";
652                 switch (vertexOut)
653                 {
654                         case 0:
655                                 break;
656
657                         case 1:
658                                 vertexSource << "\tv_geom_0 = a_color;\n";
659                                 break;
660
661                         case 2:
662                                 vertexSource << "\tv_geom_0 = a_color * 0.5;\n";
663                                 vertexSource << "\tv_geom_1 = a_color.zyxw * 0.5;\n";
664                                 break;
665
666                         default:
667                                 DE_ASSERT(DE_FALSE);
668                 }
669                 vertexSource << "}\n";
670         }
671
672         // fragmentSource
673
674         fragmentSource <<       "${GLSL_VERSION_DECL}\n"
675                                                 "layout(location = 0) out mediump vec4 fragColor;\n";
676
677         for (int i = 0; i < geometryOut; ++i)
678                 fragmentSource << "in mediump vec4 v_frag_" << i << ";\n";
679
680         fragmentSource <<       "void main (void)\n"
681                                                 "{\n";
682         switch (geometryOut)
683         {
684                 case 0:
685                         fragmentSource << "\tfragColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
686                         break;
687
688                 case 1:
689                         fragmentSource << "\tfragColor = v_frag_0;\n";
690                         break;
691
692                 case 2:
693                         fragmentSource << "\tfragColor = v_frag_0 + v_frag_1.yxzw;\n";
694                         break;
695
696                 default:
697                         DE_ASSERT(DE_FALSE);
698         }
699         fragmentSource << "}\n";
700
701         // geometrySource
702
703         geometrySource <<       "${GLSL_VERSION_DECL}\n"
704                                                 "${GLSL_EXT_GEOMETRY_SHADER}"
705                                                 "layout(triangles) in;\n"
706                                                 "layout(triangle_strip, max_vertices = 3) out;\n";
707
708         for (int i = 0; i < vertexOut; ++i)
709                 geometrySource << "in highp vec4 v_geom_" << i << "[];\n";
710         for (int i = 0; i < geometryOut; ++i)
711                 geometrySource << "out highp vec4 v_frag_" << i << ";\n";
712
713         geometrySource <<       "void main (void)\n"
714                                                 "{\n"
715                                                 "\thighp vec4 offset = vec4(-0.2, -0.2, 0.0, 0.0);\n"
716                                                 "\thighp vec4 inputColor;\n\n";
717
718         for (int vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
719         {
720                 if (vertexOut == -1)
721                 {
722                         // vertex is a no-op
723                         geometrySource <<       "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
724                                                                 "\tgl_Position = vec4(" << ((vertexNdx==0) ? ("0.0, 0.0") : ((vertexNdx==1) ? ("1.0, 0.0") : ("1.0, 1.0"))) << ", 0.0, 1.0) + offset;\n"
725                                                                 "\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
726                 }
727                 else
728                 {
729                         switch (vertexOut)
730                         {
731                                 case 0:
732                                         geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
733                                         break;
734
735                                 case 1:
736                                         geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "];\n";
737                                         break;
738
739                                 case 2:
740                                         geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "] * 0.5 + v_geom_1[" << vertexNdx << "].zyxw * 0.5;\n";
741                                         break;
742
743                                 default:
744                                         DE_ASSERT(DE_FALSE);
745                         }
746                         geometrySource <<       "\tgl_Position = gl_in[" << vertexNdx << "].gl_Position + offset;\n"
747                                                                 "\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
748                 }
749
750                 switch (geometryOut)
751                 {
752                         case 0:
753                                 break;
754
755                         case 1:
756                                 geometrySource << "\tv_frag_0 = inputColor;\n";
757                                 break;
758
759                         case 2:
760                                 geometrySource << "\tv_frag_0 = inputColor * 0.5;\n";
761                                 geometrySource << "\tv_frag_1 = inputColor.yxzw * 0.5;\n";
762                                 break;
763
764                         default:
765                                 DE_ASSERT(DE_FALSE);
766                 }
767
768                 geometrySource << "\tEmitVertex();\n\n";
769         }
770
771         geometrySource <<       "\tEndPrimitive();\n"
772                                                 "}\n";
773
774         decl
775                 << sglr::pdec::VertexSource(specializeShader(vertexSource.str(), contextType))
776                 << sglr::pdec::FragmentSource(specializeShader(fragmentSource.str(), contextType))
777                 << sglr::pdec::GeometrySource(specializeShader(geometrySource.str(), contextType));
778         return decl;
779 }
780
781 class OutputCountShader : public sglr::ShaderProgram
782 {
783 public:
784                                                                         OutputCountShader               (const glu::ContextType& contextType, const OutputCountPatternSpec& spec);
785
786         void                                                    shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
787         void                                                    shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
788         void                                                    shadePrimitives                 (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
789
790 private:
791         std::string                                             genGeometrySource               (const glu::ContextType& contextType, const OutputCountPatternSpec& spec) const;
792         size_t                                                  getPatternEmitCount             (const OutputCountPatternSpec& spec) const;
793
794         const int                                               m_patternLength;
795         const int                                               m_patternMaxEmitCount;
796         const OutputCountPatternSpec    m_spec;
797 };
798
799 OutputCountShader::OutputCountShader (const glu::ContextType& contextType, const OutputCountPatternSpec& spec)
800         : sglr::ShaderProgram   (sglr::pdec::ShaderProgramDeclaration()
801                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
802                                                         << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
803                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
804                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
805                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
806                                                         << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
807                                                         << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
808                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, getPatternEmitCount(spec))
809                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, spec)))
810         , m_patternLength               ((int)spec.pattern.size())
811         , m_patternMaxEmitCount ((int)getPatternEmitCount(spec))
812         , m_spec                                (spec)
813 {
814 }
815
816 void OutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
817 {
818         for (int ndx = 0; ndx < numPackets; ++ndx)
819         {
820                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
821                 packets[ndx]->pointSize = 1.0f;
822                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
823         }
824 }
825
826 void OutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
827 {
828         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
829         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
830                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
831 }
832
833 void OutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
834 {
835         DE_UNREF(verticesIn);
836         DE_UNREF(invocationID);
837
838         const float rowHeight   = 2.0f / (float)m_patternLength;
839         const float colWidth    = 2.0f / (float)m_patternMaxEmitCount;
840
841         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
842         {
843                 // Create triangle strip at this point
844                 const rr::VertexPacket* vertex          = packets[packetNdx].vertices[0];
845                 const int                               emitCount       = m_spec.pattern[packets[packetNdx].primitiveIDIn];
846
847                 for (int ndx = 0; ndx < emitCount / 2; ++ndx)
848                 {
849                         output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, 0.0,       0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
850                         output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, rowHeight, 0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
851                 }
852                 output.EndPrimitive();
853         }
854 }
855
856 std::string     OutputCountShader::genGeometrySource (const glu::ContextType& contextType, const OutputCountPatternSpec& spec) const
857 {
858         std::ostringstream str;
859
860         // draw row with a triangle strip, always make rectangles
861         for (int ndx = 0; ndx < (int)spec.pattern.size(); ++ndx)
862                 DE_ASSERT(spec.pattern[ndx] % 2 == 0);
863
864         str << "${GLSL_VERSION_DECL}\n";
865         str << "${GLSL_EXT_GEOMETRY_SHADER}";
866         str << "layout(points) in;\n";
867         str << "layout(triangle_strip, max_vertices = " << getPatternEmitCount(spec) << ") out;";
868         str << "\n";
869
870         str <<  "in highp vec4 v_geom_FragColor[];\n"
871                         "out highp vec4 v_frag_FragColor;\n"
872                         "\n"
873                         "void main (void)\n"
874                         "{\n"
875                         "       const highp float rowHeight = 2.0 / float(" << spec.pattern.size() << ");\n"
876                         "       const highp float colWidth = 2.0 / float(" << getPatternEmitCount(spec) << ");\n"
877                         "\n";
878
879         str <<  "       highp int emitCount = ";
880         for (int ndx = 0; ndx < (int)spec.pattern.size() - 1; ++ndx)
881                 str << "(gl_PrimitiveIDIn == " << ndx << ") ? (" << spec.pattern[ndx] << ") : (";
882         str <<  spec.pattern[(int)spec.pattern.size() - 1]
883                 <<      ((spec.pattern.size() == 1) ? ("") : (")"))
884                 <<      ";\n";
885
886         str <<  "       for (highp int ndx = 0; ndx < emitCount / 2; ndx++)\n"
887                         "       {\n"
888                         "               gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, 0.0, 0.0, 0.0);\n"
889                         "               v_frag_FragColor = v_geom_FragColor[0];\n"
890                         "               EmitVertex();\n"
891                         "\n"
892                         "               gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, rowHeight, 0.0, 0.0);\n"
893                         "               v_frag_FragColor = v_geom_FragColor[0];\n"
894                         "               EmitVertex();\n"
895                         "       }\n"
896                         "}\n";
897
898         return specializeShader(str.str(), contextType);
899 }
900
901 size_t OutputCountShader::getPatternEmitCount (const OutputCountPatternSpec& spec) const
902 {
903         return *std::max_element(spec.pattern.begin(), spec.pattern.end());
904 }
905
906 class BuiltinVariableShader : public sglr::ShaderProgram
907 {
908 public:
909         enum VariableTest
910         {
911                 TEST_POINT_SIZE = 0,
912                 TEST_PRIMITIVE_ID_IN,
913                 TEST_PRIMITIVE_ID,
914
915                 TEST_LAST
916         };
917
918                                                 BuiltinVariableShader   (const glu::ContextType& contextType, VariableTest test);
919
920         void                            shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
921         void                            shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
922         void                            shadePrimitives                 (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
923
924         static const char*      getTestAttributeName    (VariableTest test);
925
926 private:
927         std::string                     genGeometrySource               (const glu::ContextType& contextType, VariableTest test) const;
928         std::string                     genVertexSource                 (const glu::ContextType& contextType, VariableTest test) const;
929         std::string                     genFragmentSource               (const glu::ContextType& contextType, VariableTest test) const;
930
931         const VariableTest      m_test;
932 };
933
934 BuiltinVariableShader::BuiltinVariableShader (const glu::ContextType& contextType, VariableTest test)
935         : sglr::ShaderProgram   (sglr::pdec::ShaderProgramDeclaration()
936                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
937                                                         << sglr::pdec::VertexAttribute(getTestAttributeName(test), rr::GENERICVECTYPE_FLOAT)
938                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
939                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
940                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
941                                                         << sglr::pdec::VertexSource(genVertexSource(contextType, test))
942                                                         << sglr::pdec::FragmentSource(genFragmentSource(contextType, test))
943                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
944                                                                                                                                          ((test == TEST_POINT_SIZE) ? (rr::GEOMETRYSHADEROUTPUTTYPE_POINTS) : (rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP)),
945                                                                                                                                          ((test == TEST_POINT_SIZE) ? (1) : (3)))
946                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, test)))
947         , m_test                                (test)
948 {
949 }
950
951 void BuiltinVariableShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
952 {
953         for (int ndx = 0; ndx < numPackets; ++ndx)
954         {
955                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
956                 packets[ndx]->pointSize = 1.0f;
957                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
958         }
959 }
960
961 void BuiltinVariableShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
962 {
963         const tcu::Vec4 red                     = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
964         const tcu::Vec4 green           = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
965         const tcu::Vec4 blue            = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
966         const tcu::Vec4 yellow          = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
967         const tcu::Vec4 colors[4]       = { yellow, red, green, blue };
968
969         if (m_test == TEST_POINT_SIZE || m_test == TEST_PRIMITIVE_ID_IN)
970         {
971                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
972                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
973                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
974         }
975         else if (m_test == TEST_PRIMITIVE_ID)
976         {
977                 const tcu::Vec4 color = colors[context.primitiveID % 4];
978
979                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
980                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
981                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
982         }
983         else
984                 DE_ASSERT(DE_FALSE);
985 }
986
987 void BuiltinVariableShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
988 {
989         DE_UNREF(verticesIn);
990         DE_UNREF(invocationID);
991
992         const tcu::Vec4 red                     = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
993         const tcu::Vec4 green           = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
994         const tcu::Vec4 blue            = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
995         const tcu::Vec4 yellow          = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
996         const tcu::Vec4 colors[4]       = { red, green, blue, yellow };
997
998         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
999         {
1000                 const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
1001
1002                 if (m_test == TEST_POINT_SIZE)
1003                 {
1004                         rr::GenericVec4 fragColor;
1005                         const float             pointSize = vertex->outputs[0].get<float>().x() + 1.0f;
1006
1007                         fragColor = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
1008                         output.EmitVertex(vertex->position, pointSize, &fragColor, packets[packetNdx].primitiveIDIn);
1009                 }
1010                 else if (m_test == TEST_PRIMITIVE_ID_IN)
1011                 {
1012                         rr::GenericVec4 fragColor;
1013                         fragColor = colors[packets[packetNdx].primitiveIDIn % 4];
1014
1015                         output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1016                         output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1017                         output.EmitVertex(vertex->position + tcu::Vec4(0.0f,  0.05f, 0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1018                 }
1019                 else if (m_test == TEST_PRIMITIVE_ID)
1020                 {
1021                         const int primitiveID = (int)deFloatFloor(vertex->outputs[0].get<float>().x()) + 3;
1022
1023                         output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1024                         output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1025                         output.EmitVertex(vertex->position + tcu::Vec4(0.0f,  0.05f, 0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1026                 }
1027                 else
1028                         DE_ASSERT(DE_FALSE);
1029
1030                 output.EndPrimitive();
1031         }
1032 }
1033
1034 const char* BuiltinVariableShader::getTestAttributeName (VariableTest test)
1035 {
1036         switch (test)
1037         {
1038                 case TEST_POINT_SIZE:                   return "a_pointSize";
1039                 case TEST_PRIMITIVE_ID_IN:              return "";
1040                 case TEST_PRIMITIVE_ID:                 return "a_primitiveID";
1041                 default:
1042                         DE_ASSERT(DE_FALSE);
1043                         return "";
1044         }
1045 }
1046
1047 std::string BuiltinVariableShader::genGeometrySource (const glu::ContextType& contextType, VariableTest test) const
1048 {
1049         std::ostringstream buf;
1050
1051         buf <<  "${GLSL_VERSION_DECL}\n"
1052                         "${GLSL_EXT_GEOMETRY_SHADER}";
1053
1054         if (test == TEST_POINT_SIZE)
1055                 buf << "#extension GL_EXT_geometry_point_size : require\n";
1056
1057         buf << "layout(points) in;\n";
1058
1059         if (test == TEST_POINT_SIZE)
1060                 buf << "layout(points, max_vertices = 1) out;\n";
1061         else
1062                 buf << "layout(triangle_strip, max_vertices = 3) out;\n";
1063
1064         if (test == TEST_POINT_SIZE)
1065                 buf << "in highp vec4 v_geom_pointSize[];\n";
1066         else if (test == TEST_PRIMITIVE_ID)
1067                 buf << "in highp vec4 v_geom_primitiveID[];\n";
1068
1069         if (test != TEST_PRIMITIVE_ID)
1070                 buf << "out highp vec4 v_frag_FragColor;\n";
1071
1072         buf <<  "\n"
1073                         "void main (void)\n"
1074                         "{\n";
1075
1076         if (test == TEST_POINT_SIZE)
1077         {
1078                 buf <<  "       gl_Position = gl_in[0].gl_Position;\n"
1079                                 "       gl_PointSize = v_geom_pointSize[0].x + 1.0;\n"
1080                                 "       v_frag_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1081                                 "       EmitVertex();\n";
1082         }
1083         else if (test == TEST_PRIMITIVE_ID_IN)
1084         {
1085                 buf <<  "       const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1086                                 "       const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1087                                 "       const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1088                                 "       const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1089                                 "       const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1090                                 "\n"
1091                                 "       gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1092                                 "       v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1093                                 "       EmitVertex();\n"
1094                                 "\n"
1095                                 "       gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1096                                 "       v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1097                                 "       EmitVertex();\n"
1098                                 "\n"
1099                                 "       gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1100                                 "       v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1101                                 "       EmitVertex();\n";
1102         }
1103         else if (test == TEST_PRIMITIVE_ID)
1104         {
1105                 buf <<  "       gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1106                                 "       gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1107                                 "       EmitVertex();\n"
1108                                 "\n"
1109                                 "       gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1110                                 "       gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1111                                 "       EmitVertex();\n"
1112                                 "\n"
1113                                 "       gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1114                                 "       gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1115                                 "       EmitVertex();\n"
1116                                 "\n";
1117         }
1118         else
1119                 DE_ASSERT(DE_FALSE);
1120
1121         buf << "}\n";
1122
1123         return specializeShader(buf.str(), contextType);
1124 }
1125
1126 std::string BuiltinVariableShader::genVertexSource (const glu::ContextType& contextType, VariableTest test) const
1127 {
1128         std::ostringstream buf;
1129
1130         buf <<  "${GLSL_VERSION_DECL}\n"
1131                         "in highp vec4 a_position;\n";
1132
1133         if (test == TEST_POINT_SIZE)
1134                 buf << "in highp vec4 a_pointSize;\n";
1135         else if (test == TEST_PRIMITIVE_ID)
1136                 buf << "in highp vec4 a_primitiveID;\n";
1137
1138         if (test == TEST_POINT_SIZE)
1139                 buf << "out highp vec4 v_geom_pointSize;\n";
1140         else if (test == TEST_PRIMITIVE_ID)
1141                 buf << "out highp vec4 v_geom_primitiveID;\n";
1142
1143         buf <<  "void main (void)\n"
1144                         "{\n"
1145                         "       gl_Position = a_position;\n"
1146                         "       gl_PointSize = 1.0;\n";
1147
1148         if (test == TEST_POINT_SIZE)
1149                 buf << "        v_geom_pointSize = a_pointSize;\n";
1150         else if (test == TEST_PRIMITIVE_ID)
1151                 buf << "        v_geom_primitiveID = a_primitiveID;\n";
1152
1153         buf <<  "}\n";
1154
1155         return specializeShader(buf.str(), contextType);
1156 }
1157
1158 std::string BuiltinVariableShader::genFragmentSource (const glu::ContextType& contextType, VariableTest test) const
1159 {
1160         std::ostringstream buf;
1161
1162         if (test == TEST_POINT_SIZE || test == TEST_PRIMITIVE_ID_IN)
1163                 return specializeShader(s_commonShaderSourceFragment, contextType);
1164         else if (test == TEST_PRIMITIVE_ID)
1165         {
1166                 buf <<  "${GLSL_VERSION_DECL}\n"
1167                                 "${GLSL_EXT_GEOMETRY_SHADER}"
1168                                 "layout(location = 0) out mediump vec4 fragColor;\n"
1169                                 "void main (void)\n"
1170                                 "{\n"
1171                                 "       const mediump vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1172                                 "       const mediump vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1173                                 "       const mediump vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1174                                 "       const mediump vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1175                                 "       const mediump vec4 colors[4] = vec4[4](yellow, red, green, blue);\n"
1176                                 "       fragColor = colors[gl_PrimitiveID % 4];\n"
1177                                 "}\n";
1178
1179                 return specializeShader(buf.str(), contextType);
1180         }
1181         else
1182         {
1183                 DE_ASSERT(DE_FALSE);
1184                 return DE_NULL;
1185         }
1186 }
1187
1188 class VaryingOutputCountShader : public sglr::ShaderProgram
1189 {
1190 public:
1191         enum VaryingSource
1192         {
1193                 READ_ATTRIBUTE = 0,
1194                 READ_UNIFORM,
1195                 READ_TEXTURE,
1196
1197                 READ_LAST
1198         };
1199
1200         enum
1201         {
1202                 EMIT_COUNT_VERTEX_0 = 6,
1203                 EMIT_COUNT_VERTEX_1 = 0,
1204                 EMIT_COUNT_VERTEX_2 = -1,
1205                 EMIT_COUNT_VERTEX_3 = 10,
1206         };
1207
1208                                                                 VaryingOutputCountShader        (const glu::ContextType& contextType, VaryingSource source, int maxEmitCount, bool instanced);
1209
1210         void                                            shadeVertices                           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1211         void                                            shadeFragments                          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1212         void                                            shadePrimitives                         (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1213
1214         static const char*                      getAttributeName                        (VaryingSource test);
1215
1216 private:
1217         static std::string                      genGeometrySource                       (const glu::ContextType& contextType, VaryingSource test, int maxEmitCount, bool instanced);
1218         static std::string                      genVertexSource                         (const glu::ContextType& contextType, VaryingSource test);
1219
1220         const VaryingSource                     m_test;
1221         const sglr::UniformSlot&        m_sampler;
1222         const sglr::UniformSlot&        m_emitCount;
1223         const int                                       m_maxEmitCount;
1224         const bool                                      m_instanced;
1225 };
1226
1227 VaryingOutputCountShader::VaryingOutputCountShader (const glu::ContextType& contextType, VaryingSource source, int maxEmitCount, bool instanced)
1228         : sglr::ShaderProgram   (sglr::pdec::ShaderProgramDeclaration()
1229                                                         << sglr::pdec::Uniform("u_sampler", glu::TYPE_SAMPLER_2D)
1230                                                         << sglr::pdec::Uniform("u_emitCount", glu::TYPE_INT_VEC4)
1231                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1232                                                         << sglr::pdec::VertexAttribute(getAttributeName(source), rr::GENERICVECTYPE_FLOAT)
1233                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1234                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1235                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1236                                                         << sglr::pdec::VertexSource(genVertexSource(contextType, source))
1237                                                         << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
1238                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1239                                                                                                                                          rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1240                                                                                                                                          maxEmitCount,
1241                                                                                                                                          (instanced) ? (4) : (1))
1242                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, source, maxEmitCount, instanced)))
1243         , m_test                                (source)
1244         , m_sampler                             (getUniformByName("u_sampler"))
1245         , m_emitCount                   (getUniformByName("u_emitCount"))
1246         , m_maxEmitCount                (maxEmitCount)
1247         , m_instanced                   (instanced)
1248 {
1249 }
1250
1251 void VaryingOutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1252 {
1253         for (int ndx = 0; ndx < numPackets; ++ndx)
1254         {
1255                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1256                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1257         }
1258 }
1259
1260 void VaryingOutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1261 {
1262         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1263         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1264                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1265 }
1266
1267 void VaryingOutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1268 {
1269         DE_UNREF(verticesIn);
1270
1271         const tcu::Vec4 red                     = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1272         const tcu::Vec4 green           = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1273         const tcu::Vec4 blue            = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1274         const tcu::Vec4 yellow          = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1275         const tcu::Vec4 colors[4]       = { red, green, blue, yellow };
1276
1277         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1278         {
1279                 const rr::VertexPacket* vertex          = packets[packetNdx].vertices[0];
1280                 int                                             emitCount       = 0;
1281                 tcu::Vec4                               color           = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1282
1283                 if (m_test == READ_ATTRIBUTE)
1284                 {
1285                         emitCount = (int)vertex->outputs[0].get<float>()[(m_instanced) ? (invocationID) : (0)];
1286                         color = tcu::Vec4((emitCount < 10) ? (0.0f) : (1.0f), (emitCount > 10) ? (0.0f) : (1.0f), 1.0f, 1.0f);
1287                 }
1288                 else if (m_test == READ_UNIFORM)
1289                 {
1290                         const int primitiveNdx = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1291
1292                         DE_ASSERT(primitiveNdx >= 0);
1293                         DE_ASSERT(primitiveNdx < 4);
1294
1295                         emitCount = m_emitCount.value.i4[primitiveNdx];
1296                         color = colors[primitiveNdx];
1297                 }
1298                 else if (m_test == READ_TEXTURE)
1299                 {
1300                         const int                       primitiveNdx    = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1301                         const tcu::Vec2         texCoord                = tcu::Vec2(1.0f / 8.0f + (float)primitiveNdx / 4.0f, 0.5f);
1302                         const tcu::Vec4         texColor                = m_sampler.sampler.tex2D->sample(texCoord.x(), texCoord.y(), 0.0f);
1303
1304                         DE_ASSERT(primitiveNdx >= 0);
1305                         DE_ASSERT(primitiveNdx < 4);
1306
1307                         color = colors[primitiveNdx];
1308                         emitCount = 0;
1309
1310                         if (texColor.x() > 0.0f)
1311                                 emitCount += (EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_0);
1312                         if (texColor.y() > 0.0f)
1313                                 emitCount += (EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_1);
1314                         if (texColor.z() > 0.0f)
1315                                 emitCount += (EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_2);
1316                         if (texColor.w() > 0.0f)
1317                                 emitCount += (EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_3);
1318                 }
1319                 else
1320                         DE_ASSERT(DE_FALSE);
1321
1322                 for (int ndx = 0; ndx < (int)emitCount / 2; ++ndx)
1323                 {
1324                         const float             angle                   = (float(ndx) + 0.5f) / float(emitCount / 2) * 3.142f;
1325                         const tcu::Vec4 basePosition    = (m_instanced) ?
1326                                                                                                 (vertex->position + tcu::Vec4(deFloatCos(float(invocationID)), deFloatSin(float(invocationID)), 0.0f, 0.0f) * 0.5f) :
1327                                                                                                 (vertex->position);
1328                         const tcu::Vec4 position0               = basePosition + tcu::Vec4(deFloatCos(angle),  deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1329                         const tcu::Vec4 position1               = basePosition + tcu::Vec4(deFloatCos(angle), -deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1330                         rr::GenericVec4 fragColor;
1331
1332                         fragColor = color;
1333
1334                         output.EmitVertex(position0, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1335                         output.EmitVertex(position1, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1336                 }
1337
1338                 output.EndPrimitive();
1339         }
1340 }
1341
1342 const char* VaryingOutputCountShader::getAttributeName (VaryingSource test)
1343 {
1344         switch (test)
1345         {
1346                 case READ_ATTRIBUTE:    return "a_emitCount";
1347                 case READ_UNIFORM:              return "a_vertexNdx";
1348                 case READ_TEXTURE:              return "a_vertexNdx";
1349                 default:
1350                         DE_ASSERT(DE_FALSE);
1351                         return "";
1352         }
1353 }
1354
1355 std::string VaryingOutputCountShader::genGeometrySource (const glu::ContextType& contextType, VaryingSource test, int maxEmitCount, bool instanced)
1356 {
1357         std::ostringstream buf;
1358
1359         buf <<  "${GLSL_VERSION_DECL}\n"
1360                         "${GLSL_EXT_GEOMETRY_SHADER}"
1361                         "layout(points" << ((instanced) ? (",invocations=4") : ("")) << ") in;\n"
1362                         "layout(triangle_strip, max_vertices = " << maxEmitCount << ") out;\n";
1363
1364         if (test == READ_ATTRIBUTE)
1365                 buf <<  "in highp vec4 v_geom_emitCount[];\n";
1366         else if (test == READ_UNIFORM)
1367                 buf <<  "in highp vec4 v_geom_vertexNdx[];\n"
1368                                 "uniform highp ivec4 u_emitCount;\n";
1369         else
1370                 buf <<  "in highp vec4 v_geom_vertexNdx[];\n"
1371                                 "uniform highp sampler2D u_sampler;\n";
1372
1373         buf <<  "out highp vec4 v_frag_FragColor;\n"
1374                         "\n"
1375                         "void main (void)\n"
1376                         "{\n";
1377
1378         // emit count
1379
1380         if (test == READ_ATTRIBUTE)
1381         {
1382                 buf <<  "       highp vec4 attrEmitCounts = v_geom_emitCount[0];\n"
1383                                 "       mediump int emitCount = int(attrEmitCounts[" << ((instanced) ? ("gl_InvocationID") : ("0")) << "]);\n";
1384         }
1385         else if (test == READ_UNIFORM)
1386         {
1387                 buf <<  "       mediump int primitiveNdx = " << ((instanced) ? ("gl_InvocationID") : ("int(v_geom_vertexNdx[0].x)")) << ";\n"
1388                                 "       mediump int emitCount = u_emitCount[primitiveNdx];\n";
1389         }
1390         else if (test == READ_TEXTURE)
1391         {
1392                 buf <<  "       highp float primitiveNdx = " << ((instanced) ? ("float(gl_InvocationID)") : ("v_geom_vertexNdx[0].x")) << ";\n"
1393                                 "       highp vec2 texCoord = vec2(1.0 / 8.0 + primitiveNdx / 4.0, 0.5);\n"
1394                                 "       highp vec4 texColor = texture(u_sampler, texCoord);\n"
1395                                 "       mediump int emitCount = 0;\n"
1396                                 "       if (texColor.x > 0.0)\n"
1397                                 "               emitCount += " << ((EMIT_COUNT_VERTEX_0 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_0)) << ";\n"
1398                                 "       if (texColor.y > 0.0)\n"
1399                                 "               emitCount += " << ((EMIT_COUNT_VERTEX_1 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_1)) << ";\n"
1400                                 "       if (texColor.z > 0.0)\n"
1401                                 "               emitCount += " << ((EMIT_COUNT_VERTEX_2 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_2)) << ";\n"
1402                                 "       if (texColor.w > 0.0)\n"
1403                                 "               emitCount += " << ((EMIT_COUNT_VERTEX_3 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_3)) << ";\n";
1404         }
1405         else
1406                 DE_ASSERT(DE_FALSE);
1407
1408         // color
1409
1410         if (test == READ_ATTRIBUTE)
1411         {
1412                 // We don't want color to be compile time constant
1413                 buf <<  "       highp vec4 color = vec4((emitCount < 10) ? (0.0) : (1.0), (emitCount > 10) ? (0.0) : (1.0), 1.0, 1.0);\n";
1414         }
1415         else if (test == READ_UNIFORM || test == READ_TEXTURE)
1416         {
1417                 buf <<  "\n"
1418                                 "       const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1419                                 "       const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1420                                 "       const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1421                                 "       const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1422                                 "       const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1423                                 "       highp vec4 color = colors[int(primitiveNdx)];\n";
1424         }
1425         else
1426                 DE_ASSERT(DE_FALSE);
1427
1428         buf <<  "\n"
1429                         "       highp vec4 basePos = " << ((instanced) ? ("gl_in[0].gl_Position + 0.5 * vec4(cos(float(gl_InvocationID)), sin(float(gl_InvocationID)), 0.0, 0.0)") : ("gl_in[0].gl_Position")) << ";\n"
1430                         "       for (mediump int i = 0; i < emitCount / 2; i++)\n"
1431                         "       {\n"
1432                         "               highp float angle = (float(i) + 0.5) / float(emitCount / 2) * 3.142;\n"
1433                         "               gl_Position = basePos + vec4(cos(angle),  sin(angle), 0.0, 0.0) * 0.15;\n"
1434                         "               v_frag_FragColor = color;\n"
1435                         "               EmitVertex();\n"
1436                         "               gl_Position = basePos + vec4(cos(angle), -sin(angle), 0.0, 0.0) * 0.15;\n"
1437                         "               v_frag_FragColor = color;\n"
1438                         "               EmitVertex();\n"
1439                         "       }"
1440                         "}\n";
1441
1442         return specializeShader(buf.str(), contextType);
1443 }
1444
1445 std::string VaryingOutputCountShader::genVertexSource (const glu::ContextType& contextType, VaryingSource test)
1446 {
1447         std::ostringstream buf;
1448
1449         buf <<  "${GLSL_VERSION_DECL}\n"
1450                         "in highp vec4 a_position;\n";
1451
1452         if (test == READ_ATTRIBUTE)
1453         {
1454                 buf << "in highp vec4 a_emitCount;\n";
1455                 buf << "out highp vec4 v_geom_emitCount;\n";
1456         }
1457         else if (test == READ_UNIFORM || test == READ_TEXTURE)
1458         {
1459                 buf << "in highp vec4 a_vertexNdx;\n";
1460                 buf << "out highp vec4 v_geom_vertexNdx;\n";
1461         }
1462
1463         buf <<  "void main (void)\n"
1464                         "{\n"
1465                         "       gl_Position = a_position;\n";
1466
1467         if (test == READ_ATTRIBUTE)
1468                 buf << "        v_geom_emitCount = a_emitCount;\n";
1469         else if (test == READ_UNIFORM || test == READ_TEXTURE)
1470                 buf << "        v_geom_vertexNdx = a_vertexNdx;\n";
1471
1472         buf <<  "}\n";
1473
1474         return specializeShader(buf.str(), contextType);
1475 }
1476
1477 class InvocationCountShader : public sglr::ShaderProgram
1478 {
1479 public:
1480         enum OutputCase
1481         {
1482                 CASE_FIXED_OUTPUT_COUNTS = 0,
1483                 CASE_DIFFERENT_OUTPUT_COUNTS,
1484
1485                 CASE_LAST
1486         };
1487
1488                                                 InvocationCountShader           (const glu::ContextType& contextType, int numInvocations, OutputCase testCase);
1489
1490 private:
1491         void                            shadeVertices                           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1492         void                            shadeFragments                          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1493         void                            shadePrimitives                         (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1494
1495         static std::string      genGeometrySource                       (const glu::ContextType& contextType, int numInvocations, OutputCase testCase);
1496         static size_t           getNumVertices                          (int numInvocations, OutputCase testCase);
1497
1498         const int                       m_numInvocations;
1499         const OutputCase        m_testCase;
1500 };
1501
1502 InvocationCountShader::InvocationCountShader (const glu::ContextType& contextType, int numInvocations, OutputCase testCase)
1503         : sglr::ShaderProgram   (sglr::pdec::ShaderProgramDeclaration()
1504                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1505                                                         << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
1506                                                         << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1507                                                         << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1508                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1509                                                         << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
1510                                                         << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
1511                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1512                                                                                                                                          rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1513                                                                                                                                          getNumVertices(numInvocations, testCase),
1514                                                                                                                                          numInvocations)
1515                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations, testCase)))
1516         , m_numInvocations              (numInvocations)
1517         , m_testCase                    (testCase)
1518 {
1519 }
1520
1521 void InvocationCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1522 {
1523         for (int ndx = 0; ndx < numPackets; ++ndx)
1524         {
1525                 packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1526                 packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1527         }
1528 }
1529
1530 void InvocationCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1531 {
1532         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1533         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1534                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1535 }
1536
1537 void InvocationCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1538 {
1539         DE_UNREF(verticesIn);
1540
1541         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1542         {
1543                 const float                             l_angle         = float(invocationID) / float(m_numInvocations) * 5.5f;
1544                 const float                             l_radius        = 0.6f;
1545
1546                 const rr::VertexPacket* vertex          = packets[packetNdx].vertices[0];
1547
1548                 if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
1549                 {
1550                         const tcu::Vec4                 position0       = vertex->position + tcu::Vec4(deFloatCos(l_angle)      * (l_radius - 0.1f), deFloatSin(l_angle)      * (l_radius - 0.1f), 0.0f, 0.0f);
1551                         const tcu::Vec4                 position1       = vertex->position + tcu::Vec4(deFloatCos(l_angle+0.1f) * l_radius,          deFloatSin(l_angle+0.1f) * l_radius,          0.0f, 0.0f);
1552                         const tcu::Vec4                 position2       = vertex->position + tcu::Vec4(deFloatCos(l_angle-0.1f) * l_radius,          deFloatSin(l_angle-0.1f) * l_radius,          0.0f, 0.0f);
1553
1554                         rr::GenericVec4                 tipColor;
1555                         rr::GenericVec4                 baseColor;
1556
1557                         tipColor  = tcu::Vec4(1.0, 1.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1558                         baseColor = tcu::Vec4(1.0, 0.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1559
1560                         output.EmitVertex(position0, 0.0f, &tipColor, packets[packetNdx].primitiveIDIn);
1561                         output.EmitVertex(position1, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1562                         output.EmitVertex(position2, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1563                         output.EndPrimitive();
1564                 }
1565                 else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1566                 {
1567                         const tcu::Vec4 color                   = tcu::Vec4(float(invocationID % 2), (((invocationID / 2) % 2) == 0) ? (1.0f) : (0.0f), 1.0f, 1.0f);
1568                         const tcu::Vec4 basePosition    = vertex->position + tcu::Vec4(deFloatCos(l_angle) * l_radius, deFloatSin(l_angle) * l_radius, 0.0f, 0.0f);
1569                         const int               numNgonVtx              = invocationID + 3;
1570
1571                         rr::GenericVec4 outColor;
1572                         outColor = color;
1573
1574                         for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)
1575                         {
1576                                 const float subAngle = (float(ndx) + 1.0f) / float(numNgonVtx) * 3.141f;
1577
1578                                 output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) *  0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1579                                 output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * -0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1580                         }
1581
1582                         if ((numNgonVtx % 2) == 1)
1583                                 output.EmitVertex(basePosition + tcu::Vec4(-0.1f, 0.0f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1584
1585                         output.EndPrimitive();
1586                 }
1587         }
1588 }
1589
1590 std::string InvocationCountShader::genGeometrySource (const glu::ContextType& contextType, int numInvocations, OutputCase testCase)
1591 {
1592         const int                       maxVertices = (int)getNumVertices(numInvocations, testCase);
1593         std::ostringstream      buf;
1594
1595         buf     <<      "${GLSL_VERSION_DECL}\n"
1596                         "${GLSL_EXT_GEOMETRY_SHADER}"
1597                         "layout(points, invocations = " << numInvocations << ") in;\n"
1598                         "layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n"
1599                         "\n"
1600                         "in highp vec4 v_geom_FragColor[];\n"
1601                         "out highp vec4 v_frag_FragColor;\n"
1602                         "\n"
1603                         "void main ()\n"
1604                         "{\n"
1605                         "       highp float l_angle = float(gl_InvocationID) / float(" << numInvocations << ") * 5.5;\n"
1606                         "       highp float l_radius = 0.6;\n"
1607                         "\n";
1608
1609         if (testCase == CASE_FIXED_OUTPUT_COUNTS)
1610         {
1611                 buf <<  "       v_frag_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1612                                 "       gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle) * (l_radius - 0.1), sin(l_angle) * (l_radius - 0.1), 0.0, 0.0);\n"
1613                                 "       EmitVertex();\n"
1614                                 "\n"
1615                                 "       v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1616                                 "       gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle+0.1) * l_radius, sin(l_angle+0.1) * l_radius, 0.0, 0.0);\n"
1617                                 "       EmitVertex();\n"
1618                                 "\n"
1619                                 "       v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1620                                 "       gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle-0.1) * l_radius, sin(l_angle-0.1) * l_radius, 0.0, 0.0);\n"
1621                                 "       EmitVertex();\n";
1622         }
1623         else if (testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1624         {
1625                 buf <<  "       highp vec4 l_color = vec4(float(gl_InvocationID % 2), (((gl_InvocationID / 2) % 2) == 0) ? (1.0) : (0.0), 1.0, 1.0);\n"
1626                                 "       highp vec4 basePosition = gl_in[0].gl_Position + vec4(cos(l_angle) * l_radius, sin(l_angle) * l_radius, 0.0, 0.0);\n"
1627                                 "       mediump int numNgonVtx = gl_InvocationID + 3;\n"
1628                                 "\n"
1629                                 "       for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)\n"
1630                                 "       {\n"
1631                                 "               highp float sub_angle = (float(ndx) + 1.0) / float(numNgonVtx) * 3.141;\n"
1632                                 "\n"
1633                                 "               v_frag_FragColor = l_color;\n"
1634                                 "               gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * 0.1, 0.0, 0.0);\n"
1635                                 "               EmitVertex();\n"
1636                                 "\n"
1637                                 "               v_frag_FragColor = l_color;\n"
1638                                 "               gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * -0.1, 0.0, 0.0);\n"
1639                                 "               EmitVertex();\n"
1640                                 "       }\n"
1641                                 "       if ((numNgonVtx % 2) == 1)\n"
1642                                 "       {\n"
1643                                 "               v_frag_FragColor = l_color;\n"
1644                                 "               gl_Position = basePosition + vec4(-0.1, 0.0, 0.0, 0.0);\n"
1645                                 "               EmitVertex();\n"
1646                                 "       }\n";
1647         }
1648         else
1649                 DE_ASSERT(false);
1650
1651         buf <<  "}\n";
1652
1653         return specializeShader(buf.str(), contextType);
1654 }
1655
1656 size_t InvocationCountShader::getNumVertices (int numInvocations, OutputCase testCase)
1657 {
1658         switch (testCase)
1659         {
1660                 case CASE_FIXED_OUTPUT_COUNTS:                  return 3;
1661                 case CASE_DIFFERENT_OUTPUT_COUNTS:              return (size_t)(2 + numInvocations);
1662                 default:
1663                         DE_ASSERT(false);
1664                         return 0;
1665         }
1666 }
1667
1668 class InstancedExpansionShader : public sglr::ShaderProgram
1669 {
1670 public:
1671                                                                 InstancedExpansionShader        (const glu::ContextType& contextType, int numInvocations);
1672
1673 private:
1674         void                                            shadeVertices                           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1675         void                                            shadeFragments                          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1676         void                                            shadePrimitives                         (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1677
1678         static std::string                      genVertexSource                         (const glu::ContextType& contextType);
1679         static std::string                      genFragmentSource                       (const glu::ContextType& contextType);
1680         static std::string                      genGeometrySource                       (const glu::ContextType& contextType, int numInvocations);
1681
1682         const int                                       m_numInvocations;
1683 };
1684
1685 InstancedExpansionShader::InstancedExpansionShader (const glu::ContextType& contextType, int numInvocations)
1686         : sglr::ShaderProgram   (sglr::pdec::ShaderProgramDeclaration()
1687                                                         << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1688                                                         << sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
1689                                                         << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1690                                                         << sglr::pdec::VertexSource(genVertexSource(contextType))
1691                                                         << sglr::pdec::FragmentSource(genFragmentSource(contextType))
1692                                                         << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1693                                                                                                                                          rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1694                                                                                                                                          4,
1695                                                                                                                                          numInvocations)
1696                                                         << sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations)))
1697         , m_numInvocations              (numInvocations)
1698 {
1699 }
1700
1701 void InstancedExpansionShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1702 {
1703         for (int ndx = 0; ndx < numPackets; ++ndx)
1704         {
1705                 packets[ndx]->position =        rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
1706                                                                         rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1707         }
1708 }
1709
1710 void InstancedExpansionShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1711 {
1712         DE_UNREF(packets);
1713
1714         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1715         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1716                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1717 }
1718
1719 void InstancedExpansionShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1720 {
1721         DE_UNREF(verticesIn);
1722
1723         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1724         {
1725                 const rr::VertexPacket* vertex                  = packets[packetNdx].vertices[0];
1726                 const tcu::Vec4                 basePosition    = vertex->position;
1727                 const float                             phase                   = float(invocationID) / float(m_numInvocations) * 6.3f;
1728                 const tcu::Vec4                 centerPosition  = basePosition + tcu::Vec4(deFloatCos(phase), deFloatSin(phase), 0.0f, 0.0f) * 0.1f;
1729
1730                 output.EmitVertex(centerPosition + tcu::Vec4( 0.0f,  -0.1f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1731                 output.EmitVertex(centerPosition + tcu::Vec4(-0.05f,  0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1732                 output.EmitVertex(centerPosition + tcu::Vec4( 0.05f,  0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1733                 output.EndPrimitive();
1734         }
1735 }
1736
1737 std::string InstancedExpansionShader::genVertexSource (const glu::ContextType& contextType)
1738 {
1739         std::ostringstream buf;
1740
1741         buf <<  "${GLSL_VERSION_DECL}\n"
1742                         "in highp vec4 a_position;\n"
1743                         "in highp vec4 a_offset;\n"
1744                         "void main (void)\n"
1745                         "{\n"
1746                         "       gl_Position = a_position + a_offset;\n"
1747                         "}\n";
1748
1749         return specializeShader(buf.str(), contextType);
1750 }
1751
1752 std::string InstancedExpansionShader::genFragmentSource (const glu::ContextType& contextType)
1753 {
1754         std::ostringstream buf;
1755
1756         buf <<  "${GLSL_VERSION_DECL}\n"
1757                         "layout(location = 0) out mediump vec4 fragColor;\n"
1758                         "void main (void)\n"
1759                         "{\n"
1760                         "       fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1761                         "}\n";
1762
1763         return specializeShader(buf.str(), contextType);
1764 }
1765
1766 std::string InstancedExpansionShader::genGeometrySource (const glu::ContextType& contextType, int numInvocations)
1767 {
1768         std::ostringstream buf;
1769
1770         buf <<  "${GLSL_VERSION_DECL}\n"
1771                         "${GLSL_EXT_GEOMETRY_SHADER}"
1772                         "layout(points,invocations=" << numInvocations << ") in;\n"
1773                         "layout(triangle_strip, max_vertices = 3) out;\n"
1774                         "\n"
1775                         "void main (void)\n"
1776                         "{\n"
1777                         "       highp vec4 basePosition = gl_in[0].gl_Position;\n"
1778                         "       highp float phase = float(gl_InvocationID) / float(" << numInvocations << ") * 6.3;\n"
1779                         "       highp vec4 centerPosition = basePosition + 0.1 * vec4(cos(phase), sin(phase), 0.0, 0.0);\n"
1780                         "\n"
1781                         "       gl_Position = centerPosition + vec4( 0.00, -0.1, 0.0, 0.0);\n"
1782                         "       EmitVertex();\n"
1783                         "       gl_Position = centerPosition + vec4(-0.05,  0.0, 0.0, 0.0);\n"
1784                         "       EmitVertex();\n"
1785                         "       gl_Position = centerPosition + vec4( 0.05,  0.0, 0.0, 0.0);\n"
1786                         "       EmitVertex();\n"
1787                         "}\n";
1788
1789         return specializeShader(buf.str(), contextType);
1790 }
1791
1792 class GeometryShaderRenderTest : public TestCase
1793 {
1794 public:
1795         enum Flag
1796         {
1797                 FLAG_DRAW_INSTANCED             = 1,
1798                 FLAG_USE_INDICES                = 2,
1799                 FLAG_USE_RESTART_INDEX  = 4,
1800         };
1801
1802                                                                         GeometryShaderRenderTest        (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags = 0);
1803         virtual                                                 ~GeometryShaderRenderTest       (void);
1804
1805         void                                                    init                                            (void);
1806         void                                                    deinit                                          (void);
1807
1808         IterateResult                                   iterate                                         (void);
1809         bool                                                    compare                                         (void);
1810
1811         virtual sglr::ShaderProgram&    getProgram                                      (void) = 0;
1812
1813 protected:
1814         virtual void                                    genVertexAttribData                     (void);
1815         void                                                    renderWithContext                       (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface);
1816         virtual void                                    preRender                                       (sglr::Context& ctx, GLuint programID);
1817         virtual void                                    postRender                                      (sglr::Context& ctx, GLuint programID);
1818
1819         int                                                             m_numDrawVertices;
1820         int                                                             m_numDrawInstances;
1821         int                                                             m_vertexAttrDivisor;
1822
1823         const GLenum                                    m_inputPrimitives;
1824         const GLenum                                    m_outputPrimitives;
1825         const char* const                               m_dataAttributeName;
1826         const int                                               m_flags;
1827
1828         tcu::IVec2                                              m_viewportSize;
1829         int                                                             m_interationCount;
1830
1831         tcu::Surface*                                   m_glResult;
1832         tcu::Surface*                                   m_refResult;
1833
1834         sglr::ReferenceContextBuffers*  m_refBuffers;
1835         sglr::ReferenceContext*                 m_refContext;
1836         sglr::Context*                                  m_glContext;
1837
1838         std::vector<tcu::Vec4>                  m_vertexPosData;
1839         std::vector<tcu::Vec4>                  m_vertexAttrData;
1840         std::vector<deUint16>                   m_indices;
1841 };
1842
1843 GeometryShaderRenderTest::GeometryShaderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags)
1844         : TestCase                              (context, name, desc)
1845         , m_numDrawVertices             (0)
1846         , m_numDrawInstances    (0)
1847         , m_vertexAttrDivisor   (0)
1848         , m_inputPrimitives             (inputPrimitives)
1849         , m_outputPrimitives    (outputPrimitives)
1850         , m_dataAttributeName   (dataAttributeName)
1851         , m_flags                               (flags)
1852         , m_viewportSize                (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE)
1853         , m_interationCount             (0)
1854         , m_glResult                    (DE_NULL)
1855         , m_refResult                   (DE_NULL)
1856         , m_refBuffers                  (DE_NULL)
1857         , m_refContext                  (DE_NULL)
1858         , m_glContext                   (DE_NULL)
1859 {
1860         // Disallow instanced drawElements
1861         DE_ASSERT(((m_flags & FLAG_DRAW_INSTANCED) == 0) || ((m_flags & FLAG_USE_INDICES) == 0));
1862         // Disallow restart without indices
1863         DE_ASSERT(!(((m_flags & FLAG_USE_RESTART_INDEX) != 0) && ((m_flags & FLAG_USE_INDICES) == 0)));
1864 }
1865
1866 GeometryShaderRenderTest::~GeometryShaderRenderTest (void)
1867 {
1868         deinit();
1869 }
1870
1871 void GeometryShaderRenderTest::init (void)
1872 {
1873         // requirements
1874         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
1875                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
1876
1877         // gen resources
1878         {
1879                 sglr::ReferenceContextLimits limits;
1880
1881                 m_glResult              = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
1882                 m_refResult             = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
1883
1884                 m_refBuffers    = new sglr::ReferenceContextBuffers(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, m_viewportSize.x(), m_viewportSize.y());
1885                 m_refContext    = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
1886                 m_glContext             = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, m_viewportSize.x(), m_viewportSize.y()));
1887         }
1888 }
1889
1890 void GeometryShaderRenderTest::deinit (void)
1891 {
1892         delete m_glResult;
1893         delete m_refResult;
1894
1895         m_glResult = DE_NULL;
1896         m_refResult = DE_NULL;
1897
1898         delete m_refContext;
1899         delete m_glContext;
1900         delete m_refBuffers;
1901
1902         m_refBuffers = DE_NULL;
1903         m_refContext = DE_NULL;
1904         m_glContext = DE_NULL;
1905 }
1906
1907 tcu::TestCase::IterateResult GeometryShaderRenderTest::iterate (void)
1908 {
1909         // init() must be called
1910         DE_ASSERT(m_glContext);
1911         DE_ASSERT(m_refContext);
1912
1913         const int iteration = m_interationCount++;
1914
1915         if (iteration == 0)
1916         {
1917                 // Check requirements
1918                 const int width  = m_context.getRenderTarget().getWidth();
1919                 const int height = m_context.getRenderTarget().getHeight();
1920
1921                 if (width < m_viewportSize.x() || height < m_viewportSize.y())
1922                         throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_viewportSize.x()) + "x" + de::toString(m_viewportSize.y()));
1923
1924                 // Gen data
1925                 genVertexAttribData();
1926
1927                 return CONTINUE;
1928         }
1929         else if (iteration == 1)
1930         {
1931                 // Render
1932                 sglr::ShaderProgram& program = getProgram();
1933
1934                 renderWithContext(*m_glContext, program, *m_glResult);
1935                 renderWithContext(*m_refContext, program, *m_refResult);
1936
1937                 return CONTINUE;
1938         }
1939         else
1940         {
1941                 if (compare())
1942                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1943                 else
1944                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1945
1946                 return STOP;
1947         }
1948 }
1949
1950 bool GeometryShaderRenderTest::compare (void)
1951 {
1952         using tcu::TestLog;
1953
1954         if (m_context.getRenderTarget().getNumSamples() > 1)
1955         {
1956                 return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", m_refResult->getAccess(), m_glResult->getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
1957         }
1958         else
1959         {
1960                 tcu::Surface    errorMask                               (m_viewportSize.x(), m_viewportSize.y());
1961                 const tcu::RGBA green                                   (0, 255, 0, 255);
1962                 const tcu::RGBA red                                             (255, 0, 0, 255);
1963                 const int               colorComponentThreshold = 20;
1964                 bool                    testResult                              = true;
1965
1966                 for (int x = 0; x < m_viewportSize.x(); ++x)
1967                 for (int y = 0; y < m_viewportSize.y(); ++y)
1968                 {
1969                         if (x == 0 || y == 0 || x + 1 == m_viewportSize.x() || y + 1 == m_viewportSize.y())
1970                         {
1971                                 // Mark edge pixels as correct since their neighbourhood is undefined
1972                                 errorMask.setPixel(x, y, green);
1973                         }
1974                         else
1975                         {
1976                                 const tcu::RGBA refcolor        = m_refResult->getPixel(x, y);
1977                                 bool                    found           = false;
1978
1979                                 // Got to find similar pixel near this pixel (3x3 kernel)
1980                                 for (int dx = -1; dx <= 1; ++dx)
1981                                 for (int dy = -1; dy <= 1; ++dy)
1982                                 {
1983                                         const tcu::RGBA         testColor       = m_glResult->getPixel(x + dx, y + dy);
1984                                         const tcu::IVec4        colDiff         = tcu::abs(testColor.toIVec() - refcolor.toIVec());
1985
1986                                         const int                       maxColDiff      = de::max(de::max(colDiff.x(), colDiff.y()), colDiff.z()); // check RGB channels
1987
1988                                         if (maxColDiff <= colorComponentThreshold)
1989                                                 found = true;
1990                                 }
1991
1992                                 if (!found)
1993                                         testResult = false;
1994
1995                                 errorMask.setPixel(x, y, (found) ? (green) : (red));
1996                         }
1997                 }
1998
1999                 if (testResult)
2000                 {
2001                         m_testCtx.getLog()      << TestLog::ImageSet("Compare result", "Result of rendering")
2002                                                                 << TestLog::Image("Result", "Result", *m_glResult)
2003                                                                 << TestLog::EndImageSet;
2004                         m_testCtx.getLog() << TestLog::Message << "Image compare ok." << TestLog::EndMessage;
2005                 }
2006                 else
2007                 {
2008                         m_testCtx.getLog()      << TestLog::ImageSet("Compare result", "Result of rendering")
2009                                                                 << TestLog::Image("Result",             "Result",               *m_glResult)
2010                                                                 << TestLog::Image("Reference",  "Reference",    *m_refResult)
2011                                                                 << TestLog::Image("ErrorMask",  "Error mask",   errorMask)
2012                                                                 << TestLog::EndImageSet;
2013                         m_testCtx.getLog() << TestLog::Message << "Image compare failed." << TestLog::EndMessage;
2014                 }
2015
2016                 return testResult;
2017         }
2018 }
2019
2020 void GeometryShaderRenderTest::genVertexAttribData (void)
2021 {
2022         // Create 1 X 2 grid in triangle strip adjacent - order
2023         const float scale = 0.3f;
2024         const tcu::Vec4 offset(-0.5f, -0.2f, 0.0f, 1.0f);
2025
2026         m_vertexPosData.resize(12);
2027         m_vertexPosData[ 0] = tcu::Vec4( 0,  0, 0.0f, 0.0f) * scale + offset;
2028         m_vertexPosData[ 1] = tcu::Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
2029         m_vertexPosData[ 2] = tcu::Vec4( 0, -1, 0.0f, 0.0f) * scale + offset;
2030         m_vertexPosData[ 3] = tcu::Vec4( 1,  1, 0.0f, 0.0f) * scale + offset;
2031         m_vertexPosData[ 4] = tcu::Vec4( 1,  0, 0.0f, 0.0f) * scale + offset;
2032         m_vertexPosData[ 5] = tcu::Vec4( 0, -2, 0.0f, 0.0f) * scale + offset;
2033         m_vertexPosData[ 6] = tcu::Vec4( 1, -1, 0.0f, 0.0f) * scale + offset;
2034         m_vertexPosData[ 7] = tcu::Vec4( 2,  1, 0.0f, 0.0f) * scale + offset;
2035         m_vertexPosData[ 8] = tcu::Vec4( 2,  0, 0.0f, 0.0f) * scale + offset;
2036         m_vertexPosData[ 9] = tcu::Vec4( 1, -2, 0.0f, 0.0f) * scale + offset;
2037         m_vertexPosData[10] = tcu::Vec4( 2, -1, 0.0f, 0.0f) * scale + offset;
2038         m_vertexPosData[11] = tcu::Vec4( 3,  0, 0.0f, 0.0f) * scale + offset;
2039
2040         // Red and white
2041         m_vertexAttrData.resize(12);
2042         for (int i = 0; i < 12; ++i)
2043                 m_vertexAttrData[i] = (i % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2044
2045         m_numDrawVertices = 12;
2046 }
2047
2048 void GeometryShaderRenderTest::renderWithContext (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface)
2049 {
2050 #define CHECK_GL_CTX_ERRORS() glu::checkError(ctx.getError(), DE_NULL, __FILE__, __LINE__)
2051
2052         const GLuint    programId               = ctx.createProgram(&program);
2053         const GLint             attrPosLoc              = ctx.getAttribLocation(programId, "a_position");
2054         const GLint             attrColLoc              = ctx.getAttribLocation(programId, m_dataAttributeName);
2055         GLuint                  vaoId                   = 0;
2056         GLuint                  vertexPosBuf    = 0;
2057         GLuint                  vertexAttrBuf   = 0;
2058         GLuint                  elementArrayBuf = 0;
2059
2060         ctx.genVertexArrays(1, &vaoId);
2061         ctx.bindVertexArray(vaoId);
2062
2063         if (attrPosLoc != -1)
2064         {
2065                 ctx.genBuffers(1, &vertexPosBuf);
2066                 ctx.bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2067                 ctx.bufferData(GL_ARRAY_BUFFER, m_vertexPosData.size() * sizeof(tcu::Vec4), &m_vertexPosData[0], GL_STATIC_DRAW);
2068                 ctx.vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2069                 ctx.enableVertexAttribArray(attrPosLoc);
2070         }
2071
2072         if (attrColLoc != -1)
2073         {
2074                 ctx.genBuffers(1, &vertexAttrBuf);
2075                 ctx.bindBuffer(GL_ARRAY_BUFFER, vertexAttrBuf);
2076                 ctx.bufferData(GL_ARRAY_BUFFER, m_vertexAttrData.size() * sizeof(tcu::Vec4), &m_vertexAttrData[0], GL_STATIC_DRAW);
2077                 ctx.vertexAttribPointer(attrColLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2078                 ctx.enableVertexAttribArray(attrColLoc);
2079
2080                 if (m_vertexAttrDivisor)
2081                         ctx.vertexAttribDivisor(attrColLoc, m_vertexAttrDivisor);
2082         }
2083
2084         if (m_flags & FLAG_USE_INDICES)
2085         {
2086                 ctx.genBuffers(1, &elementArrayBuf);
2087                 ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBuf);
2088                 ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(deUint16), &m_indices[0], GL_STATIC_DRAW);
2089         }
2090
2091         ctx.clearColor(0, 0, 0, 1);
2092         ctx.clear(GL_COLOR_BUFFER_BIT);
2093
2094         ctx.viewport(0, 0, m_viewportSize.x(), m_viewportSize.y());
2095         CHECK_GL_CTX_ERRORS();
2096
2097         ctx.useProgram(programId);
2098         CHECK_GL_CTX_ERRORS();
2099
2100         preRender(ctx, programId);
2101         CHECK_GL_CTX_ERRORS();
2102
2103         if (m_flags & FLAG_USE_RESTART_INDEX)
2104         {
2105                 ctx.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2106                 CHECK_GL_CTX_ERRORS();
2107         }
2108
2109         if (m_flags & FLAG_USE_INDICES)
2110                 ctx.drawElements(m_inputPrimitives, m_numDrawVertices, GL_UNSIGNED_SHORT, DE_NULL);
2111         else if (m_flags & FLAG_DRAW_INSTANCED)
2112                 ctx.drawArraysInstanced(m_inputPrimitives, 0, m_numDrawVertices, m_numDrawInstances);
2113         else
2114                 ctx.drawArrays(m_inputPrimitives, 0, m_numDrawVertices);
2115
2116         CHECK_GL_CTX_ERRORS();
2117
2118         if (m_flags & FLAG_USE_RESTART_INDEX)
2119         {
2120                 ctx.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2121                 CHECK_GL_CTX_ERRORS();
2122         }
2123
2124         postRender(ctx, programId);
2125         CHECK_GL_CTX_ERRORS();
2126
2127         ctx.useProgram(0);
2128
2129         if (attrPosLoc != -1)
2130                 ctx.disableVertexAttribArray(attrPosLoc);
2131         if (attrColLoc != -1)
2132                 ctx.disableVertexAttribArray(attrColLoc);
2133
2134         if (vertexPosBuf)
2135                 ctx.deleteBuffers(1, &vertexPosBuf);
2136         if (vertexAttrBuf)
2137                 ctx.deleteBuffers(1, &vertexAttrBuf);
2138         if (elementArrayBuf)
2139                 ctx.deleteBuffers(1, &elementArrayBuf);
2140
2141         ctx.deleteVertexArrays(1, &vaoId);
2142
2143         CHECK_GL_CTX_ERRORS();
2144
2145         ctx.finish();
2146         ctx.readPixels(dstSurface, 0, 0, m_viewportSize.x(), m_viewportSize.y());
2147
2148 #undef CHECK_GL_CTX_ERRORS
2149 }
2150
2151 void GeometryShaderRenderTest::preRender (sglr::Context& ctx, GLuint programID)
2152 {
2153         DE_UNREF(ctx);
2154         DE_UNREF(programID);
2155 }
2156
2157 void GeometryShaderRenderTest::postRender (sglr::Context& ctx, GLuint programID)
2158 {
2159         DE_UNREF(ctx);
2160         DE_UNREF(programID);
2161 }
2162
2163 class GeometryExpanderRenderTest : public GeometryShaderRenderTest
2164 {
2165 public:
2166                                                                         GeometryExpanderRenderTest      (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives);
2167         virtual                                                 ~GeometryExpanderRenderTest     (void);
2168
2169         sglr::ShaderProgram&                    getProgram                                      (void);
2170
2171 private:
2172         void                                                    init                                            (void);
2173         void                                                    deinit                                          (void);
2174         VertexExpanderShader*                   m_program;
2175 };
2176
2177 GeometryExpanderRenderTest::GeometryExpanderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives)
2178         : GeometryShaderRenderTest      (context, name, desc, inputPrimitives, outputPrimitives, "a_color")
2179         , m_program                                     (DE_NULL)
2180 {
2181 }
2182
2183 GeometryExpanderRenderTest::~GeometryExpanderRenderTest (void)
2184 {
2185 }
2186
2187 void GeometryExpanderRenderTest::init (void)
2188 {
2189         m_program = new VertexExpanderShader(m_context.getRenderContext().getType(), sglr::rr_util::mapGLGeometryShaderInputType(m_inputPrimitives), sglr::rr_util::mapGLGeometryShaderOutputType(m_outputPrimitives));
2190
2191         GeometryShaderRenderTest::init();
2192 }
2193
2194 void GeometryExpanderRenderTest::deinit (void)
2195 {
2196         if (m_program)
2197         {
2198                 delete m_program;
2199                 m_program = DE_NULL;
2200         }
2201
2202         GeometryShaderRenderTest::deinit();
2203 }
2204
2205 sglr::ShaderProgram& GeometryExpanderRenderTest::getProgram (void)
2206 {
2207         return *m_program;
2208 }
2209
2210 class EmitTest : public GeometryShaderRenderTest
2211 {
2212 public:
2213                                                         EmitTest                                (Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType);
2214
2215         sglr::ShaderProgram&    getProgram                              (void);
2216 private:
2217         void                                    init                                    (void);
2218         void                                    deinit                                  (void);
2219         void                                    genVertexAttribData             (void);
2220
2221         VertexEmitterShader*    m_program;
2222         int                                             m_emitCountA;
2223         int                                             m_endCountA;
2224         int                                             m_emitCountB;
2225         int                                             m_endCountB;
2226         GLenum                                  m_outputType;
2227 };
2228
2229 EmitTest::EmitTest (Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType)
2230         : GeometryShaderRenderTest      (context, name, desc, GL_POINTS, outputType, "a_color")
2231         , m_program                                     (DE_NULL)
2232         , m_emitCountA                          (emitCountA)
2233         , m_endCountA                           (endCountA)
2234         , m_emitCountB                          (emitCountB)
2235         , m_endCountB                           (endCountB)
2236         , m_outputType                          (outputType)
2237 {
2238 }
2239
2240 void EmitTest::init(void)
2241 {
2242         m_program = new VertexEmitterShader(m_context.getRenderContext().getType(), m_emitCountA, m_endCountA, m_emitCountB, m_endCountB, sglr::rr_util::mapGLGeometryShaderOutputType(m_outputType));
2243
2244         GeometryShaderRenderTest::init();
2245 }
2246
2247 void EmitTest::deinit (void)
2248 {
2249         if (m_program)
2250         {
2251                 delete m_program;
2252                 m_program = DE_NULL;
2253         }
2254
2255         GeometryShaderRenderTest::deinit();
2256 }
2257
2258 sglr::ShaderProgram& EmitTest::getProgram (void)
2259 {
2260         return *m_program;
2261 }
2262
2263 void EmitTest::genVertexAttribData (void)
2264 {
2265         m_vertexPosData.resize(1);
2266         m_vertexPosData[0] = tcu::Vec4(0, 0, 0, 1);
2267
2268         m_vertexAttrData.resize(1);
2269         m_vertexAttrData[0] = tcu::Vec4(1, 1, 1, 1);
2270
2271         m_numDrawVertices = 1;
2272 }
2273
2274 class VaryingTest : public GeometryShaderRenderTest
2275 {
2276 public:
2277                                                         VaryingTest                             (Context& context, const char* name, const char* desc, int vertexOut, int geometryOut);
2278
2279         sglr::ShaderProgram&    getProgram                              (void);
2280 private:
2281         void                                    init                                    (void);
2282         void                                    deinit                                  (void);
2283         void                                    genVertexAttribData             (void);
2284
2285         VertexVaryingShader*    m_program;
2286         int                                             m_vertexOut;
2287         int                                             m_geometryOut;
2288 };
2289
2290 VaryingTest::VaryingTest (Context& context, const char* name, const char* desc, int vertexOut, int geometryOut)
2291         : GeometryShaderRenderTest      (context, name, desc, GL_TRIANGLES, GL_TRIANGLE_STRIP, "a_color")
2292         , m_program                                     (DE_NULL)
2293         , m_vertexOut                           (vertexOut)
2294         , m_geometryOut                         (geometryOut)
2295 {
2296 }
2297
2298 void VaryingTest::init (void)
2299 {
2300         m_program = new VertexVaryingShader(m_context.getRenderContext().getType(), m_vertexOut, m_geometryOut);
2301
2302         GeometryShaderRenderTest::init();
2303 }
2304
2305 void VaryingTest::deinit (void)
2306 {
2307         if (m_program)
2308         {
2309                 delete m_program;
2310                 m_program = DE_NULL;
2311         }
2312
2313         GeometryShaderRenderTest::deinit();
2314 }
2315
2316 sglr::ShaderProgram& VaryingTest::getProgram (void)
2317 {
2318         return *m_program;
2319 }
2320
2321 void VaryingTest::genVertexAttribData (void)
2322 {
2323         m_vertexPosData.resize(3);
2324         m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
2325         m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
2326         m_vertexPosData[2] = tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f);
2327
2328         m_vertexAttrData.resize(3);
2329         m_vertexAttrData[0] = tcu::Vec4(0.7f, 0.4f, 0.6f, 1.0f);
2330         m_vertexAttrData[1] = tcu::Vec4(0.9f, 0.2f, 0.5f, 1.0f);
2331         m_vertexAttrData[2] = tcu::Vec4(0.1f, 0.8f, 0.3f, 1.0f);
2332
2333         m_numDrawVertices = 3;
2334 }
2335
2336 class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
2337 {
2338 public:
2339                                 TriangleStripAdjacencyVertexCountTest   (Context& context, const char* name, const char* desc, int numInputVertices);
2340
2341 private:
2342         void            genVertexAttribData                                             (void);
2343
2344         int                     m_numInputVertices;
2345 };
2346
2347 TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (Context& context, const char* name, const char* desc, int numInputVertices)
2348         : GeometryExpanderRenderTest    (context, name, desc, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLE_STRIP)
2349         , m_numInputVertices                    (numInputVertices)
2350 {
2351 }
2352
2353 void TriangleStripAdjacencyVertexCountTest::genVertexAttribData (void)
2354 {
2355         this->GeometryShaderRenderTest::genVertexAttribData();
2356         m_numDrawVertices = m_numInputVertices;
2357 }
2358
2359 class NegativeDrawCase : public TestCase
2360 {
2361 public:
2362                                                         NegativeDrawCase        (Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives);
2363                                                         ~NegativeDrawCase       (void);
2364
2365         void                                    init                            (void);
2366         void                                    deinit                          (void);
2367
2368         IterateResult                   iterate                         (void);
2369
2370 private:
2371         sglr::Context*                  m_ctx;
2372         VertexExpanderShader*   m_program;
2373         GLenum                                  m_inputType;
2374         GLenum                                  m_inputPrimitives;
2375 };
2376
2377 NegativeDrawCase::NegativeDrawCase (Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives)
2378         : TestCase                      (context, name, desc)
2379         , m_ctx                         (DE_NULL)
2380         , m_program                     (DE_NULL)
2381         , m_inputType           (inputType)
2382         , m_inputPrimitives     (inputPrimitives)
2383 {
2384 }
2385
2386 NegativeDrawCase::~NegativeDrawCase (void)
2387 {
2388         deinit();
2389 }
2390
2391 void NegativeDrawCase::init (void)
2392 {
2393         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2394                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2395
2396         m_ctx           = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, 1, 1));
2397         m_program       = new VertexExpanderShader(m_context.getRenderContext().getType() , sglr::rr_util::mapGLGeometryShaderInputType(m_inputType), rr::GEOMETRYSHADEROUTPUTTYPE_POINTS);
2398 }
2399
2400 void NegativeDrawCase::deinit (void)
2401 {
2402         delete m_ctx;
2403         delete m_program;
2404
2405         m_ctx = NULL;
2406         m_program = DE_NULL;
2407 }
2408
2409 NegativeDrawCase::IterateResult NegativeDrawCase::iterate (void)
2410 {
2411         const GLuint    programId               = m_ctx->createProgram(m_program);
2412         const GLint             attrPosLoc              = m_ctx->getAttribLocation(programId, "a_position");
2413         const tcu::Vec4 vertexPosData   (0, 0, 0, 1);
2414
2415         GLuint vaoId            = 0;
2416         GLuint vertexPosBuf = 0;
2417         GLenum errorCode        = 0;
2418
2419         m_ctx->genVertexArrays(1, &vaoId);
2420         m_ctx->bindVertexArray(vaoId);
2421
2422         m_ctx->genBuffers(1, &vertexPosBuf);
2423         m_ctx->bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2424         m_ctx->bufferData(GL_ARRAY_BUFFER, sizeof(tcu::Vec4), vertexPosData.m_data, GL_STATIC_DRAW);
2425         m_ctx->vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2426         m_ctx->enableVertexAttribArray(attrPosLoc);
2427
2428         m_ctx->clearColor(0, 0, 0, 1);
2429         m_ctx->clear(GL_COLOR_BUFFER_BIT);
2430
2431         m_ctx->viewport(0, 0, 1, 1);
2432
2433         m_ctx->useProgram(programId);
2434
2435         // no errors before
2436         glu::checkError(m_ctx->getError(), "", __FILE__, __LINE__);
2437
2438         m_ctx->drawArrays(m_inputPrimitives, 0, 1);
2439
2440         errorCode = m_ctx->getError();
2441         if (errorCode != GL_INVALID_OPERATION)
2442         {
2443                 m_testCtx.getLog() << tcu::TestLog::Message << "Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
2444                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2445         }
2446         else
2447         {
2448                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2449         }
2450
2451         m_ctx->useProgram(0);
2452
2453         m_ctx->disableVertexAttribArray(attrPosLoc);
2454         m_ctx->deleteBuffers(1, &vertexPosBuf);
2455
2456         m_ctx->deleteVertexArrays(1, &vaoId);
2457
2458         return STOP;
2459 }
2460
2461 class OutputCountCase : public GeometryShaderRenderTest
2462 {
2463 public:
2464                                                                         OutputCountCase                 (Context& context, const char* name, const char* desc, const OutputCountPatternSpec&);
2465 private:
2466         void                                                    init                                    (void);
2467         void                                                    deinit                                  (void);
2468
2469         sglr::ShaderProgram&                    getProgram                              (void);
2470         void                                                    genVertexAttribData             (void);
2471
2472         const int                                               m_primitiveCount;
2473         OutputCountShader*                              m_program;
2474         OutputCountPatternSpec                  m_spec;
2475 };
2476
2477 OutputCountCase::OutputCountCase (Context& context, const char* name, const char* desc, const OutputCountPatternSpec& spec)
2478         : GeometryShaderRenderTest      (context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
2479         , m_primitiveCount                      ((int)spec.pattern.size())
2480         , m_program                                     (DE_NULL)
2481         , m_spec                                        (spec)
2482 {
2483 }
2484
2485 void OutputCountCase::init (void)
2486 {
2487         // Check requirements and adapt to them
2488         {
2489                 const int       componentsPerVertex     = 4 + 4; // vec4 pos, vec4 color
2490                 const int       testVertices            = *std::max_element(m_spec.pattern.begin(), m_spec.pattern.end());
2491                 glw::GLint      maxVertices                     = 0;
2492                 glw::GLint      maxComponents           = 0;
2493
2494                 // check the extension before querying anything
2495                 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2496                         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2497
2498                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
2499                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
2500
2501                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices << tcu::TestLog::EndMessage;
2502                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents << tcu::TestLog::EndMessage;
2503                 m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex << tcu::TestLog::EndMessage;
2504
2505                 if (testVertices == -1)
2506                 {
2507                         // "max vertices"-case
2508                         DE_ASSERT((int)m_spec.pattern.size() == 1);
2509                         m_spec.pattern[0] = de::min(maxVertices, maxComponents / componentsPerVertex);
2510
2511                         // make sure size is dividable by 2, as OutputShader requires
2512                         m_spec.pattern[0] = m_spec.pattern[0] & ~0x00000001;
2513
2514                         if (m_spec.pattern[0] == 0)
2515                                 throw tcu::InternalError("Pattern size is invalid.");
2516                 }
2517                 else
2518                 {
2519                         // normal case
2520                         if (testVertices > maxVertices)
2521                                 throw tcu::NotSupportedError(de::toString(testVertices) + " output vertices required.");
2522                         if (testVertices * componentsPerVertex > maxComponents)
2523                                 throw tcu::NotSupportedError(de::toString(testVertices * componentsPerVertex) + " output components required.");
2524                 }
2525         }
2526
2527         // Log what the test tries to do
2528
2529         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)m_spec.pattern.size() << " row(s).\nOne geometry shader invocation generates one row.\nRow sizes:" << tcu::TestLog::EndMessage;
2530         for (int ndx = 0; ndx < (int)m_spec.pattern.size(); ++ndx)
2531                 m_testCtx.getLog() << tcu::TestLog::Message << "Row " << ndx << ": " << m_spec.pattern[ndx] << " vertices." << tcu::TestLog::EndMessage;
2532
2533         // Gen shader
2534         DE_ASSERT(!m_program);
2535         m_program = new OutputCountShader(m_context.getRenderContext().getType(), m_spec);
2536
2537         // Case init
2538         GeometryShaderRenderTest::init();
2539 }
2540
2541 void OutputCountCase::deinit (void)
2542 {
2543         if (m_program)
2544         {
2545                 delete m_program;
2546                 m_program = DE_NULL;
2547         }
2548
2549         GeometryShaderRenderTest::deinit();
2550 }
2551
2552 sglr::ShaderProgram& OutputCountCase::getProgram (void)
2553 {
2554         return *m_program;
2555 }
2556
2557 void OutputCountCase::genVertexAttribData (void)
2558 {
2559         m_vertexPosData.resize(m_primitiveCount);
2560         m_vertexAttrData.resize(m_primitiveCount);
2561
2562         for (int ndx = 0; ndx < m_primitiveCount; ++ndx)
2563         {
2564                 m_vertexPosData[ndx] = tcu::Vec4(-1.0f, ((float)ndx) / (float)m_primitiveCount * 2.0f - 1.0f, 0.0f, 1.0f);
2565                 m_vertexAttrData[ndx] = (ndx % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2566         }
2567
2568         m_numDrawVertices = m_primitiveCount;
2569 }
2570
2571 class BuiltinVariableRenderTest : public GeometryShaderRenderTest
2572 {
2573 public:
2574                                                                                                 BuiltinVariableRenderTest       (Context& context, const char* name, const char* desc, BuiltinVariableShader::VariableTest test, int flags = 0);
2575
2576 private:
2577         void                                                                            init                                            (void);
2578         void                                                                            deinit                                          (void);
2579
2580         sglr::ShaderProgram&                                            getProgram                                      (void);
2581         void                                                                            genVertexAttribData                     (void);
2582
2583         BuiltinVariableShader*                                          m_program;
2584         const BuiltinVariableShader::VariableTest       m_test;
2585 };
2586
2587 BuiltinVariableRenderTest::BuiltinVariableRenderTest (Context& context, const char* name, const char* desc, BuiltinVariableShader::VariableTest test, int flags)
2588         : GeometryShaderRenderTest      (context, name, desc, GL_POINTS, GL_POINTS, BuiltinVariableShader::getTestAttributeName(test), flags)
2589         , m_program                                     (DE_NULL)
2590         , m_test                                        (test)
2591 {
2592 }
2593
2594 void BuiltinVariableRenderTest::init (void)
2595 {
2596         // Requirements
2597         if (m_test == BuiltinVariableShader::TEST_POINT_SIZE)
2598         {
2599                 const float requiredPointSize = 5.0f;
2600
2601                 tcu::Vec2 range = tcu::Vec2(1.0f, 1.0f);
2602
2603                 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 4)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_point_size"))
2604                         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_point_size extension.");
2605
2606                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range.getPtr());
2607                 if (range.y() < requiredPointSize)
2608                         throw tcu::NotSupportedError("Test case requires point size " + de::toString(requiredPointSize));
2609         }
2610
2611         m_program = new BuiltinVariableShader(m_context.getRenderContext().getType(), m_test);
2612
2613         // Shader init
2614         GeometryShaderRenderTest::init();
2615 }
2616
2617 void BuiltinVariableRenderTest::deinit(void)
2618 {
2619         if (m_program)
2620         {
2621                 delete m_program;
2622                 m_program = DE_NULL;
2623         }
2624
2625         GeometryShaderRenderTest::deinit();
2626 }
2627
2628
2629 sglr::ShaderProgram& BuiltinVariableRenderTest::getProgram (void)
2630 {
2631         return *m_program;
2632 }
2633
2634 void BuiltinVariableRenderTest::genVertexAttribData (void)
2635 {
2636         m_vertexPosData.resize(4);
2637         m_vertexPosData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 1.0f);
2638         m_vertexPosData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 1.0f);
2639         m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
2640         m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
2641
2642         m_vertexAttrData.resize(4);
2643         m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
2644         m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
2645         m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
2646         m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
2647
2648         // Only used by primitive ID restart test
2649         m_indices.resize(4);
2650         m_indices[0] = 3;
2651         m_indices[1] = 2;
2652         m_indices[2] = 0xFFFF; // restart
2653         m_indices[3] = 1;
2654
2655         m_numDrawVertices = 4;
2656 }
2657
2658 class LayeredRenderCase : public TestCase
2659 {
2660 public:
2661         enum LayeredRenderTargetType
2662         {
2663                 TARGET_CUBE = 0,
2664                 TARGET_3D,
2665                 TARGET_1D_ARRAY,
2666                 TARGET_2D_ARRAY,
2667                 TARGET_2D_MS_ARRAY,
2668
2669                 TARGET_LAST
2670         };
2671         enum TestType
2672         {
2673                 TEST_DEFAULT_LAYER,                                             // !< draw to default layer
2674                 TEST_SINGLE_LAYER,                                              // !< draw to single layer
2675                 TEST_ALL_LAYERS,                                                // !< draw all layers
2676                 TEST_DIFFERENT_LAYERS,                                  // !< draw different content to different layers
2677                 TEST_INVOCATION_PER_LAYER,                              // !< draw to all layers, one invocation per layer
2678                 TEST_MULTIPLE_LAYERS_PER_INVOCATION,    // !< draw to all layers, multiple invocations write to multiple layers
2679                 TEST_LAYER_ID,                                                  // !< draw to all layers, verify gl_Layer fragment input
2680                 TEST_LAYER_PROVOKING_VERTEX,                    // !< draw primitive with vertices in different layers, check which layer it was drawn to
2681
2682                 TEST_LAST
2683         };
2684                                                                                 LayeredRenderCase                       (Context& context, const char* name, const char* desc, LayeredRenderTargetType target, TestType test);
2685                                                                                 ~LayeredRenderCase                      (void);
2686
2687         void                                                            init                                            (void);
2688         void                                                            deinit                                          (void);
2689         IterateResult                                           iterate                                         (void);
2690
2691 private:
2692         void                                                            initTexture                                     (void);
2693         void                                                            initFbo                                         (void);
2694         void                                                            initRenderShader                        (void);
2695         void                                                            initSamplerShader                       (void);
2696
2697         std::string                                                     genFragmentSource                       (const glu::ContextType& contextType) const;
2698         std::string                                                     genGeometrySource                       (const glu::ContextType& contextType) const;
2699         std::string                                                     genSamplerFragmentSource        (const glu::ContextType& contextType) const;
2700
2701         void                                                            renderToTexture                         (void);
2702         void                                                            sampleTextureLayer                      (tcu::Surface& dst, int layer);
2703         bool                                                            verifyLayerContent                      (const tcu::Surface& layer, int layerNdx);
2704         bool                                                            verifyImageSingleColoredRow (const tcu::Surface& layer, float rowWidthRatio, const tcu::Vec4& color, bool logging = true);
2705         bool                                                            verifyEmptyImage                        (const tcu::Surface& layer, bool logging = true);
2706         bool                                                            verifyProvokingVertexLayers     (const tcu::Surface& layer0, const tcu::Surface& layer1);
2707
2708         static int                                                      getTargetLayers                         (LayeredRenderTargetType target);
2709         static glw::GLenum                                      getTargetTextureTarget          (LayeredRenderTargetType target);
2710         static tcu::IVec3                                       getTargetDimensions                     (LayeredRenderTargetType target);
2711         static tcu::IVec2                                       getResolveDimensions            (LayeredRenderTargetType target);
2712
2713         const LayeredRenderTargetType           m_target;
2714         const TestType                                          m_test;
2715         const int                                                       m_numLayers;
2716         const int                                                       m_targetLayer;
2717         const tcu::IVec2                                        m_resolveDimensions;
2718
2719         int                                                                     m_iteration;
2720         bool                                                            m_allLayersOk;
2721
2722         glw::GLuint                                                     m_texture;
2723         glw::GLuint                                                     m_fbo;
2724         glu::ShaderProgram*                                     m_renderShader;
2725         glu::ShaderProgram*                                     m_samplerShader;
2726
2727         glw::GLint                                                      m_samplerSamplerLoc;
2728         glw::GLint                                                      m_samplerLayerLoc;
2729
2730         glw::GLenum                                                     m_provokingVertex;
2731 };
2732
2733 LayeredRenderCase::LayeredRenderCase (Context& context, const char* name, const char* desc, LayeredRenderTargetType target, TestType test)
2734         : TestCase                              (context, name, desc)
2735         , m_target                              (target)
2736         , m_test                                (test)
2737         , m_numLayers                   (getTargetLayers(target))
2738         , m_targetLayer                 (m_numLayers / 2)
2739         , m_resolveDimensions   (getResolveDimensions(target))
2740         , m_iteration                   (0)
2741         , m_allLayersOk                 (true)
2742         , m_texture                             (0)
2743         , m_fbo                                 (0)
2744         , m_renderShader                (DE_NULL)
2745         , m_samplerShader               (DE_NULL)
2746         , m_samplerSamplerLoc   (-1)
2747         , m_samplerLayerLoc             (-1)
2748         , m_provokingVertex             (0)
2749 {
2750 }
2751
2752 LayeredRenderCase::~LayeredRenderCase (void)
2753 {
2754         deinit();
2755 }
2756
2757 void LayeredRenderCase::init (void)
2758 {
2759         // Requirements
2760
2761         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2762                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2763
2764         if (m_target == TARGET_2D_MS_ARRAY && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
2765                 TCU_THROW(NotSupportedError, "Test requires OES_texture_storage_multisample_2d_array extension or higher context version.");
2766
2767         if (m_context.getRenderTarget().getWidth() < m_resolveDimensions.x() || m_context.getRenderTarget().getHeight() < m_resolveDimensions.y())
2768                 throw tcu::NotSupportedError("Render target size must be at least " + de::toString(m_resolveDimensions.x()) + "x" + de::toString(m_resolveDimensions.y()));
2769
2770         // log what the test tries to do
2771
2772         if (m_test == TEST_DEFAULT_LAYER)
2773                 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to the default layer." << tcu::TestLog::EndMessage;
2774         else if (m_test == TEST_SINGLE_LAYER)
2775                 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to a single layer." << tcu::TestLog::EndMessage;
2776         else if (m_test == TEST_ALL_LAYERS)
2777                 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to all layers." << tcu::TestLog::EndMessage;
2778         else if (m_test == TEST_DIFFERENT_LAYERS)
2779                 m_testCtx.getLog() << tcu::TestLog::Message << "Outputting different number of vertices to each layer." << tcu::TestLog::EndMessage;
2780         else if (m_test == TEST_INVOCATION_PER_LAYER)
2781                 m_testCtx.getLog() << tcu::TestLog::Message << "Using a different invocation to output to each layer." << tcu::TestLog::EndMessage;
2782         else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
2783                 m_testCtx.getLog() << tcu::TestLog::Message << "Outputting to each layer from multiple invocations." << tcu::TestLog::EndMessage;
2784         else if (m_test == TEST_LAYER_ID)
2785                 m_testCtx.getLog() << tcu::TestLog::Message << "Using gl_Layer in fragment shader." << tcu::TestLog::EndMessage;
2786         else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
2787                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying LAYER_PROVOKING_VERTEX." << tcu::TestLog::EndMessage;
2788         else
2789                 DE_ASSERT(false);
2790
2791         // init resources
2792
2793         initTexture();
2794         initFbo();
2795         initRenderShader();
2796         initSamplerShader();
2797 }
2798
2799 void LayeredRenderCase::deinit (void)
2800 {
2801         if (m_texture)
2802         {
2803                 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
2804                 m_texture = 0;
2805         }
2806
2807         if (m_fbo)
2808         {
2809                 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
2810                 m_fbo = 0;
2811         }
2812
2813         delete m_renderShader;
2814         delete m_samplerShader;
2815
2816         m_renderShader = DE_NULL;
2817         m_samplerShader = DE_NULL;
2818 }
2819
2820 LayeredRenderCase::IterateResult LayeredRenderCase::iterate (void)
2821 {
2822         ++m_iteration;
2823
2824         if (m_iteration == 1)
2825         {
2826                 if (m_test == TEST_LAYER_PROVOKING_VERTEX)
2827                 {
2828                         // which layer the implementation claims to render to
2829
2830                         gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
2831
2832                         m_context.getRenderContext().getFunctions().getIntegerv(GL_LAYER_PROVOKING_VERTEX, &state);
2833                         GLU_EXPECT_NO_ERROR(m_context.getRenderContext().getFunctions().getError(), "getInteger(GL_LAYER_PROVOKING_VERTEX)");
2834
2835                         if (!state.verifyValidity(m_testCtx))
2836                                 return STOP;
2837
2838                         m_testCtx.getLog() << tcu::TestLog::Message << "GL_LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state) << tcu::TestLog::EndMessage;
2839
2840                         if (state != GL_FIRST_VERTEX_CONVENTION &&
2841                                 state != GL_LAST_VERTEX_CONVENTION &&
2842                                 state != GL_UNDEFINED_VERTEX)
2843                         {
2844                                 m_testCtx.getLog() << tcu::TestLog::Message << "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got " << state << tcu::TestLog::EndMessage;
2845                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected provoking vertex value");
2846                                 return STOP;
2847                         }
2848
2849                         m_provokingVertex = (glw::GLenum)state;
2850                 }
2851
2852                 // render to texture
2853                 {
2854                         const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTexture", "Render to layered texture");
2855
2856                         // render to layered texture with the geometry shader
2857                         renderToTexture();
2858                 }
2859
2860                 return CONTINUE;
2861         }
2862         else if (m_test == TEST_LAYER_PROVOKING_VERTEX && m_provokingVertex == GL_UNDEFINED_VERTEX)
2863         {
2864                 // Verification requires information from another layers, layers not independent
2865                 {
2866                         const tcu::ScopedLogSection     section         (m_testCtx.getLog(), "VerifyLayers", "Verify layers 0 and 1");
2867                         tcu::Surface                            layer0          (m_resolveDimensions.x(), m_resolveDimensions.y());
2868                         tcu::Surface                            layer1          (m_resolveDimensions.x(), m_resolveDimensions.y());
2869
2870                         // sample layer to frame buffer
2871                         sampleTextureLayer(layer0, 0);
2872                         sampleTextureLayer(layer1, 1);
2873
2874                         m_allLayersOk &= verifyProvokingVertexLayers(layer0, layer1);
2875                 }
2876
2877                 // Other layers empty
2878                 for (int layerNdx = 2; layerNdx < m_numLayers; ++layerNdx)
2879                 {
2880                         const tcu::ScopedLogSection     section         (m_testCtx.getLog(), "VerifyLayer", "Verify layer " + de::toString(layerNdx));
2881                         tcu::Surface                            layer           (m_resolveDimensions.x(), m_resolveDimensions.y());
2882
2883                         // sample layer to frame buffer
2884                         sampleTextureLayer(layer, layerNdx);
2885
2886                         // verify
2887                         m_allLayersOk &= verifyEmptyImage(layer);
2888                 }
2889         }
2890         else
2891         {
2892                 // Layers independent
2893
2894                 const int                                       layerNdx        = m_iteration - 2;
2895                 const tcu::ScopedLogSection     section         (m_testCtx.getLog(), "VerifyLayer", "Verify layer " + de::toString(layerNdx));
2896                 tcu::Surface                            layer           (m_resolveDimensions.x(), m_resolveDimensions.y());
2897
2898                 // sample layer to frame buffer
2899                 sampleTextureLayer(layer, layerNdx);
2900
2901                 // verify
2902                 m_allLayersOk &= verifyLayerContent(layer, layerNdx);
2903
2904                 if (layerNdx < m_numLayers-1)
2905                         return CONTINUE;
2906         }
2907
2908         // last iteration
2909         if (m_allLayersOk)
2910                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2911         else
2912                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected invalid layer content");
2913
2914         return STOP;
2915 }
2916
2917 void LayeredRenderCase::initTexture (void)
2918 {
2919         DE_ASSERT(!m_texture);
2920
2921         const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
2922         const tcu::IVec3                        texSize                 = getTargetDimensions(m_target);
2923         const tcu::TextureFormat        texFormat               = glu::mapGLInternalFormat(GL_RGBA8);
2924         const glu::TransferFormat       transferFormat  = glu::getTransferFormat(texFormat);
2925
2926         gl.genTextures(1, &m_texture);
2927         GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
2928
2929         switch (m_target)
2930         {
2931                 case TARGET_CUBE:
2932                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating cubemap texture, size = " << texSize.x() << "x" << texSize.y() << tcu::TestLog::EndMessage;
2933                         gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
2934                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2935                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2936                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2937                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2938                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2939                         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2940                         break;
2941
2942                 case TARGET_3D:
2943                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 3d texture, size = " << texSize.x() << "x" << texSize.y() << "x" << texSize.z() << tcu::TestLog::EndMessage;
2944                         gl.bindTexture(GL_TEXTURE_3D, m_texture);
2945                         gl.texImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2946                         break;
2947
2948                 case TARGET_1D_ARRAY:
2949                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 1d texture array, size = " << texSize.x() << ", layers = " << texSize.y() << tcu::TestLog::EndMessage;
2950                         gl.bindTexture(GL_TEXTURE_1D_ARRAY, m_texture);
2951                         gl.texImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2952                         break;
2953
2954                 case TARGET_2D_ARRAY:
2955                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d texture array, size = " << texSize.x() << "x" << texSize.y() << ", layers = " << texSize.z() << tcu::TestLog::EndMessage;
2956                         gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
2957                         gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2958                         break;
2959
2960                 case TARGET_2D_MS_ARRAY:
2961                 {
2962                         const int numSamples = 2;
2963
2964                         int maxSamples = 0;
2965                         gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
2966
2967                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d multisample texture array, size = " << texSize.x() << "x" << texSize.y() << ", layers = " << texSize.z() << ", samples = " << numSamples << tcu::TestLog::EndMessage;
2968
2969                         if (numSamples > maxSamples)
2970                                 throw tcu::NotSupportedError("Test requires " + de::toString(numSamples) + " color texture samples." );
2971
2972                         gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture);
2973                         gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, numSamples, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), GL_TRUE);
2974                         break;
2975                 }
2976
2977                 default:
2978                         DE_ASSERT(DE_FALSE);
2979         }
2980         GLU_EXPECT_NO_ERROR(gl.getError(), "tex image");
2981
2982         // Multisample textures don't use filters
2983         if (getTargetTextureTarget(m_target) != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
2984         {
2985                 gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2986                 gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2987                 gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_S, GL_REPEAT);
2988                 gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_T, GL_REPEAT);
2989                 gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_R, GL_REPEAT);
2990                 GLU_EXPECT_NO_ERROR(gl.getError(), "tex filter");
2991         }
2992 }
2993
2994 void LayeredRenderCase::initFbo (void)
2995 {
2996         DE_ASSERT(!m_fbo);
2997
2998         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2999
3000         m_testCtx.getLog() << tcu::TestLog::Message << "Creating FBO" << tcu::TestLog::EndMessage;
3001
3002         gl.genFramebuffers(1, &m_fbo);
3003         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3004         gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
3005         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
3006
3007         GLU_EXPECT_NO_ERROR(gl.getError(), "setup fbo");
3008 }
3009
3010 void LayeredRenderCase::initRenderShader (void)
3011 {
3012         const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTextureShader", "Create layered rendering shader program");
3013
3014         static const char* const positionVertex =       "${GLSL_VERSION_DECL}\n"
3015                                                                                                 "void main (void)\n"
3016                                                                                                 "{\n"
3017                                                                                                 "       gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
3018                                                                                                 "}\n";
3019
3020         m_renderShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3021                 << glu::VertexSource(specializeShader(positionVertex, m_context.getRenderContext().getType()))
3022                 << glu::FragmentSource(genFragmentSource(m_context.getRenderContext().getType()))
3023                 << glu::GeometrySource(genGeometrySource(m_context.getRenderContext().getType())));
3024         m_testCtx.getLog() << *m_renderShader;
3025
3026         if (!m_renderShader->isOk())
3027                 throw tcu::TestError("failed to build render shader");
3028 }
3029
3030 void LayeredRenderCase::initSamplerShader (void)
3031 {
3032         const tcu::ScopedLogSection section(m_testCtx.getLog(), "TextureSamplerShader", "Create shader sampler program");
3033
3034         static const char* const positionVertex =       "${GLSL_VERSION_DECL}\n"
3035                                                                                                 "in highp vec4 a_position;\n"
3036                                                                                                 "void main (void)\n"
3037                                                                                                 "{\n"
3038                                                                                                 "       gl_Position = a_position;\n"
3039                                                                                                 "}\n";
3040
3041         m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3042                                                                                                                                                         << glu::VertexSource(specializeShader(positionVertex, m_context.getRenderContext().getType()))
3043                                                                                                                                                         << glu::FragmentSource(genSamplerFragmentSource(m_context.getRenderContext().getType())));
3044
3045         m_testCtx.getLog() << *m_samplerShader;
3046
3047         if (!m_samplerShader->isOk())
3048                 throw tcu::TestError("failed to build sampler shader");
3049
3050         m_samplerSamplerLoc = m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
3051         if (m_samplerSamplerLoc == -1)
3052                 throw tcu::TestError("u_sampler uniform location = -1");
3053
3054         m_samplerLayerLoc = m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_layer");
3055         if (m_samplerLayerLoc == -1)
3056                 throw tcu::TestError("u_layer uniform location = -1");
3057 }
3058
3059 std::string LayeredRenderCase::genFragmentSource (const glu::ContextType& contextType) const
3060 {
3061         static const char* const fragmentLayerIdShader =        "${GLSL_VERSION_DECL}\n"
3062                                                                                                                 "${GLSL_EXT_GEOMETRY_SHADER}"
3063                                                                                                                 "layout(location = 0) out mediump vec4 fragColor;\n"
3064                                                                                                                 "void main (void)\n"
3065                                                                                                                 "{\n"
3066                                                                                                                 "       fragColor = vec4(((gl_Layer % 2) == 1) ? 1.0 : 0.5,\n"
3067                                                                                                                 "                        (((gl_Layer / 2) % 2) == 1) ? 1.0 : 0.5,\n"
3068                                                                                                                 "                        (gl_Layer == 0) ? 1.0 : 0.0,\n"
3069                                                                                                                 "                        1.0);\n"
3070                                                                                                                 "}\n";
3071
3072         if (m_test != TEST_LAYER_ID)
3073                 return specializeShader(s_commonShaderSourceFragment, contextType);
3074         else
3075                 return specializeShader(fragmentLayerIdShader, contextType);
3076 }
3077
3078 std::string LayeredRenderCase::genGeometrySource (const glu::ContextType& contextType) const
3079 {
3080         // TEST_DIFFERENT_LAYERS:                               draw 0 quad to first layer, 1 to second, etc.
3081         // TEST_ALL_LAYERS:                                             draw 1 quad to all layers
3082         // TEST_MULTIPLE_LAYERS_PER_INVOCATION: draw 1 triangle to "current layer" and 1 triangle to another layer
3083         // else:                                                                draw 1 quad to some single layer
3084         const int                       maxVertices =           (m_test == TEST_DIFFERENT_LAYERS) ? ((2 + m_numLayers-1) * m_numLayers) :
3085                                                                                         (m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID) ? (m_numLayers * 4) :
3086                                                                                         (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION) ? (6) :
3087                                                                                         (m_test == TEST_LAYER_PROVOKING_VERTEX) ? (6) :
3088                                                                                         (4);
3089         std::ostringstream      buf;
3090
3091         buf <<  "${GLSL_VERSION_DECL}\n"
3092                         "${GLSL_EXT_GEOMETRY_SHADER}";
3093
3094         if (m_test == TEST_INVOCATION_PER_LAYER || m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3095                 buf << "layout(points, invocations=" << m_numLayers << ") in;\n";
3096         else
3097                 buf << "layout(points) in;\n";
3098
3099         buf <<  "layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n"
3100                         "out highp vec4 v_frag_FragColor;\n"
3101                         "\n"
3102                         "void main (void)\n"
3103                         "{\n";
3104
3105         if (m_test == TEST_DEFAULT_LAYER)
3106         {
3107                 buf <<  "       const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3108                                 "       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3109                                 "       v_frag_FragColor = white;\n"
3110                                 "       EmitVertex();\n\n"
3111                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3112                                 "       v_frag_FragColor = white;\n"
3113                                 "       EmitVertex();\n\n"
3114                                 "       gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3115                                 "       v_frag_FragColor = white;\n"
3116                                 "       EmitVertex();\n\n"
3117                                 "       gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3118                                 "       v_frag_FragColor = white;\n"
3119                                 "       EmitVertex();\n";
3120         }
3121         else if (m_test == TEST_SINGLE_LAYER)
3122         {
3123                 buf <<  "       const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3124                                 "       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3125                                 "       gl_Layer = " << m_targetLayer << ";\n"
3126                                 "       v_frag_FragColor = white;\n"
3127                                 "       EmitVertex();\n\n"
3128                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3129                                 "       gl_Layer = " << m_targetLayer << ";\n"
3130                                 "       v_frag_FragColor = white;\n"
3131                                 "       EmitVertex();\n\n"
3132                                 "       gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3133                                 "       gl_Layer = " << m_targetLayer << ";\n"
3134                                 "       v_frag_FragColor = white;\n"
3135                                 "       EmitVertex();\n\n"
3136                                 "       gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3137                                 "       gl_Layer = " << m_targetLayer << ";\n"
3138                                 "       v_frag_FragColor = white;\n"
3139                                 "       EmitVertex();\n";
3140         }
3141         else if (m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID)
3142         {
3143                 DE_ASSERT(m_numLayers <= 6);
3144
3145                 buf <<  "       const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3146                                 "       const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3147                                 "       const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3148                                 "       const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3149                                 "       const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3150                                 "       const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3151                                 "       const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n\n"
3152                                 "       for (mediump int layerNdx = 0; layerNdx < " << m_numLayers << "; ++layerNdx)\n"
3153                                 "       {\n"
3154                                 "               gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3155                                 "               gl_Layer = layerNdx;\n"
3156                                 "               v_frag_FragColor = colors[layerNdx];\n"
3157                                 "               EmitVertex();\n\n"
3158                                 "               gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3159                                 "               gl_Layer = layerNdx;\n"
3160                                 "               v_frag_FragColor = colors[layerNdx];\n"
3161                                 "               EmitVertex();\n\n"
3162                                 "               gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3163                                 "               gl_Layer = layerNdx;\n"
3164                                 "               v_frag_FragColor = colors[layerNdx];\n"
3165                                 "               EmitVertex();\n\n"
3166                                 "               gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3167                                 "               gl_Layer = layerNdx;\n"
3168                                 "               v_frag_FragColor = colors[layerNdx];\n"
3169                                 "               EmitVertex();\n"
3170                                 "               EndPrimitive();\n"
3171                                 "       }\n";
3172         }
3173         else if (m_test == TEST_DIFFERENT_LAYERS)
3174         {
3175                 DE_ASSERT(m_numLayers <= 6);
3176
3177                 buf <<  "       const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3178                                 "       for (mediump int layerNdx = 0; layerNdx < " << m_numLayers << "; ++layerNdx)\n"
3179                                 "       {\n"
3180                                 "               for (mediump int colNdx = 0; colNdx <= layerNdx; ++colNdx)\n"
3181                                 "               {\n"
3182                                 "                       highp float posX = float(colNdx) / float(" << m_numLayers << ") * 2.0 - 1.0;\n\n"
3183                                 "                       gl_Position = vec4(posX,  1.0, 0.0, 1.0);\n"
3184                                 "                       gl_Layer = layerNdx;\n"
3185                                 "                       v_frag_FragColor = white;\n"
3186                                 "                       EmitVertex();\n\n"
3187                                 "                       gl_Position = vec4(posX, -1.0, 0.0, 1.0);\n"
3188                                 "                       gl_Layer = layerNdx;\n"
3189                                 "                       v_frag_FragColor = white;\n"
3190                                 "                       EmitVertex();\n"
3191                                 "               }\n"
3192                                 "               EndPrimitive();\n"
3193                                 "       }\n";
3194         }
3195         else if (m_test == TEST_INVOCATION_PER_LAYER)
3196         {
3197                 buf <<  "       const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3198                                 "       const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3199                                 "       const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3200                                 "       const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3201                                 "       const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3202                                 "       const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3203                                 "       const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n"
3204                                 "\n"
3205                                 "       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3206                                 "       gl_Layer = gl_InvocationID;\n"
3207                                 "       v_frag_FragColor = colors[gl_InvocationID];\n"
3208                                 "       EmitVertex();\n\n"
3209                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3210                                 "       gl_Layer = gl_InvocationID;\n"
3211                                 "       v_frag_FragColor = colors[gl_InvocationID];\n"
3212                                 "       EmitVertex();\n\n"
3213                                 "       gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3214                                 "       gl_Layer = gl_InvocationID;\n"
3215                                 "       v_frag_FragColor = colors[gl_InvocationID];\n"
3216                                 "       EmitVertex();\n\n"
3217                                 "       gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3218                                 "       gl_Layer = gl_InvocationID;\n"
3219                                 "       v_frag_FragColor = colors[gl_InvocationID];\n"
3220                                 "       EmitVertex();\n"
3221                                 "       EndPrimitive();\n";
3222         }
3223         else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3224         {
3225                 buf <<  "       const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n"
3226                                 "\n"
3227                                 "       mediump int layerA = gl_InvocationID;\n"
3228                                 "       mediump int layerB = (gl_InvocationID + 1) % " << m_numLayers << ";\n"
3229                                 "       highp float aEnd = float(layerA) / float(" << m_numLayers << ") * 2.0 - 1.0;\n"
3230                                 "       highp float bEnd = float(layerB) / float(" << m_numLayers << ") * 2.0 - 1.0;\n"
3231                                 "\n"
3232                                 "       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3233                                 "       gl_Layer = layerA;\n"
3234                                 "       v_frag_FragColor = white;\n"
3235                                 "       EmitVertex();\n\n"
3236                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3237                                 "       gl_Layer = layerA;\n"
3238                                 "       v_frag_FragColor = white;\n"
3239                                 "       EmitVertex();\n\n"
3240                                 "       gl_Position = vec4(aEnd, -1.0, 0.0, 1.0);\n"
3241                                 "       gl_Layer = layerA;\n"
3242                                 "       v_frag_FragColor = white;\n"
3243                                 "       EmitVertex();\n\n"
3244                                 "       EndPrimitive();\n"
3245                                 "\n"
3246                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3247                                 "       gl_Layer = layerB;\n"
3248                                 "       v_frag_FragColor = white;\n"
3249                                 "       EmitVertex();\n\n"
3250                                 "       gl_Position = vec4(bEnd,  1.0, 0.0, 1.0);\n"
3251                                 "       gl_Layer = layerB;\n"
3252                                 "       v_frag_FragColor = white;\n"
3253                                 "       EmitVertex();\n\n"
3254                                 "       gl_Position = vec4(bEnd, -1.0, 0.0, 1.0);\n"
3255                                 "       gl_Layer = layerB;\n"
3256                                 "       v_frag_FragColor = white;\n"
3257                                 "       EmitVertex();\n\n"
3258                                 "       EndPrimitive();\n";
3259         }
3260         else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
3261         {
3262                 buf <<  "       const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3263                                 "       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3264                                 "       gl_Layer = 0;\n"
3265                                 "       v_frag_FragColor = white;\n"
3266                                 "       EmitVertex();\n\n"
3267                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3268                                 "       gl_Layer = 1;\n"
3269                                 "       v_frag_FragColor = white;\n"
3270                                 "       EmitVertex();\n\n"
3271                                 "       gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3272                                 "       gl_Layer = 1;\n"
3273                                 "       v_frag_FragColor = white;\n"
3274                                 "       EmitVertex();\n\n"
3275                                 "       EndPrimitive();\n\n"
3276                                 "       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3277                                 "       gl_Layer = 0;\n"
3278                                 "       v_frag_FragColor = white;\n"
3279                                 "       EmitVertex();\n\n"
3280                                 "       gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3281                                 "       gl_Layer = 1;\n"
3282                                 "       v_frag_FragColor = white;\n"
3283                                 "       EmitVertex();\n\n"
3284                                 "       gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3285                                 "       gl_Layer = 1;\n"
3286                                 "       v_frag_FragColor = white;\n"
3287                                 "       EmitVertex();\n";
3288         }
3289         else
3290                 DE_ASSERT(DE_FALSE);
3291
3292         buf <<  "}\n";
3293
3294         return specializeShader(buf.str(), contextType);
3295 }
3296
3297 std::string LayeredRenderCase::genSamplerFragmentSource (const glu::ContextType& contextType) const
3298 {
3299         std::ostringstream buf;
3300
3301         buf << "${GLSL_VERSION_DECL}\n";
3302         if (m_target == TARGET_2D_MS_ARRAY)
3303                 buf << "${GLSL_OES_TEXTURE_STORAGE_MULTISAMPLE}";
3304         buf << "layout(location = 0) out mediump vec4 fragColor;\n";
3305
3306         switch (m_target)
3307         {
3308                 case TARGET_CUBE:                       buf << "uniform highp samplerCube u_sampler;\n";                break;
3309                 case TARGET_3D:                         buf << "uniform highp sampler3D u_sampler;\n";                  break;
3310                 case TARGET_2D_ARRAY:           buf << "uniform highp sampler2DArray u_sampler;\n";             break;
3311                 case TARGET_1D_ARRAY:           buf << "uniform highp sampler1DArray u_sampler;\n";             break;
3312                 case TARGET_2D_MS_ARRAY:        buf << "uniform highp sampler2DMSArray u_sampler;\n";   break;
3313                 default:
3314                         DE_ASSERT(DE_FALSE);
3315         }
3316
3317         buf <<  "uniform highp int u_layer;\n"
3318                         "void main (void)\n"
3319                         "{\n";
3320
3321         switch (m_target)
3322         {
3323                 case TARGET_CUBE:
3324                         buf <<  "       highp vec2 facepos = 2.0 * gl_FragCoord.xy / vec2(ivec2(" << m_resolveDimensions.x() << ", " << m_resolveDimensions.y() << ")) - vec2(1.0, 1.0);\n"
3325                                         "       if (u_layer == 0)\n"
3326                                         "               fragColor = textureLod(u_sampler, vec3(1.0, -facepos.y, -facepos.x), 0.0);\n"
3327                                         "       else if (u_layer == 1)\n"
3328                                         "               fragColor = textureLod(u_sampler, vec3(-1.0, -facepos.y, facepos.x), 0.0);\n"
3329                                         "       else if (u_layer == 2)\n"
3330                                         "               fragColor = textureLod(u_sampler, vec3(facepos.x, 1.0, facepos.y), 0.0);\n"
3331                                         "       else if (u_layer == 3)\n"
3332                                         "               fragColor = textureLod(u_sampler, vec3(facepos.x, -1.0, -facepos.y), 0.0);\n"
3333                                         "       else if (u_layer == 4)\n"
3334                                         "               fragColor = textureLod(u_sampler, vec3(facepos.x, -facepos.y, 1.0), 0.0);\n"
3335                                         "       else if (u_layer == 5)\n"
3336                                         "               fragColor = textureLod(u_sampler, vec3(-facepos.x, -facepos.y, -1.0), 0.0);\n"
3337                                         "       else\n"
3338                                         "               fragColor = vec4(1.0, 0.0, 1.0, 1.0);\n";
3339                         break;
3340
3341                 case TARGET_3D:
3342                 case TARGET_2D_ARRAY:
3343                 case TARGET_2D_MS_ARRAY:
3344                         buf <<  "       highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3345                                         "       fragColor = texelFetch(u_sampler, ivec3(screenpos, u_layer), 0);\n";
3346                         break;
3347
3348                 case TARGET_1D_ARRAY:
3349                         buf <<  "       highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3350                                         "       fragColor = texelFetch(u_sampler, ivec2(screenpos.x, u_layer), 0);\n";
3351                         break;
3352
3353                 default:
3354                         DE_ASSERT(DE_FALSE);
3355         }
3356         buf <<  "}\n";
3357         return specializeShader(buf.str(), contextType);
3358 }
3359
3360 void LayeredRenderCase::renderToTexture (void)
3361 {
3362         const tcu::IVec3                texSize         = getTargetDimensions(m_target);
3363         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
3364         glu::VertexArray                vao                     (m_context.getRenderContext());
3365
3366         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to texture" << tcu::TestLog::EndMessage;
3367
3368         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3369         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3370         gl.clear(GL_COLOR_BUFFER_BIT);
3371         gl.viewport(0, 0, texSize.x(), texSize.y());
3372         gl.clear(GL_COLOR_BUFFER_BIT);
3373
3374         gl.bindVertexArray(*vao);
3375         gl.useProgram(m_renderShader->getProgram());
3376         gl.drawArrays(GL_POINTS, 0, 1);
3377         gl.useProgram(0);
3378         gl.bindVertexArray(0);
3379         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
3380
3381         GLU_EXPECT_NO_ERROR(gl.getError(), "render");
3382 }
3383
3384 void LayeredRenderCase::sampleTextureLayer (tcu::Surface& dst, int layer)
3385 {
3386         DE_ASSERT(dst.getWidth() == m_resolveDimensions.x());
3387         DE_ASSERT(dst.getHeight() == m_resolveDimensions.y());
3388
3389         static const tcu::Vec4 fullscreenQuad[4] =
3390         {
3391                 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
3392                 tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
3393                 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
3394                 tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
3395         };
3396
3397         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
3398         const int                               positionLoc     = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
3399         glu::VertexArray                vao                     (m_context.getRenderContext());
3400         glu::Buffer                             buf                     (m_context.getRenderContext());
3401
3402         m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture layer " << layer << tcu::TestLog::EndMessage;
3403
3404         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3405         gl.clear(GL_COLOR_BUFFER_BIT);
3406         gl.viewport(0, 0, m_resolveDimensions.x(), m_resolveDimensions.y());
3407         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
3408
3409         gl.bindBuffer(GL_ARRAY_BUFFER, *buf);
3410         gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
3411         GLU_EXPECT_NO_ERROR(gl.getError(), "buf");
3412
3413         gl.bindVertexArray(*vao);
3414         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
3415         gl.enableVertexAttribArray(positionLoc);
3416         GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
3417
3418         gl.activeTexture(GL_TEXTURE0);
3419         gl.bindTexture(getTargetTextureTarget(m_target), m_texture);
3420         GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
3421
3422         gl.useProgram(m_samplerShader->getProgram());
3423         gl.uniform1i(m_samplerLayerLoc, layer);
3424         gl.uniform1i(m_samplerSamplerLoc, 0);
3425         GLU_EXPECT_NO_ERROR(gl.getError(), "setup program");
3426
3427         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
3428         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
3429
3430         gl.useProgram(0);
3431         gl.bindVertexArray(0);
3432         GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
3433
3434         glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
3435 }
3436
3437 bool LayeredRenderCase::verifyLayerContent (const tcu::Surface& layer, int layerNdx)
3438 {
3439         const tcu::Vec4 white   = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
3440         const tcu::Vec4 red     = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
3441         const tcu::Vec4 green   = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
3442         const tcu::Vec4 blue    = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
3443         const tcu::Vec4 yellow  = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
3444         const tcu::Vec4 magenta = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
3445         const tcu::Vec4 colors[6] = { white, red, green, blue, yellow, magenta };
3446
3447         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying layer contents" << tcu::TestLog::EndMessage;
3448
3449         switch (m_test)
3450         {
3451                 case TEST_DEFAULT_LAYER:
3452                         if (layerNdx == 0)
3453                                 return verifyImageSingleColoredRow(layer, 0.5f, white);
3454                         else
3455                                 return verifyEmptyImage(layer);
3456
3457                 case TEST_SINGLE_LAYER:
3458                         if (layerNdx == m_targetLayer)
3459                                 return verifyImageSingleColoredRow(layer, 0.5f, white);
3460                         else
3461                                 return verifyEmptyImage(layer);
3462
3463                 case TEST_ALL_LAYERS:
3464                 case TEST_INVOCATION_PER_LAYER:
3465                         return verifyImageSingleColoredRow(layer, 0.5f, colors[layerNdx]);
3466
3467                 case TEST_DIFFERENT_LAYERS:
3468                 case TEST_MULTIPLE_LAYERS_PER_INVOCATION:
3469                         if (layerNdx == 0)
3470                                 return verifyEmptyImage(layer);
3471                         else
3472                                 return verifyImageSingleColoredRow(layer, (float)layerNdx / (float)m_numLayers, white);
3473
3474                 case TEST_LAYER_ID:
3475                 {
3476                         const tcu::Vec4 layerColor((layerNdx % 2 == 1) ? (1.0f) : (0.5f),
3477                                                                            ((layerNdx/2) % 2 == 1) ? (1.0f) : (0.5f),
3478                                                                            (layerNdx == 0) ? (1.0f) : (0.0f),
3479                                                                            1.0f);
3480                         return verifyImageSingleColoredRow(layer, 0.5f, layerColor);
3481                 }
3482
3483                 case TEST_LAYER_PROVOKING_VERTEX:
3484                         if (m_provokingVertex == GL_FIRST_VERTEX_CONVENTION)
3485                         {
3486                                 if (layerNdx == 0)
3487                                         return verifyImageSingleColoredRow(layer, 0.5f, white);
3488                                 else
3489                                         return verifyEmptyImage(layer);
3490                         }
3491                         else if (m_provokingVertex == GL_LAST_VERTEX_CONVENTION)
3492                         {
3493                                 if (layerNdx == 1)
3494                                         return verifyImageSingleColoredRow(layer, 0.5f, white);
3495                                 else
3496                                         return verifyEmptyImage(layer);
3497                         }
3498                         else
3499                         {
3500                                 DE_ASSERT(false);
3501                                 return false;
3502                         }
3503
3504                 default:
3505                         DE_ASSERT(DE_FALSE);
3506                         return false;
3507         };
3508 }
3509
3510 bool LayeredRenderCase::verifyImageSingleColoredRow (const tcu::Surface& layer, float rowWidthRatio, const tcu::Vec4& barColor, bool logging)
3511 {
3512         DE_ASSERT(rowWidthRatio > 0.0f);
3513
3514         const int               barLength                       = (int)(rowWidthRatio * (float)layer.getWidth());
3515         const int               barLengthThreshold      = 1;
3516         tcu::Surface    errorMask                       (layer.getWidth(), layer.getHeight());
3517         bool                    allPixelsOk                     = true;
3518
3519         if (logging)
3520                 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting all pixels with distance less or equal to (about) " << barLength << " pixels from left border to be of color " << barColor.swizzle(0,1,2) << "." << tcu::TestLog::EndMessage;
3521
3522         tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toIVec());
3523
3524         for (int y = 0; y < layer.getHeight(); ++y)
3525         for (int x = 0; x < layer.getWidth(); ++x)
3526         {
3527                 const tcu::RGBA color           = layer.getPixel(x, y);
3528                 const tcu::RGBA refColor        = tcu::RGBA(barColor);
3529                 const int               threshold       = 8;
3530                 const bool              isBlack         = color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3531                 const bool              isColor         = tcu::allEqual(tcu::lessThan(tcu::abs(color.toIVec().swizzle(0, 1, 2) - refColor.toIVec().swizzle(0, 1, 2)), tcu::IVec3(threshold, threshold, threshold)), tcu::BVec3(true, true, true));
3532
3533                 bool                    isOk;
3534
3535                 if (x <= barLength - barLengthThreshold)
3536                         isOk = isColor;
3537                 else if (x >= barLength + barLengthThreshold)
3538                         isOk = isBlack;
3539                 else
3540                         isOk = isColor || isBlack;
3541
3542                 allPixelsOk &= isOk;
3543
3544                 if (!isOk)
3545                         errorMask.setPixel(x, y, tcu::RGBA::red());
3546         }
3547
3548         if (allPixelsOk)
3549         {
3550                 if (logging)
3551                         m_testCtx.getLog()      << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage
3552                                                                 << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3553                                                                 << tcu::TestLog::Image("Layer", "Layer", layer)
3554                                                                 << tcu::TestLog::EndImageSet;
3555                 return true;
3556         }
3557         else
3558         {
3559                 if (logging)
3560                         m_testCtx.getLog()      << tcu::TestLog::Message << "Image verification failed. Got unexpected pixels." << tcu::TestLog::EndMessage
3561                                                                 << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3562                                                                 << tcu::TestLog::Image("Layer",         "Layer",        layer)
3563                                                                 << tcu::TestLog::Image("ErrorMask",     "Errors",       errorMask)
3564                                                                 << tcu::TestLog::EndImageSet;
3565                 return false;
3566         }
3567
3568         if (logging)
3569                 m_testCtx.getLog() << tcu::TestLog::Image("LayerContent", "Layer content", layer);
3570
3571         return allPixelsOk;
3572 }
3573
3574 bool LayeredRenderCase::verifyEmptyImage (const tcu::Surface& layer, bool logging)
3575 {
3576         // Expect black
3577         if (logging)
3578                 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting empty image" << tcu::TestLog::EndMessage;
3579
3580         for (int y = 0; y < layer.getHeight(); ++y)
3581         for (int x = 0; x < layer.getWidth(); ++x)
3582         {
3583                 const tcu::RGBA color           = layer.getPixel(x, y);
3584                 const int               threshold       = 8;
3585                 const bool              isBlack         = color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3586
3587                 if (!isBlack)
3588                 {
3589                         if (logging)
3590                                 m_testCtx.getLog()      << tcu::TestLog::Message
3591                                                                         << "Found (at least) one bad pixel at " << x << "," << y << ". Pixel color is not background color."
3592                                                                         << tcu::TestLog::EndMessage
3593                                                                         << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3594                                                                         << tcu::TestLog::Image("Layer", "Layer", layer)
3595                                                                         << tcu::TestLog::EndImageSet;
3596                         return false;
3597                 }
3598         }
3599
3600         if (logging)
3601                 m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage;
3602
3603         return true;
3604 }
3605
3606 bool LayeredRenderCase::verifyProvokingVertexLayers (const tcu::Surface& layer0, const tcu::Surface& layer1)
3607 {
3608         const bool              layer0Empty             = verifyEmptyImage(layer0, false);
3609         const bool              layer1Empty             = verifyEmptyImage(layer1, false);
3610         bool                    error                   = false;
3611
3612         // Both images could contain something if the quad triangles get assigned to different layers
3613         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting non-empty layers, or non-empty layer." << tcu::TestLog::EndMessage;
3614
3615         if (layer0Empty == true && layer1Empty == true)
3616         {
3617                 m_testCtx.getLog() << tcu::TestLog::Message << "Got empty images." << tcu::TestLog::EndMessage;
3618                 error = true;
3619         }
3620
3621         // log images always
3622         m_testCtx.getLog()
3623                 << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3624                 << tcu::TestLog::Image("Layer", "Layer0", layer0)
3625                 << tcu::TestLog::Image("Layer", "Layer1", layer1)
3626                 << tcu::TestLog::EndImageSet;
3627
3628         if (error)
3629                 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
3630         else
3631                 m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage;
3632
3633         return !error;
3634 }
3635
3636 int LayeredRenderCase::getTargetLayers (LayeredRenderTargetType target)
3637 {
3638         switch (target)
3639         {
3640                 case TARGET_CUBE:                       return 6;
3641                 case TARGET_3D:                         return 4;
3642                 case TARGET_1D_ARRAY:           return 4;
3643                 case TARGET_2D_ARRAY:           return 4;
3644                 case TARGET_2D_MS_ARRAY:        return 2;
3645                 default:
3646                         DE_ASSERT(DE_FALSE);
3647                         return 0;
3648         }
3649 }
3650
3651 glw::GLenum LayeredRenderCase::getTargetTextureTarget (LayeredRenderTargetType target)
3652 {
3653         switch (target)
3654         {
3655                 case TARGET_CUBE:                       return GL_TEXTURE_CUBE_MAP;
3656                 case TARGET_3D:                         return GL_TEXTURE_3D;
3657                 case TARGET_1D_ARRAY:           return GL_TEXTURE_1D_ARRAY;
3658                 case TARGET_2D_ARRAY:           return GL_TEXTURE_2D_ARRAY;
3659                 case TARGET_2D_MS_ARRAY:        return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
3660                 default:
3661                         DE_ASSERT(DE_FALSE);
3662                         return 0;
3663         }
3664 }
3665
3666 tcu::IVec3 LayeredRenderCase::getTargetDimensions (LayeredRenderTargetType target)
3667 {
3668         switch (target)
3669         {
3670                 case TARGET_CUBE:                       return tcu::IVec3(64, 64, 0);
3671                 case TARGET_3D:                         return tcu::IVec3(64, 64, 4);
3672                 case TARGET_1D_ARRAY:           return tcu::IVec3(64, 4, 0);
3673                 case TARGET_2D_ARRAY:           return tcu::IVec3(64, 64, 4);
3674                 case TARGET_2D_MS_ARRAY:        return tcu::IVec3(64, 64, 2);
3675                 default:
3676                         DE_ASSERT(DE_FALSE);
3677                         return tcu::IVec3(0, 0, 0);
3678         }
3679 }
3680
3681 tcu::IVec2 LayeredRenderCase::getResolveDimensions (LayeredRenderTargetType target)
3682 {
3683         switch (target)
3684         {
3685                 case TARGET_CUBE:                       return tcu::IVec2(64, 64);
3686                 case TARGET_3D:                         return tcu::IVec2(64, 64);
3687                 case TARGET_1D_ARRAY:           return tcu::IVec2(64, 1);
3688                 case TARGET_2D_ARRAY:           return tcu::IVec2(64, 64);
3689                 case TARGET_2D_MS_ARRAY:        return tcu::IVec2(64, 64);
3690                 default:
3691                         DE_ASSERT(DE_FALSE);
3692                         return tcu::IVec2(0, 0);
3693         }
3694 }
3695
3696 class VaryingOutputCountCase : public GeometryShaderRenderTest
3697 {
3698 public:
3699         enum ShaderInstancingMode
3700         {
3701                 MODE_WITHOUT_INSTANCING = 0,
3702                 MODE_WITH_INSTANCING,
3703
3704                 MODE_LAST
3705         };
3706                                                                                                         VaryingOutputCountCase                  (Context& context, const char* name, const char* desc, VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode);
3707 private:
3708         void                                                                                    init                                                    (void);
3709         void                                                                                    deinit                                                  (void);
3710         void                                                                                    preRender                                               (sglr::Context& ctx, GLuint programID);
3711
3712         sglr::ShaderProgram&                                                    getProgram                                              (void);
3713         void                                                                                    genVertexAttribData                             (void);
3714         void                                                                                    genVertexDataWithoutInstancing  (void);
3715         void                                                                                    genVertexDataWithInstancing             (void);
3716
3717         VaryingOutputCountShader*                                               m_program;
3718         const VaryingOutputCountShader::VaryingSource   m_test;
3719         const ShaderInstancingMode                                              m_mode;
3720         int                                                                                             m_maxEmitCount;
3721 };
3722
3723 VaryingOutputCountCase::VaryingOutputCountCase (Context& context, const char* name, const char* desc, VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode)
3724         : GeometryShaderRenderTest      (context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, VaryingOutputCountShader::getAttributeName(test))
3725         , m_program                                     (DE_NULL)
3726         , m_test                                        (test)
3727         , m_mode                                        (mode)
3728         , m_maxEmitCount                        (0)
3729 {
3730         DE_ASSERT(mode < MODE_LAST);
3731 }
3732
3733 void VaryingOutputCountCase::init (void)
3734 {
3735         // Check requirements
3736
3737         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
3738                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
3739
3740         if (m_test == VaryingOutputCountShader::READ_TEXTURE)
3741         {
3742                 glw::GLint maxTextures = 0;
3743
3744                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &maxTextures);
3745
3746                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = " << maxTextures << tcu::TestLog::EndMessage;
3747
3748                 if (maxTextures < 1)
3749                         throw tcu::NotSupportedError("Geometry shader texture units required");
3750         }
3751
3752         // Get max emit count
3753         {
3754                 const int       componentsPerVertex     = 4 + 4; // vec4 pos, vec4 color
3755                 glw::GLint      maxVertices                     = 0;
3756                 glw::GLint      maxComponents           = 0;
3757
3758                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
3759                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
3760
3761                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices << tcu::TestLog::EndMessage;
3762                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents << tcu::TestLog::EndMessage;
3763                 m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex << tcu::TestLog::EndMessage;
3764
3765                 if (maxVertices < 256)
3766                         throw tcu::TestError("MAX_GEOMETRY_OUTPUT_VERTICES was less than minimum required (256)");
3767                 if (maxComponents < 1024)
3768                         throw tcu::TestError("MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS was less than minimum required (1024)");
3769
3770                 m_maxEmitCount = de::min(maxVertices, maxComponents / componentsPerVertex);
3771         }
3772
3773         // Log what the test tries to do
3774
3775         m_testCtx.getLog()
3776                 << tcu::TestLog::Message
3777                 << "Rendering 4 n-gons with n = "
3778                 << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0)) << ", "
3779                 << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1)) << ", "
3780                 << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2)) << ", and "
3781                 << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3)) << ".\n"
3782                 << "N is supplied to the geomery shader with "
3783                 << ((m_test == VaryingOutputCountShader::READ_ATTRIBUTE) ? ("attribute") : (m_test == VaryingOutputCountShader::READ_UNIFORM) ? ("uniform") : ("texture"))
3784                 << tcu::TestLog::EndMessage;
3785
3786         // Gen shader
3787         {
3788                 const bool instanced = (m_mode == MODE_WITH_INSTANCING);
3789
3790                 DE_ASSERT(!m_program);
3791                 m_program = new VaryingOutputCountShader(m_context.getRenderContext().getType(), m_test, m_maxEmitCount, instanced);
3792         }
3793
3794         // Case init
3795         GeometryShaderRenderTest::init();
3796 }
3797
3798 void VaryingOutputCountCase::deinit (void)
3799 {
3800         if (m_program)
3801         {
3802                 delete m_program;
3803                 m_program = DE_NULL;
3804         }
3805
3806         GeometryShaderRenderTest::deinit();
3807 }
3808
3809 void VaryingOutputCountCase::preRender (sglr::Context& ctx, GLuint programID)
3810 {
3811         if (m_test == VaryingOutputCountShader::READ_UNIFORM)
3812         {
3813                 const int               location                = ctx.getUniformLocation(programID, "u_emitCount");
3814                 const deInt32   emitCount[4]    = { 6, 0, m_maxEmitCount, 10 };
3815
3816                 if (location == -1)
3817                         throw tcu::TestError("uniform location of u_emitCount was -1.");
3818
3819                 ctx.uniform4iv(location, 1, emitCount);
3820         }
3821         else if (m_test == VaryingOutputCountShader::READ_TEXTURE)
3822         {
3823                 const deUint8 data[4*4] =
3824                 {
3825                         255,   0,   0,   0,
3826                           0, 255,   0,   0,
3827                           0,   0, 255,   0,
3828                           0,   0,   0, 255,
3829                 };
3830                 const int       location        = ctx.getUniformLocation(programID, "u_sampler");
3831                 GLuint          texID           = 0;
3832
3833                 if (location == -1)
3834                         throw tcu::TestError("uniform location of u_sampler was -1.");
3835                 ctx.uniform1i(location, 0);
3836
3837                 // \note we don't need to explicitly delete the texture, the sglr context will delete it
3838                 ctx.genTextures(1, &texID);
3839                 ctx.bindTexture(GL_TEXTURE_2D, texID);
3840                 ctx.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
3841                 ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3842                 ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3843         }
3844 }
3845
3846 sglr::ShaderProgram& VaryingOutputCountCase::getProgram (void)
3847 {
3848         return *m_program;
3849 }
3850
3851 void VaryingOutputCountCase::genVertexAttribData (void)
3852 {
3853         if (m_mode == MODE_WITHOUT_INSTANCING)
3854                 genVertexDataWithoutInstancing();
3855         else if (m_mode == MODE_WITH_INSTANCING)
3856                 genVertexDataWithInstancing();
3857         else
3858                 DE_ASSERT(false);
3859 }
3860
3861 void VaryingOutputCountCase::genVertexDataWithoutInstancing (void)
3862 {
3863         m_numDrawVertices = 4;
3864
3865         m_vertexPosData.resize(4);
3866         m_vertexAttrData.resize(4);
3867
3868         m_vertexPosData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 1.0f);
3869         m_vertexPosData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 1.0f);
3870         m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
3871         m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
3872
3873         if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
3874         {
3875                 m_vertexAttrData[0] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_0)), 0.0f, 0.0f, 0.0f);
3876                 m_vertexAttrData[1] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_1)), 0.0f, 0.0f, 0.0f);
3877                 m_vertexAttrData[2] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_2)), 0.0f, 0.0f, 0.0f);
3878                 m_vertexAttrData[3] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_3)), 0.0f, 0.0f, 0.0f);
3879         }
3880         else
3881         {
3882                 m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
3883                 m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
3884                 m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
3885                 m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
3886         }
3887 }
3888
3889 void VaryingOutputCountCase::genVertexDataWithInstancing (void)
3890 {
3891         m_numDrawVertices = 1;
3892
3893         m_vertexPosData.resize(1);
3894         m_vertexAttrData.resize(1);
3895
3896         m_vertexPosData[0] = tcu::Vec4(0.0f,  0.0f, 0.0f, 1.0f);
3897
3898         if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
3899         {
3900                 const int emitCounts[] =
3901                 {
3902                         (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0),
3903                         (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1),
3904                         (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2),
3905                         (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3),
3906                 };
3907
3908                 m_vertexAttrData[0] = tcu::Vec4((float)emitCounts[0], (float)emitCounts[1], (float)emitCounts[2], (float)emitCounts[3]);
3909         }
3910         else
3911         {
3912                 // not used
3913                 m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
3914         }
3915 }
3916
3917 class GeometryProgramQueryCase : public TestCase
3918 {
3919 public:
3920         struct ProgramCase
3921         {
3922                 const char*     description;
3923                 const char*     header;
3924                 int                     value;
3925         };
3926
3927                                                 GeometryProgramQueryCase                        (Context& context, const char* name, const char* description, glw::GLenum target);
3928
3929         void                            init                                                            (void);
3930         IterateResult           iterate                                                         (void);
3931
3932 private:
3933         void                            expectProgramValue                                      (deUint32 program, int value);
3934         void                            expectQueryError                                        (deUint32 program);
3935
3936         const glw::GLenum       m_target;
3937
3938 protected:
3939         std::vector<ProgramCase> m_cases;
3940 };
3941
3942 GeometryProgramQueryCase::GeometryProgramQueryCase (Context& context, const char* name, const char* description, glw::GLenum target)
3943         : TestCase      (context, name, description)
3944         , m_target      (target)
3945 {
3946 }
3947
3948 void GeometryProgramQueryCase::init (void)
3949 {
3950         if (!(m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") || glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))))
3951                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
3952 }
3953
3954 GeometryProgramQueryCase::IterateResult GeometryProgramQueryCase::iterate (void)
3955 {
3956         const bool                      supportsES32                    = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
3957
3958         const std::string       vertexSource                    = std::string(glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) + "\n"
3959                                                                                                   "void main ()\n"
3960                                                                                                   "{\n"
3961                                                                                                   "     gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
3962                                                                                                   "}\n";
3963         const std::string       fragmentSource                  = std::string(glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) + "\n"
3964                                                                                                   "layout(location = 0) out mediump vec4 fragColor;\n"
3965                                                                                                   "void main ()\n"
3966                                                                                                   "{\n"
3967                                                                                                   "     fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
3968                                                                                                   "}\n";
3969         static const char*      s_geometryBody                  ="void main ()\n"
3970                                                                                                   "{\n"
3971                                                                                                   "     gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
3972                                                                                                   "     EmitVertex();\n"
3973                                                                                                   "}\n";
3974
3975         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3976
3977         // default cases
3978         for (int ndx = 0; ndx < (int)m_cases.size(); ++ndx)
3979         {
3980                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "Case", m_cases[ndx].description);
3981                 const std::string                       geometrySource  = m_cases[ndx].header + std::string(s_geometryBody);
3982                 const glu::ShaderProgram        program                 (m_context.getRenderContext(),
3983                                                                                                                 glu::ProgramSources()
3984                                                                                                                 << glu::VertexSource(vertexSource)
3985                                                                                                                 << glu::FragmentSource(fragmentSource)
3986                                                                                                                 << glu::GeometrySource(specializeShader(geometrySource, m_context.getRenderContext().getType())));
3987
3988                 m_testCtx.getLog() << program;
3989                 expectProgramValue(program.getProgram(), m_cases[ndx].value);
3990         }
3991
3992         // no geometry shader -case (INVALID OP)
3993         {
3994                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "NoGeometryShader", "No geometry shader");
3995                 const glu::ShaderProgram        program                 (m_context.getRenderContext(),
3996                                                                                                                 glu::ProgramSources()
3997                                                                                                                 << glu::VertexSource(vertexSource)
3998                                                                                                                 << glu::FragmentSource(fragmentSource));
3999
4000                 m_testCtx.getLog() << program;
4001                 expectQueryError(program.getProgram());
4002         }
4003
4004         // not linked -case (INVALID OP)
4005         {
4006                 const tcu::ScopedLogSection section                             (m_testCtx.getLog(), "NotLinkedProgram", "Shader program not linked");
4007                 const std::string       geometrySource                          = std::string(glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) + "\n"
4008                                                                                                                 + std::string(supportsES32 ? "" : "#extension GL_EXT_geometry_shader : require\n")
4009                                                                                                                 + "layout (triangles) in;\n"
4010                                                                                                                 "layout (points, max_vertices = 3) out;\n"
4011                                                                                                                 + std::string(s_geometryBody);
4012
4013
4014                 const char* const                       vtxSourcePtr    = vertexSource.c_str();
4015                 const char* const                       fragSourcePtr   = fragmentSource.c_str();
4016                 const char* const                       geomSourcePtr   = geometrySource.c_str();
4017
4018                 glu::Shader                                     vertexShader    (m_context.getRenderContext(), glu::SHADERTYPE_VERTEX);
4019                 glu::Shader                                     fragmentShader  (m_context.getRenderContext(), glu::SHADERTYPE_FRAGMENT);
4020                 glu::Shader                                     geometryShader  (m_context.getRenderContext(), glu::SHADERTYPE_GEOMETRY);
4021                 glu::Program                            program                 (m_context.getRenderContext());
4022
4023                 vertexShader.setSources(1, &vtxSourcePtr, DE_NULL);
4024                 fragmentShader.setSources(1, &fragSourcePtr, DE_NULL);
4025                 geometryShader.setSources(1, &geomSourcePtr, DE_NULL);
4026
4027                 vertexShader.compile();
4028                 fragmentShader.compile();
4029                 geometryShader.compile();
4030
4031                 if (!vertexShader.getCompileStatus()   ||
4032                         !fragmentShader.getCompileStatus() ||
4033                         !geometryShader.getCompileStatus())
4034                         throw tcu::TestError("Failed to compile shader");
4035
4036                 program.attachShader(vertexShader.getShader());
4037                 program.attachShader(fragmentShader.getShader());
4038                 program.attachShader(geometryShader.getShader());
4039
4040                 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a program with geometry shader, but not linking it" << tcu::TestLog::EndMessage;
4041
4042                 expectQueryError(program.getProgram());
4043         }
4044
4045         return STOP;
4046 }
4047
4048 void GeometryProgramQueryCase::expectProgramValue (deUint32 program, int value)
4049 {
4050         const glw::Functions&                                                                           gl              = m_context.getRenderContext().getFunctions();
4051         gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint>     state;
4052
4053         gl.getProgramiv(program, m_target, &state);
4054         GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
4055
4056         m_testCtx.getLog() << tcu::TestLog::Message << glu::getProgramParamStr(m_target) << " = " << state << tcu::TestLog::EndMessage;
4057
4058         if (state != value)
4059         {
4060                 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << value << ", got " << state << tcu::TestLog::EndMessage;
4061
4062                 // don't overwrite error
4063                 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
4064                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
4065         }
4066 }
4067
4068 void GeometryProgramQueryCase::expectQueryError (deUint32 program)
4069 {
4070         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
4071         glw::GLint                              dummy;
4072         glw::GLenum                             errorCode;
4073
4074         m_testCtx.getLog() << tcu::TestLog::Message << "Querying " << glu::getProgramParamStr(m_target) << ", expecting INVALID_OPERATION" << tcu::TestLog::EndMessage;
4075         gl.getProgramiv(program, m_target, &dummy);
4076
4077         errorCode = gl.getError();
4078
4079         if (errorCode != GL_INVALID_OPERATION)
4080         {
4081                 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected INVALID_OPERATION, got " << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
4082
4083                 // don't overwrite error
4084                 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
4085                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected error code");
4086         }
4087 }
4088
4089 class GeometryShaderInvocationsQueryCase : public GeometryProgramQueryCase
4090 {
4091 public:
4092         GeometryShaderInvocationsQueryCase(Context& context, const char* name, const char* description);
4093 };
4094
4095 GeometryShaderInvocationsQueryCase::GeometryShaderInvocationsQueryCase(Context& context, const char* name, const char* description)
4096         : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_SHADER_INVOCATIONS)
4097 {
4098         // 2 normal cases
4099         m_cases.resize(2);
4100
4101         m_cases[0].description  = "Default value";
4102         m_cases[0].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
4103         m_cases[0].value                = 1;
4104
4105         m_cases[1].description  = "Value declared";
4106         m_cases[1].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles, invocations=2) in;\nlayout (points, max_vertices = 3) out;\n";
4107         m_cases[1].value                = 2;
4108 }
4109
4110 class GeometryShaderVerticesQueryCase : public GeometryProgramQueryCase
4111 {
4112 public:
4113         GeometryShaderVerticesQueryCase(Context& context, const char* name, const char* description);
4114 };
4115
4116 GeometryShaderVerticesQueryCase::GeometryShaderVerticesQueryCase (Context& context, const char* name, const char* description)
4117         : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_VERTICES_OUT_EXT)
4118 {
4119         m_cases.resize(1);
4120
4121         m_cases[0].description  = "max_vertices = 1";
4122         m_cases[0].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, max_vertices = 1) out;\n";
4123         m_cases[0].value                = 1;
4124 }
4125
4126 class GeometryShaderInputQueryCase : public GeometryProgramQueryCase
4127 {
4128 public:
4129         GeometryShaderInputQueryCase(Context& context, const char* name, const char* description);
4130 };
4131
4132 GeometryShaderInputQueryCase::GeometryShaderInputQueryCase(Context& context, const char* name, const char* description)
4133         : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_INPUT_TYPE_EXT)
4134 {
4135         m_cases.resize(3);
4136
4137         m_cases[0].description  = "Triangles";
4138         m_cases[0].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
4139         m_cases[0].value                = GL_TRIANGLES;
4140
4141         m_cases[1].description  = "Lines";
4142         m_cases[1].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (lines) in;\nlayout (points, max_vertices = 3) out;\n";
4143         m_cases[1].value                = GL_LINES;
4144
4145         m_cases[2].description  = "Points";
4146         m_cases[2].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (points) in;\nlayout (points, max_vertices = 3) out;\n";
4147         m_cases[2].value                = GL_POINTS;
4148 }
4149
4150 class GeometryShaderOutputQueryCase : public GeometryProgramQueryCase
4151 {
4152 public:
4153         GeometryShaderOutputQueryCase(Context& context, const char* name, const char* description);
4154 };
4155
4156 GeometryShaderOutputQueryCase::GeometryShaderOutputQueryCase(Context& context, const char* name, const char* description)
4157         : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT)
4158 {
4159         m_cases.resize(3);
4160
4161         m_cases[0].description  = "Triangle strip";
4162         m_cases[0].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (triangle_strip, max_vertices = 3) out;\n";
4163         m_cases[0].value                = GL_TRIANGLE_STRIP;
4164
4165         m_cases[1].description  = "Lines";
4166         m_cases[1].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (line_strip, max_vertices = 3) out;\n";
4167         m_cases[1].value                = GL_LINE_STRIP;
4168
4169         m_cases[2].description  = "Points";
4170         m_cases[2].header               = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
4171         m_cases[2].value                = GL_POINTS;
4172 }
4173
4174 class ImplementationLimitCase : public TestCase
4175 {
4176 public:
4177                                                 ImplementationLimitCase (Context& context, const char* name, const char* description, glw::GLenum target, int minValue);
4178
4179         void                            init                                    (void);
4180         IterateResult           iterate                                 (void);
4181
4182         const glw::GLenum       m_target;
4183         const int                       m_minValue;
4184 };
4185
4186 ImplementationLimitCase::ImplementationLimitCase (Context& context, const char* name, const char* description, glw::GLenum target, int minValue)
4187         : TestCase              (context, name, description)
4188         , m_target              (target)
4189         , m_minValue    (minValue)
4190 {
4191 }
4192
4193 void ImplementationLimitCase::init (void)
4194 {
4195         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4196                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4197 }
4198
4199 ImplementationLimitCase::IterateResult ImplementationLimitCase::iterate (void)
4200 {
4201         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4202         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
4203
4204         gl.enableLogging(true);
4205         verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
4206
4207         {
4208                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
4209                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
4210                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
4211                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
4212         }
4213
4214         result.setTestContextResult(m_testCtx);
4215         return STOP;
4216 }
4217
4218 class LayerProvokingVertexQueryCase : public TestCase
4219 {
4220 public:
4221                                         LayerProvokingVertexQueryCase   (Context& context, const char* name, const char* description);
4222
4223         void                    init                                                    (void);
4224         IterateResult   iterate                                                 (void);
4225 };
4226
4227 LayerProvokingVertexQueryCase::LayerProvokingVertexQueryCase (Context& context, const char* name, const char* description)
4228         : TestCase(context, name, description)
4229 {
4230 }
4231
4232 void LayerProvokingVertexQueryCase::init (void)
4233 {
4234         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4235                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4236 }
4237
4238 LayerProvokingVertexQueryCase::IterateResult LayerProvokingVertexQueryCase::iterate (void)
4239 {
4240         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4241         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
4242         QueriedState                    state;
4243
4244         gl.enableLogging(true);
4245         queryState(result, gl, QUERY_INTEGER, GL_LAYER_PROVOKING_VERTEX, state);
4246
4247         if (!state.isUndefined())
4248         {
4249                 m_testCtx.getLog() << tcu::TestLog::Message << "LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state.getIntAccess()) << tcu::TestLog::EndMessage;
4250
4251                 if (state.getIntAccess() != GL_FIRST_VERTEX_CONVENTION &&
4252                         state.getIntAccess() != GL_LAST_VERTEX_CONVENTION &&
4253                         state.getIntAccess() != GL_UNDEFINED_VERTEX)
4254                 {
4255                         m_testCtx.getLog()
4256                                 << tcu::TestLog::Message
4257                                 << "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got "
4258                                 << state.getIntAccess() << "\n"
4259                                 << "Expected any of {FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, UNDEFINED_VERTEX}."
4260                                 << tcu::TestLog::EndMessage;
4261
4262                         result.fail("got unexpected provoking vertex value");
4263                 }
4264
4265                 {
4266                         const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
4267                         verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_BOOLEAN);
4268                         verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_INTEGER64);
4269                         verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_FLOAT);
4270                 }
4271         }
4272
4273         result.setTestContextResult(m_testCtx);
4274         return STOP;
4275 }
4276
4277 class GeometryInvocationCase : public GeometryShaderRenderTest
4278 {
4279 public:
4280         enum OutputCase
4281         {
4282                 CASE_FIXED_OUTPUT_COUNTS = 0,
4283                 CASE_DIFFERENT_OUTPUT_COUNTS,
4284
4285                 CASE_LAST
4286         };
4287
4288                                                                 GeometryInvocationCase  (Context& context, const char* name, const char* description, int numInvocations, OutputCase testCase);
4289                                                                 ~GeometryInvocationCase (void);
4290
4291         void                                            init                                    (void);
4292         void                                            deinit                                  (void);
4293
4294 private:
4295         sglr::ShaderProgram&            getProgram                              (void);
4296         void                                            genVertexAttribData             (void);
4297
4298         static InvocationCountShader::OutputCase mapToShaderCaseType (OutputCase testCase);
4299
4300         const OutputCase                        m_testCase;
4301         int                                                     m_numInvocations;
4302         InvocationCountShader*          m_program;
4303 };
4304
4305 GeometryInvocationCase::GeometryInvocationCase (Context& context, const char* name, const char* description, int numInvocations, OutputCase testCase)
4306         : GeometryShaderRenderTest      (context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
4307         , m_testCase                            (testCase)
4308         , m_numInvocations                      (numInvocations)
4309         , m_program                                     (DE_NULL)
4310 {
4311         DE_ASSERT(m_testCase < CASE_LAST);
4312 }
4313
4314 GeometryInvocationCase::~GeometryInvocationCase (void)
4315 {
4316         deinit();
4317 }
4318
4319 void GeometryInvocationCase::init (void)
4320 {
4321         const glw::Functions&   gl                                                              = m_context.getRenderContext().getFunctions();
4322         int                                             maxGeometryShaderInvocations    = 0;
4323         int                                             maxComponents                                   = 0;
4324
4325         // requirements
4326
4327         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4328                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4329
4330         gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &maxGeometryShaderInvocations);
4331         GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS)");
4332
4333         gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
4334         GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS)");
4335
4336         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << maxGeometryShaderInvocations << tcu::TestLog::EndMessage;
4337
4338         // set target num invocations
4339
4340         if (m_numInvocations == -1)
4341                 m_numInvocations = maxGeometryShaderInvocations;
4342         else if (maxGeometryShaderInvocations < m_numInvocations)
4343                 throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_SHADER_INVOCATIONS");
4344
4345         if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4346         {
4347                 const int maxEmitCount  = m_numInvocations + 2;
4348                 const int numComponents = 8; // pos + color
4349                 if (maxEmitCount * numComponents > maxComponents)
4350                         throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS");
4351         }
4352
4353         // Log what the test tries to do
4354
4355         if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
4356         {
4357                 m_testCtx.getLog()
4358                         << tcu::TestLog::Message
4359                         << "Rendering triangles in a partial circle formation with a geometry shader. Each triangle is generated by a separate invocation.\n"
4360                         << "Drawing 2 points, each generating " << m_numInvocations << " triangles."
4361                         << tcu::TestLog::EndMessage;
4362         }
4363         else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4364         {
4365                 m_testCtx.getLog()
4366                         << tcu::TestLog::Message
4367                         << "Rendering n-gons in a partial circle formation with a geometry shader. Each n-gon is generated by a separate invocation.\n"
4368                         << "Drawing 2 points, each generating " << m_numInvocations << " n-gons."
4369                         << tcu::TestLog::EndMessage;
4370         }
4371         else
4372                 DE_ASSERT(false);
4373
4374         // resources
4375
4376         m_program = new InvocationCountShader(m_context.getRenderContext().getType(), m_numInvocations, mapToShaderCaseType(m_testCase));
4377
4378         GeometryShaderRenderTest::init();
4379 }
4380
4381 void GeometryInvocationCase::deinit (void)
4382 {
4383         if (m_program)
4384         {
4385                 delete m_program;
4386                 m_program = DE_NULL;
4387         }
4388
4389         GeometryShaderRenderTest::deinit();
4390 }
4391
4392 sglr::ShaderProgram& GeometryInvocationCase::getProgram (void)
4393 {
4394         return *m_program;
4395 }
4396
4397 void GeometryInvocationCase::genVertexAttribData (void)
4398 {
4399         m_vertexPosData.resize(2);
4400         m_vertexPosData[0] = tcu::Vec4(0.0f,-0.3f, 0.0f, 1.0f);
4401         m_vertexPosData[1] = tcu::Vec4(0.2f, 0.3f, 0.0f, 1.0f);
4402
4403         m_vertexAttrData.resize(2);
4404         m_vertexAttrData[0] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
4405         m_vertexAttrData[1] = tcu::Vec4(0.8f, 0.8f, 0.8f, 1.0f);
4406         m_numDrawVertices = 2;
4407 }
4408
4409 InvocationCountShader::OutputCase GeometryInvocationCase::mapToShaderCaseType (OutputCase testCase)
4410 {
4411         switch (testCase)
4412         {
4413                 case CASE_FIXED_OUTPUT_COUNTS:                  return InvocationCountShader::CASE_FIXED_OUTPUT_COUNTS;
4414                 case CASE_DIFFERENT_OUTPUT_COUNTS:              return InvocationCountShader::CASE_DIFFERENT_OUTPUT_COUNTS;
4415                 default:
4416                         DE_ASSERT(false);
4417                         return InvocationCountShader::CASE_LAST;
4418         }
4419 }
4420
4421 class DrawInstancedGeometryInstancedCase : public GeometryShaderRenderTest
4422 {
4423 public:
4424                                                                 DrawInstancedGeometryInstancedCase      (Context& context, const char* name, const char* description, int numInstances, int numInvocations);
4425                                                                 ~DrawInstancedGeometryInstancedCase     (void);
4426
4427 private:
4428         void                                            init                                                            (void);
4429         void                                            deinit                                                          (void);
4430         sglr::ShaderProgram&            getProgram                                                      (void);
4431         void                                            genVertexAttribData                                     (void);
4432
4433         const int                                       m_numInstances;
4434         const int                                       m_numInvocations;
4435         InstancedExpansionShader*       m_program;
4436 };
4437
4438 DrawInstancedGeometryInstancedCase::DrawInstancedGeometryInstancedCase (Context& context, const char* name, const char* description, int numInstances, int numInvocations)
4439         : GeometryShaderRenderTest      (context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_offset", FLAG_DRAW_INSTANCED)
4440         , m_numInstances                        (numInstances)
4441         , m_numInvocations                      (numInvocations)
4442         , m_program                                     (DE_NULL)
4443 {
4444 }
4445
4446 DrawInstancedGeometryInstancedCase::~DrawInstancedGeometryInstancedCase (void)
4447 {
4448 }
4449
4450 void DrawInstancedGeometryInstancedCase::init (void)
4451 {
4452         m_program = new InstancedExpansionShader(m_context.getRenderContext().getType(), m_numInvocations);
4453
4454         m_testCtx.getLog()
4455                 << tcu::TestLog::Message
4456                 << "Rendering a single point with " << m_numInstances << " instances. "
4457                 << "Each geometry shader is invoked " << m_numInvocations << " times for each primitive. "
4458                 << tcu::TestLog::EndMessage;
4459
4460         GeometryShaderRenderTest::init();
4461 }
4462
4463 void DrawInstancedGeometryInstancedCase::deinit(void)
4464 {
4465         if (m_program)
4466         {
4467                 delete m_program;
4468                 m_program = DE_NULL;
4469         }
4470
4471         GeometryShaderRenderTest::deinit();
4472 }
4473
4474 sglr::ShaderProgram& DrawInstancedGeometryInstancedCase::getProgram (void)
4475 {
4476         return *m_program;
4477 }
4478
4479 void DrawInstancedGeometryInstancedCase::genVertexAttribData (void)
4480 {
4481         m_numDrawVertices = 1;
4482         m_numDrawInstances = m_numInstances;
4483         m_vertexAttrDivisor = 1;
4484
4485         m_vertexPosData.resize(1);
4486         m_vertexAttrData.resize(8);
4487
4488         m_vertexPosData[0] = tcu::Vec4( 0.0f,  0.0f, 0.0f, 1.0f);
4489
4490         m_vertexAttrData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 0.0f);
4491         m_vertexAttrData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 0.0f);
4492         m_vertexAttrData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 0.0f);
4493         m_vertexAttrData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 0.0f);
4494         m_vertexAttrData[4] = tcu::Vec4(-0.8f, -0.7f, 0.0f, 0.0f);
4495         m_vertexAttrData[5] = tcu::Vec4(-0.9f,  0.6f, 0.0f, 0.0f);
4496         m_vertexAttrData[6] = tcu::Vec4(-0.8f,  0.3f, 0.0f, 0.0f);
4497         m_vertexAttrData[7] = tcu::Vec4(-0.1f,  0.1f, 0.0f, 0.0f);
4498
4499         DE_ASSERT(m_numInstances <= (int)m_vertexAttrData.size());
4500 }
4501
4502 class GeometryProgramLimitCase : public TestCase
4503 {
4504 public:
4505                                                 GeometryProgramLimitCase        (Context& context, const char* name, const char* description, glw::GLenum apiName, const std::string& glslName, int limit);
4506
4507 private:
4508         void                            init                                            (void);
4509         IterateResult           iterate                                         (void);
4510
4511         const glw::GLenum       m_apiName;
4512         const std::string       m_glslName;
4513         const int                       m_limit;
4514 };
4515
4516 GeometryProgramLimitCase::GeometryProgramLimitCase (Context& context, const char* name, const char* description, glw::GLenum apiName, const std::string& glslName, int limit)
4517         : TestCase              (context, name, description)
4518         , m_apiName             (apiName)
4519         , m_glslName    (glslName)
4520         , m_limit               (limit)
4521 {
4522 }
4523
4524 void GeometryProgramLimitCase::init (void)
4525 {
4526         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4527                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4528 }
4529
4530 GeometryProgramLimitCase::IterateResult GeometryProgramLimitCase::iterate (void)
4531 {
4532         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
4533         int                                             limit;
4534
4535         // query limit
4536         {
4537                 gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint>     state;
4538                 glu::CallLogWrapper                                                                                     gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4539
4540                 gl.enableLogging(true);
4541                 gl.glGetIntegerv(m_apiName, &state);
4542                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getIntegerv()");
4543
4544                 m_testCtx.getLog() << tcu::TestLog::Message << glu::getGettableStateStr(m_apiName) << " = " << state << tcu::TestLog::EndMessage;
4545
4546                 if (!state.verifyValidity(result))
4547                 {
4548                         result.setTestContextResult(m_testCtx);
4549                         return STOP;
4550                 }
4551
4552                 if (state < m_limit)
4553                 {
4554                         result.fail("Minimum value = " + de::toString(m_limit) + ", got " + de::toString(state.get()));
4555                         result.setTestContextResult(m_testCtx);
4556                         return STOP;
4557                 }
4558
4559                 limit = state;
4560
4561                 // verify other getters
4562                 {
4563                         const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
4564                         verifyStateInteger(result, gl, m_apiName, limit, QUERY_BOOLEAN);
4565                         verifyStateInteger(result, gl, m_apiName, limit, QUERY_INTEGER64);
4566                         verifyStateInteger(result, gl, m_apiName, limit, QUERY_FLOAT);
4567                 }
4568         }
4569
4570         // verify limit is the same in GLSL
4571         {
4572                 static const char* const vertexSource =         "${GLSL_VERSION_DECL}\n"
4573                                                                                                         "void main ()\n"
4574                                                                                                         "{\n"
4575                                                                                                         "       gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
4576                                                                                                         "}\n";
4577                 static const char* const fragmentSource =       "${GLSL_VERSION_DECL}\n"
4578                                                                                                         "layout(location = 0) out mediump vec4 fragColor;\n"
4579                                                                                                         "void main ()\n"
4580                                                                                                         "{\n"
4581                                                                                                         "       fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
4582                                                                                                         "}\n";
4583                 const std::string geometrySource =                      "${GLSL_VERSION_DECL}\n"
4584                                                                                                         "${GLSL_EXT_GEOMETRY_SHADER}"
4585                                                                                                         "layout(points) in;\n"
4586                                                                                                         "layout(points, max_vertices = 1) out;\n"
4587                                                                                                         "void main ()\n"
4588                                                                                                         "{\n"
4589                                                                                                         "       // Building the shader will fail if the constant value is not the expected\n"
4590                                                                                                         "       const mediump int cArraySize = (gl_" + m_glslName + " == " + de::toString(limit) + ") ? (1) : (-1);\n"
4591                                                                                                         "       float[cArraySize] fArray;\n"
4592                                                                                                         "       fArray[0] = 0.0f;\n"
4593                                                                                                         "       gl_Position = vec4(0.0, 0.0, 0.0, fArray[0]);\n"
4594                                                                                                         "       EmitVertex();\n"
4595                                                                                                         "}\n";
4596
4597                 const de::UniquePtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_context.getRenderContext(),
4598                                                                                                                                                            glu::ProgramSources()
4599                                                                                                                                                            << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()))
4600                                                                                                                                                            << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()))
4601                                                                                                                                                            << glu::GeometrySource(specializeShader(geometrySource, m_context.getRenderContext().getType()))));
4602
4603                 m_testCtx.getLog() << tcu::TestLog::Message << "Building a test shader to verify GLSL constant " << m_glslName << " value." << tcu::TestLog::EndMessage;
4604                 m_testCtx.getLog() << *program;
4605
4606                 if (!program->isOk())
4607                 {
4608                         // compile failed, assume static assert failed
4609                         result.fail("Shader build failed");
4610                         result.setTestContextResult(m_testCtx);
4611                         return STOP;
4612                 }
4613
4614                 m_testCtx.getLog() << tcu::TestLog::Message << "Build ok" << tcu::TestLog::EndMessage;
4615         }
4616
4617         result.setTestContextResult(m_testCtx);
4618         return STOP;
4619 }
4620
4621 class PrimitivesGeneratedQueryCase : public TestCase
4622 {
4623 public:
4624         enum QueryTest
4625         {
4626                 TEST_NO_GEOMETRY                        = 0,
4627                 TEST_NO_AMPLIFICATION,
4628                 TEST_AMPLIFICATION,
4629                 TEST_PARTIAL_PRIMITIVES,
4630                 TEST_INSTANCED,
4631
4632                 TEST_LAST
4633         };
4634
4635                                                 PrimitivesGeneratedQueryCase    (Context& context, const char* name, const char* description, QueryTest test);
4636                                                 ~PrimitivesGeneratedQueryCase   (void);
4637
4638 private:
4639         void                            init                                                    (void);
4640         void                            deinit                                                  (void);
4641         IterateResult           iterate                                                 (void);
4642
4643         glu::ShaderProgram*     genProgram                                              (void);
4644
4645         const QueryTest         m_test;
4646         glu::ShaderProgram*     m_program;
4647 };
4648
4649 PrimitivesGeneratedQueryCase::PrimitivesGeneratedQueryCase (Context& context, const char* name, const char* description, QueryTest test)
4650         : TestCase      (context, name, description)
4651         , m_test        (test)
4652         , m_program     (DE_NULL)
4653 {
4654         DE_ASSERT(m_test < TEST_LAST);
4655 }
4656
4657 PrimitivesGeneratedQueryCase::~PrimitivesGeneratedQueryCase (void)
4658 {
4659         deinit();
4660 }
4661
4662 void PrimitivesGeneratedQueryCase::init (void)
4663 {
4664         // requirements
4665
4666         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4667                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4668
4669         // log what test tries to do
4670
4671         if (m_test == TEST_NO_GEOMETRY)
4672                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering without a geometry shader." << tcu::TestLog::EndMessage;
4673         else if (m_test == TEST_NO_AMPLIFICATION)
4674                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a non-amplifying geometry shader." << tcu::TestLog::EndMessage;
4675         else if (m_test == TEST_AMPLIFICATION)
4676                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a (3x) amplifying geometry shader." << tcu::TestLog::EndMessage;
4677         else if (m_test == TEST_PARTIAL_PRIMITIVES)
4678                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a geometry shader that emits also partial primitives." << tcu::TestLog::EndMessage;
4679         else if (m_test == TEST_INSTANCED)
4680                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a instanced geometry shader." << tcu::TestLog::EndMessage;
4681         else
4682                 DE_ASSERT(false);
4683
4684         // resources
4685
4686         m_program = genProgram();
4687         m_testCtx.getLog() << *m_program;
4688
4689         if (!m_program->isOk())
4690                 throw tcu::TestError("could not build program");
4691 }
4692
4693 void PrimitivesGeneratedQueryCase::deinit (void)
4694 {
4695         delete m_program;
4696         m_program = DE_NULL;
4697 }
4698
4699 PrimitivesGeneratedQueryCase::IterateResult PrimitivesGeneratedQueryCase::iterate (void)
4700 {
4701         glw::GLuint primitivesGenerated = 0xDEBADBAD;
4702
4703         m_testCtx.getLog()
4704                 << tcu::TestLog::Message
4705                 << "Drawing 8 points, setting a_one for each to value (1.0, 1.0, 1.0, 1.0)"
4706                 << tcu::TestLog::EndMessage;
4707
4708         {
4709                 static const tcu::Vec4 vertexData[8*2] =
4710                 {
4711                         tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4712                         tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4713                         tcu::Vec4(0.2f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4714                         tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4715                         tcu::Vec4(0.4f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4716                         tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4717                         tcu::Vec4(0.6f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4718                         tcu::Vec4(0.7f, 0.0f, 0.0f, 1.0f),      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4719                 };
4720
4721                 const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
4722                 const glu::VertexArray  vao                                     (m_context.getRenderContext());
4723                 const glu::Buffer               buffer                          (m_context.getRenderContext());
4724                 const glu::Query                query                           (m_context.getRenderContext());
4725                 const int                               positionLocation        = gl.getAttribLocation(m_program->getProgram(), "a_position");
4726                 const int                               oneLocation                     = gl.getAttribLocation(m_program->getProgram(), "a_one");
4727
4728                 gl.bindVertexArray(*vao);
4729
4730                 gl.bindBuffer(GL_ARRAY_BUFFER, *buffer);
4731                 gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(vertexData), vertexData, GL_STATIC_DRAW);
4732
4733                 gl.vertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 2 * (int)sizeof(tcu::Vec4), DE_NULL);
4734                 gl.enableVertexAttribArray(positionLocation);
4735
4736                 if (oneLocation != -1)
4737                 {
4738                         gl.vertexAttribPointer(oneLocation, 4, GL_FLOAT, GL_FALSE, 2 * (int)sizeof(tcu::Vec4), (const tcu::Vec4*)DE_NULL + 1);
4739                         gl.enableVertexAttribArray(oneLocation);
4740                 }
4741
4742                 gl.useProgram(m_program->getProgram());
4743
4744                 GLU_EXPECT_NO_ERROR(gl.getError(), "setup render");
4745
4746                 gl.beginQuery(GL_PRIMITIVES_GENERATED, *query);
4747                 gl.drawArrays(GL_POINTS, 0, 8);
4748                 gl.endQuery(GL_PRIMITIVES_GENERATED);
4749
4750                 GLU_EXPECT_NO_ERROR(gl.getError(), "render and query");
4751
4752                 gl.getQueryObjectuiv(*query, GL_QUERY_RESULT, &primitivesGenerated);
4753                 GLU_EXPECT_NO_ERROR(gl.getError(), "get query result");
4754         }
4755
4756         m_testCtx.getLog()
4757                 << tcu::TestLog::Message
4758                 << "GL_PRIMITIVES_GENERATED = " << primitivesGenerated
4759                 << tcu::TestLog::EndMessage;
4760
4761         {
4762                 const deUint32 expectedGenerated = (m_test == TEST_AMPLIFICATION) ? (3*8) : (m_test == TEST_INSTANCED) ? (8*(3+1)) : (8);
4763
4764                 if (expectedGenerated == primitivesGenerated)
4765                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4766                 else
4767                 {
4768                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong result for GL_PRIMITIVES_GENERATED");
4769                         m_testCtx.getLog()
4770                                 << tcu::TestLog::Message
4771                                 << "Got unexpected result for GL_PRIMITIVES_GENERATED. Expected " << expectedGenerated << ", got " << primitivesGenerated
4772                                 << tcu::TestLog::EndMessage;
4773                 }
4774         }
4775
4776         return STOP;
4777 }
4778
4779 glu::ShaderProgram* PrimitivesGeneratedQueryCase::genProgram (void)
4780 {
4781         static const char* const vertexSource =         "${GLSL_VERSION_DECL}\n"
4782                                                                                                 "in highp vec4 a_position;\n"
4783                                                                                                 "in highp vec4 a_one;\n"
4784                                                                                                 "out highp vec4 v_one;\n"
4785                                                                                                 "void main (void)\n"
4786                                                                                                 "{\n"
4787                                                                                                 "       gl_Position = a_position;\n"
4788                                                                                                 "       v_one = a_one;\n"
4789                                                                                                 "}\n";
4790         static const char* const fragmentSource =       "${GLSL_VERSION_DECL}\n"
4791                                                                                                 "layout(location = 0) out mediump vec4 fragColor;\n"
4792                                                                                                 "void main (void)\n"
4793                                                                                                 "{\n"
4794                                                                                                 "       fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
4795                                                                                                 "}\n";
4796         std::ostringstream geometrySource;
4797         glu::ProgramSources sources;
4798
4799         if (m_test != TEST_NO_GEOMETRY)
4800         {
4801                 geometrySource <<       "${GLSL_VERSION_DECL}\n"
4802                                                         "${GLSL_EXT_GEOMETRY_SHADER}"
4803                                                         "layout(points" << ((m_test == TEST_INSTANCED) ? (", invocations = 3") : ("")) << ") in;\n"
4804                                                         "layout(triangle_strip, max_vertices = 7) out;\n"
4805                                                         "in highp vec4 v_one[];\n"
4806                                                         "void main (void)\n"
4807                                                         "{\n"
4808                                                         "       // always taken\n"
4809                                                         "       if (v_one[0].x != 0.0)\n"
4810                                                         "       {\n"
4811                                                         "               gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4812                                                         "               EmitVertex();\n"
4813                                                         "               gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4814                                                         "               EmitVertex();\n"
4815                                                         "               gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4816                                                         "               EmitVertex();\n"
4817                                                         "               EndPrimitive();\n"
4818                                                         "       }\n";
4819
4820                 if (m_test == TEST_AMPLIFICATION)
4821                 {
4822                         geometrySource <<       "\n"
4823                                                                 "       // always taken\n"
4824                                                                 "       if (v_one[0].y != 0.0)\n"
4825                                                                 "       {\n"
4826                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4827                                                                 "               EmitVertex();\n"
4828                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4829                                                                 "               EmitVertex();\n"
4830                                                                 "               gl_Position = gl_in[0].gl_Position - vec4(0.0, 0.1, 0.0, 0.0);\n"
4831                                                                 "               EmitVertex();\n"
4832                                                                 "               gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4833                                                                 "               EmitVertex();\n"
4834                                                                 "       }\n";
4835                 }
4836                 else if (m_test == TEST_PARTIAL_PRIMITIVES)
4837                 {
4838                         geometrySource <<       "\n"
4839                                                                 "       // always taken\n"
4840                                                                 "       if (v_one[0].y != 0.0)\n"
4841                                                                 "       {\n"
4842                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4843                                                                 "               EmitVertex();\n"
4844                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4845                                                                 "               EmitVertex();\n"
4846                                                                 "\n"
4847                                                                 "               // never taken\n"
4848                                                                 "               if (v_one[0].z < 0.0)\n"
4849                                                                 "               {\n"
4850                                                                 "                       gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4851                                                                 "                       EmitVertex();\n"
4852                                                                 "               }\n"
4853                                                                 "       }\n";
4854                 }
4855                 else if (m_test == TEST_INSTANCED)
4856                 {
4857                         geometrySource <<       "\n"
4858                                                                 "       // taken once\n"
4859                                                                 "       if (v_one[0].y > float(gl_InvocationID) + 0.5)\n"
4860                                                                 "       {\n"
4861                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4862                                                                 "               EmitVertex();\n"
4863                                                                 "               gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4864                                                                 "               EmitVertex();\n"
4865                                                                 "               gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4866                                                                 "               EmitVertex();\n"
4867                                                                 "       }\n";
4868                 }
4869
4870                 geometrySource <<       "}\n";
4871         }
4872
4873         sources << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()));
4874         sources << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()));
4875
4876         if (!geometrySource.str().empty())
4877                 sources << glu::GeometrySource(specializeShader(geometrySource.str(), m_context.getRenderContext().getType()));
4878
4879         return new glu::ShaderProgram(m_context.getRenderContext(), sources);
4880 }
4881
4882 class PrimitivesGeneratedQueryObjectQueryCase : public TestCase
4883 {
4884 public:
4885                                         PrimitivesGeneratedQueryObjectQueryCase (Context& context, const char* name, const char* description);
4886
4887         void                    init                                                                    (void);
4888         IterateResult   iterate                                                                 (void);
4889 };
4890
4891 PrimitivesGeneratedQueryObjectQueryCase::PrimitivesGeneratedQueryObjectQueryCase (Context& context, const char* name, const char* description)
4892         : TestCase(context, name, description)
4893 {
4894 }
4895
4896 void PrimitivesGeneratedQueryObjectQueryCase::init (void)
4897 {
4898         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4899                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4900 }
4901
4902 PrimitivesGeneratedQueryObjectQueryCase::IterateResult PrimitivesGeneratedQueryObjectQueryCase::iterate (void)
4903 {
4904         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4905         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
4906
4907         gl.enableLogging(true);
4908
4909         {
4910                 glw::GLuint query = 0;
4911
4912                 verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, 0, QUERY_QUERY);
4913
4914                 gl.glGenQueries(1, &query);
4915                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGenQueries");
4916
4917                 gl.glBeginQuery(GL_PRIMITIVES_GENERATED, query);
4918                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "beginQuery");
4919
4920                 verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, (int)query, QUERY_QUERY);
4921
4922                 gl.glEndQuery(GL_PRIMITIVES_GENERATED);
4923                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "endQuery");
4924         }
4925
4926         result.setTestContextResult(m_testCtx);
4927         return STOP;
4928 }
4929
4930 class GeometryShaderFeartureTestCase : public TestCase
4931 {
4932 public:
4933                                         GeometryShaderFeartureTestCase  (Context& context, const char* name, const char* description);
4934
4935         void                    init                                                    (void);
4936 };
4937
4938 GeometryShaderFeartureTestCase::GeometryShaderFeartureTestCase (Context& context, const char* name, const char* description)
4939         : TestCase(context, name, description)
4940 {
4941 }
4942
4943 void GeometryShaderFeartureTestCase::init (void)
4944 {
4945         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4946                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4947 }
4948
4949 class FramebufferDefaultLayersCase : public GeometryShaderFeartureTestCase
4950 {
4951 public:
4952                                         FramebufferDefaultLayersCase    (Context& context, const char* name, const char* description);
4953         IterateResult   iterate                                                 (void);
4954 };
4955
4956 FramebufferDefaultLayersCase::FramebufferDefaultLayersCase (Context& context, const char* name, const char* description)
4957         : GeometryShaderFeartureTestCase(context, name, description)
4958 {
4959 }
4960
4961 FramebufferDefaultLayersCase::IterateResult FramebufferDefaultLayersCase::iterate (void)
4962 {
4963         glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4964
4965         gl.enableLogging(true);
4966
4967         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4968
4969         {
4970                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "Default", "Default value");
4971                 const glu::Framebuffer          fbo                             (m_context.getRenderContext());
4972                 glw::GLint                                      defaultLayers   = -1;
4973
4974                 gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
4975                 gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
4976                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
4977
4978                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers << tcu::TestLog::EndMessage;
4979
4980                 if (defaultLayers != 0)
4981                 {
4982                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 0, got " << defaultLayers << tcu::TestLog::EndMessage;
4983                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
4984                 }
4985         }
4986
4987         {
4988                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "SetTo12", "Set default layers to 12");
4989                 const glu::Framebuffer          fbo                             (m_context.getRenderContext());
4990                 glw::GLint                                      defaultLayers   = -1;
4991
4992                 gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
4993                 gl.glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 12);
4994                 gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
4995                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
4996
4997                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers << tcu::TestLog::EndMessage;
4998
4999                 if (defaultLayers != 12)
5000                 {
5001                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 12, got " << defaultLayers << tcu::TestLog::EndMessage;
5002                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5003                 }
5004         }
5005
5006         return STOP;
5007 }
5008
5009 class FramebufferAttachmentLayeredCase : public GeometryShaderFeartureTestCase
5010 {
5011 public:
5012                                         FramebufferAttachmentLayeredCase        (Context& context, const char* name, const char* description);
5013         IterateResult   iterate                                                         (void);
5014 };
5015
5016 FramebufferAttachmentLayeredCase::FramebufferAttachmentLayeredCase (Context& context, const char* name, const char* description)
5017         : GeometryShaderFeartureTestCase(context, name, description)
5018 {
5019 }
5020
5021 FramebufferAttachmentLayeredCase::IterateResult FramebufferAttachmentLayeredCase::iterate (void)
5022 {
5023         enum CaseType
5024         {
5025                 TEXTURE_3D,
5026                 TEXTURE_2D_ARRAY,
5027                 TEXTURE_CUBE,
5028                 TEXTURE_2D_MS_ARRAY,
5029                 TEXTURE_3D_LAYER,
5030                 TEXTURE_2D_ARRAY_LAYER,
5031         };
5032
5033         static const struct TextureType
5034         {
5035                 const char*     name;
5036                 const char*     description;
5037                 bool            layered;
5038                 CaseType        type;
5039         } textureTypes[] =
5040         {
5041                 { "3D",                         "3D texture",                   true,   TEXTURE_3D                              },
5042                 { "2DArray",            "2D array",                             true,   TEXTURE_2D_ARRAY                },
5043                 { "Cube",                       "Cube map",                             true,   TEXTURE_CUBE                    },
5044                 { "2DMSArray",          "2D multisample array", true,   TEXTURE_2D_MS_ARRAY             },
5045                 { "3DLayer",            "3D texture layer ",    false,  TEXTURE_3D_LAYER                },
5046                 { "2DArrayLayer",       "2D array layer ",              false,  TEXTURE_2D_ARRAY_LAYER  },
5047         };
5048
5049         glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5050         gl.enableLogging(true);
5051
5052         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5053
5054         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(textureTypes); ++ndx)
5055         {
5056                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), textureTypes[ndx].name, textureTypes[ndx].description);
5057                 const glu::Framebuffer          fbo                             (m_context.getRenderContext());
5058                 const glu::Texture                      texture                 (m_context.getRenderContext());
5059                 glw::GLint                                      layered                 = -1;
5060
5061                 gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5062
5063                 if (textureTypes[ndx].type == TEXTURE_3D || textureTypes[ndx].type == TEXTURE_3D_LAYER)
5064                 {
5065                         gl.glBindTexture(GL_TEXTURE_3D, *texture);
5066                         gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5067                         gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5068                         gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5069
5070                         if (textureTypes[ndx].type == TEXTURE_3D)
5071                                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5072                         else
5073                                 gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 2);
5074                 }
5075                 else if (textureTypes[ndx].type == TEXTURE_2D_ARRAY || textureTypes[ndx].type == TEXTURE_2D_ARRAY_LAYER)
5076                 {
5077                         gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture);
5078                         gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5079                         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5080                         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5081
5082                         if (textureTypes[ndx].type == TEXTURE_2D_ARRAY)
5083                                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5084                         else
5085                                 gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 3);
5086                 }
5087                 else if (textureTypes[ndx].type == TEXTURE_CUBE)
5088                 {
5089                         gl.glBindTexture(GL_TEXTURE_CUBE_MAP, *texture);
5090                         for (int face = 0; face < 6; ++face)
5091                                 gl.glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA8, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5092                         gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5093                         gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5094                         gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5095                 }
5096                 else if (textureTypes[ndx].type == TEXTURE_2D_MS_ARRAY)
5097                 {
5098                         // check extension
5099                         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
5100                         {
5101                                 m_testCtx.getLog() << tcu::TestLog::Message << "Context is not equal or greather than 3.2 and GL_OES_texture_storage_multisample_2d_array not supported, skipping." << tcu::TestLog::EndMessage;
5102                                 continue;
5103                         }
5104
5105                         gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, *texture);
5106                         gl.glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 1, GL_RGBA8, 32, 32, 32, GL_FALSE);
5107                         gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5108                 }
5109
5110                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attachment");
5111
5112                 gl.glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered);
5113                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
5114
5115                 m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_ATTACHMENT_LAYERED = " << glu::getBooleanStr(layered) << tcu::TestLog::EndMessage;
5116
5117                 if (layered != GL_TRUE && layered != GL_FALSE)
5118                 {
5119                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected boolean, got " << layered << tcu::TestLog::EndMessage;
5120                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid boolean");
5121                 }
5122                 else if ((layered == GL_TRUE) != textureTypes[ndx].layered)
5123                 {
5124                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected " << ((textureTypes[ndx].layered) ? ("GL_TRUE") : ("GL_FALSE")) << ", got " << glu::getBooleanStr(layered) << tcu::TestLog::EndMessage;
5125                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5126                 }
5127         }
5128
5129         return STOP;
5130 }
5131
5132 class FramebufferIncompleteLayereTargetsCase : public GeometryShaderFeartureTestCase
5133 {
5134 public:
5135                                         FramebufferIncompleteLayereTargetsCase  (Context& context, const char* name, const char* description);
5136         IterateResult   iterate                                                                 (void);
5137 };
5138
5139 FramebufferIncompleteLayereTargetsCase::FramebufferIncompleteLayereTargetsCase (Context& context, const char* name, const char* description)
5140         : GeometryShaderFeartureTestCase(context, name, description)
5141 {
5142 }
5143
5144 FramebufferIncompleteLayereTargetsCase::IterateResult FramebufferIncompleteLayereTargetsCase::iterate (void)
5145 {
5146         glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5147         gl.enableLogging(true);
5148
5149         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5150
5151         {
5152                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "LayerAndNonLayer", "Layered and non-layered");
5153                 const glu::Framebuffer          fbo                             (m_context.getRenderContext());
5154                 const glu::Texture                      texture0                (m_context.getRenderContext());
5155                 const glu::Texture                      texture1                (m_context.getRenderContext());
5156
5157                 glw::GLint                                      fboStatus;
5158
5159                 gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5160                 gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5161                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5162                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5163
5164                 gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture1);
5165                 gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5166                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5167                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5168
5169                 gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5170                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5171                 gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0, 0);
5172
5173                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5174
5175                 fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5176                 m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5177
5178                 if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5179                 {
5180                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5181                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5182                 }
5183         }
5184
5185         {
5186                 const tcu::ScopedLogSection section                     (m_testCtx.getLog(), "DifferentTarget", "Different target");
5187                 const glu::Framebuffer          fbo                             (m_context.getRenderContext());
5188                 const glu::Texture                      texture0                (m_context.getRenderContext());
5189                 const glu::Texture                      texture1                (m_context.getRenderContext());
5190
5191                 glw::GLint                                      fboStatus;
5192
5193                 gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5194                 gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5195                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5196                 gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5197
5198                 gl.glBindTexture(GL_TEXTURE_3D, *texture1);
5199                 gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5200                 gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5201                 gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5202
5203                 gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5204                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5205                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0);
5206
5207                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5208
5209                 fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5210                 m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5211
5212                 if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5213                 {
5214                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5215                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5216                 }
5217         }
5218
5219         return STOP;
5220 }
5221
5222 class ReferencedByGeometryShaderCase : public GeometryShaderFeartureTestCase
5223 {
5224 public:
5225                                         ReferencedByGeometryShaderCase  (Context& context, const char* name, const char* description);
5226         IterateResult   iterate                                                 (void);
5227 };
5228
5229 ReferencedByGeometryShaderCase::ReferencedByGeometryShaderCase (Context& context, const char* name, const char* description)
5230         : GeometryShaderFeartureTestCase(context, name, description)
5231 {
5232 }
5233
5234 ReferencedByGeometryShaderCase::IterateResult ReferencedByGeometryShaderCase::iterate (void)
5235 {
5236         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5237
5238         {
5239                 static const char* const vertexSource =         "${GLSL_VERSION_DECL}\n"
5240                                                                                                         "uniform highp vec4 u_position;\n"
5241                                                                                                         "void main (void)\n"
5242                                                                                                         "{\n"
5243                                                                                                         "       gl_Position = u_position;\n"
5244                                                                                                         "}\n";
5245                 static const char* const fragmentSource =       "${GLSL_VERSION_DECL}\n"
5246                                                                                                         "layout(location = 0) out mediump vec4 fragColor;\n"
5247                                                                                                         "void main (void)\n"
5248                                                                                                         "{\n"
5249                                                                                                         "       fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
5250                                                                                                         "}\n";
5251                 static const char* const geometrySource =       "${GLSL_VERSION_DECL}\n"
5252                                                                                                         "${GLSL_EXT_GEOMETRY_SHADER}"
5253                                                                                                         "layout(points) in;\n"
5254                                                                                                         "layout(points, max_vertices=1) out;\n"
5255                                                                                                         "uniform highp vec4 u_offset;\n"
5256                                                                                                         "void main (void)\n"
5257                                                                                                         "{\n"
5258                                                                                                         "       gl_Position = gl_in[0].gl_Position + u_offset;\n"
5259                                                                                                         "       EmitVertex();\n"
5260                                                                                                         "}\n";
5261
5262                 const glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
5263                                                                                                                                                 << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()))
5264                                                                                                                                                 << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()))
5265                                                                                                                                                 << glu::GeometrySource(specializeShader(geometrySource, m_context.getRenderContext().getType())));
5266                 m_testCtx.getLog() << program;
5267
5268                 {
5269                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "UnreferencedUniform", "Unreferenced uniform u_position");
5270                         glu::CallLogWrapper                     gl                      (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5271                         const deUint32                          props[1]        = { GL_REFERENCED_BY_GEOMETRY_SHADER };
5272                         deUint32                                        resourcePos;
5273                         glw::GLsizei                            length          = 0;
5274                         glw::GLint                                      referenced      = 0;
5275
5276                         gl.enableLogging(true);
5277
5278                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_position");
5279                         m_testCtx.getLog() << tcu::TestLog::Message << "u_position resource index: " << resourcePos << tcu::TestLog::EndMessage;
5280
5281                         gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
5282                         m_testCtx.getLog() << tcu::TestLog::Message << "Query GL_REFERENCED_BY_GEOMETRY_SHADER, got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced) << tcu::TestLog::EndMessage;
5283
5284                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
5285
5286                         if (length == 0 || referenced != GL_FALSE)
5287                         {
5288                                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FALSE." << tcu::TestLog::EndMessage;
5289                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected value");
5290                         }
5291                 }
5292
5293                 {
5294                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_offset");
5295                         glu::CallLogWrapper                     gl                      (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5296                         const deUint32                          props[1]        = { GL_REFERENCED_BY_GEOMETRY_SHADER };
5297                         deUint32                                        resourcePos;
5298                         glw::GLsizei                            length          = 0;
5299                         glw::GLint                                      referenced      = 0;
5300
5301                         gl.enableLogging(true);
5302
5303                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_offset");
5304                         m_testCtx.getLog() << tcu::TestLog::Message << "u_offset resource index: " << resourcePos << tcu::TestLog::EndMessage;
5305
5306                         gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
5307                         m_testCtx.getLog() << tcu::TestLog::Message << "Query GL_REFERENCED_BY_GEOMETRY_SHADER, got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced) << tcu::TestLog::EndMessage;
5308
5309                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
5310
5311                         if (length == 0 || referenced != GL_TRUE)
5312                         {
5313                                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_TRUE." << tcu::TestLog::EndMessage;
5314                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected value");
5315                         }
5316                 }
5317         }
5318
5319         return STOP;
5320 }
5321
5322 class CombinedGeometryUniformLimitCase : public GeometryShaderFeartureTestCase
5323 {
5324 public:
5325                                                 CombinedGeometryUniformLimitCase        (Context& context, const char* name, const char* desc);
5326 private:
5327         IterateResult           iterate                                                         (void);
5328 };
5329
5330 CombinedGeometryUniformLimitCase::CombinedGeometryUniformLimitCase (Context& context, const char* name, const char* desc)
5331         : GeometryShaderFeartureTestCase(context, name, desc)
5332 {
5333 }
5334
5335 CombinedGeometryUniformLimitCase::IterateResult CombinedGeometryUniformLimitCase::iterate (void)
5336 {
5337         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5338         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
5339
5340         gl.enableLogging(true);
5341
5342         m_testCtx.getLog()      << tcu::TestLog::Message
5343                                                 << "The minimum value of MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS is MAX_GEOMETRY_UNIFORM_BLOCKS x MAX_UNIFORM_BLOCK_SIZE / 4 + MAX_GEOMETRY_UNIFORM_COMPONENTS"
5344                                                 << tcu::TestLog::EndMessage;
5345
5346         StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
5347         gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &maxUniformBlocks);
5348         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5349
5350         StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
5351         gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
5352         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5353
5354         StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
5355         gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, &maxUniformComponents);
5356         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5357
5358         if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) && maxUniformComponents.verifyValidity(result))
5359         {
5360                 const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
5361                 verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER);
5362
5363                 {
5364                         const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
5365                         verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_BOOLEAN);
5366                         verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER64);
5367                         verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_FLOAT);
5368                 }
5369         }
5370
5371         result.setTestContextResult(m_testCtx);
5372         return STOP;
5373 }
5374
5375 class VertexFeedbackCase : public TestCase
5376 {
5377 public:
5378         enum DrawMethod
5379         {
5380                 METHOD_DRAW_ARRAYS = 0,
5381                 METHOD_DRAW_ARRAYS_INSTANCED,
5382                 METHOD_DRAW_ARRAYS_INDIRECT,
5383                 METHOD_DRAW_ELEMENTS,
5384                 METHOD_DRAW_ELEMENTS_INSTANCED,
5385                 METHOD_DRAW_ELEMENTS_INDIRECT,
5386
5387                 METHOD_LAST
5388         };
5389         enum PrimitiveType
5390         {
5391                 PRIMITIVE_LINE_LOOP = 0,
5392                 PRIMITIVE_LINE_STRIP,
5393                 PRIMITIVE_TRIANGLE_STRIP,
5394                 PRIMITIVE_TRIANGLE_FAN,
5395                 PRIMITIVE_POINTS,
5396
5397                 PRIMITIVE_LAST
5398         };
5399
5400                                                 VertexFeedbackCase      (Context& context, const char* name, const char* description, DrawMethod method, PrimitiveType output);
5401                                                 ~VertexFeedbackCase     (void);
5402 private:
5403         void                            init                            (void);
5404         void                            deinit                          (void);
5405         IterateResult           iterate                         (void);
5406
5407         glu::ShaderProgram*     genProgram                      (void);
5408         deUint32                        getOutputPrimitive      (void);
5409         deUint32                        getBasePrimitive        (void);
5410
5411         const DrawMethod        m_method;
5412         const PrimitiveType     m_output;
5413
5414         deUint32                        m_elementBuf;
5415         deUint32                        m_arrayBuf;
5416         deUint32                        m_offsetBuf;
5417         deUint32                        m_feedbackBuf;
5418         deUint32                        m_indirectBuffer;
5419         glu::ShaderProgram*     m_program;
5420         glu::VertexArray*       m_vao;
5421 };
5422
5423 VertexFeedbackCase::VertexFeedbackCase (Context& context, const char* name, const char* description, DrawMethod method, PrimitiveType output)
5424         : TestCase                      (context, name, description)
5425         , m_method                      (method)
5426         , m_output                      (output)
5427         , m_elementBuf          (0)
5428         , m_arrayBuf            (0)
5429         , m_offsetBuf           (0)
5430         , m_feedbackBuf         (0)
5431         , m_indirectBuffer      (0)
5432         , m_program                     (DE_NULL)
5433         , m_vao                         (DE_NULL)
5434 {
5435         DE_ASSERT(method < METHOD_LAST);
5436         DE_ASSERT(output < PRIMITIVE_LAST);
5437 }
5438
5439 VertexFeedbackCase::~VertexFeedbackCase (void)
5440 {
5441         deinit();
5442 }
5443
5444 void VertexFeedbackCase::init (void)
5445 {
5446         // requirements
5447
5448         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
5449                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5450
5451         // log what test tries to do
5452
5453         m_testCtx.getLog()
5454                 << tcu::TestLog::Message
5455                 << "Testing GL_EXT_geometry_shader transform feedback relaxations.\n"
5456                 << "Capturing vertex shader varying, no geometry shader. Invoke with:"
5457                 << tcu::TestLog::EndMessage;
5458
5459         switch (m_method)
5460         {
5461                 case METHOD_DRAW_ARRAYS:                                m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArrays"                        << tcu::TestLog::EndMessage;    break;
5462                 case METHOD_DRAW_ARRAYS_INSTANCED:              m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysInstanced"       << tcu::TestLog::EndMessage;    break;
5463                 case METHOD_DRAW_ARRAYS_INDIRECT:               m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysIndirect"        << tcu::TestLog::EndMessage;    break;
5464                 case METHOD_DRAW_ELEMENTS:                              m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElements"                      << tcu::TestLog::EndMessage;    break;
5465                 case METHOD_DRAW_ELEMENTS_INSTANCED:    m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsInstanced" << tcu::TestLog::EndMessage;        break;
5466                 case METHOD_DRAW_ELEMENTS_INDIRECT:             m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsIndirect"      << tcu::TestLog::EndMessage;    break;
5467                 default:
5468                         DE_ASSERT(false);
5469         }
5470         switch (m_output)
5471         {
5472                 case PRIMITIVE_LINE_LOOP:                               m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line loop"                      << tcu::TestLog::EndMessage;    break;
5473                 case PRIMITIVE_LINE_STRIP:                              m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line strip"                     << tcu::TestLog::EndMessage;    break;
5474                 case PRIMITIVE_TRIANGLE_STRIP:                  m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle strip"         << tcu::TestLog::EndMessage;    break;
5475                 case PRIMITIVE_TRIANGLE_FAN:                    m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle fan"           << tcu::TestLog::EndMessage;    break;
5476                 case PRIMITIVE_POINTS:                                  m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: points"                         << tcu::TestLog::EndMessage;    break;
5477                 default:
5478                         DE_ASSERT(false);
5479         }
5480
5481         // resources
5482
5483         {
5484                 static const deUint16 elementData[] =
5485                 {
5486                         0, 1, 2, 3,
5487                 };
5488                 static const tcu::Vec4 arrayData[] =
5489                 {
5490                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5491                         tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
5492                         tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f),
5493                         tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f),
5494                 };
5495                 static const tcu::Vec4 offsetData[] =
5496                 {
5497                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5498                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5499                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5500                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5501                 };
5502
5503                 const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
5504                 const int                               feedbackSize    = 8 * (int)sizeof(float[4]);
5505
5506                 m_vao = new glu::VertexArray(m_context.getRenderContext());
5507                 gl.bindVertexArray(**m_vao);
5508                 GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
5509
5510                 gl.genBuffers(1, &m_elementBuf);
5511                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5512                 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
5513                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5514
5515                 gl.genBuffers(1, &m_arrayBuf);
5516                 gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5517                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
5518                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5519
5520                 gl.genBuffers(1, &m_offsetBuf);
5521                 gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
5522                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(offsetData), &offsetData[0], GL_STATIC_DRAW);
5523                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5524
5525                 gl.genBuffers(1, &m_feedbackBuf);
5526                 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
5527                 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackSize, DE_NULL, GL_DYNAMIC_COPY);
5528                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5529
5530                 m_program = genProgram();
5531
5532                 if (!m_program->isOk())
5533                 {
5534                         m_testCtx.getLog() << *m_program;
5535                         throw tcu::TestError("could not build program");
5536                 }
5537         }
5538 }
5539
5540 void VertexFeedbackCase::deinit (void)
5541 {
5542         if (m_elementBuf)
5543         {
5544                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
5545                 m_elementBuf = 0;
5546         }
5547
5548         if (m_arrayBuf)
5549         {
5550                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
5551                 m_arrayBuf = 0;
5552         }
5553
5554         if (m_offsetBuf)
5555         {
5556                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_offsetBuf);
5557                 m_offsetBuf = 0;
5558         }
5559
5560         if (m_feedbackBuf)
5561         {
5562                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
5563                 m_feedbackBuf = 0;
5564         }
5565
5566         if (m_indirectBuffer)
5567         {
5568                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indirectBuffer);
5569                 m_indirectBuffer = 0;
5570         }
5571
5572         delete m_program;
5573         m_program = DE_NULL;
5574
5575         delete m_vao;
5576         m_vao = DE_NULL;
5577 }
5578
5579 VertexFeedbackCase::IterateResult VertexFeedbackCase::iterate (void)
5580 {
5581         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
5582         const deUint32                  outputPrimitive = getOutputPrimitive();
5583         const deUint32                  basePrimitive   = getBasePrimitive();
5584
5585         const int                               posLocation             = gl.getAttribLocation(m_program->getProgram(), "a_position");
5586         const int                               offsetLocation  = gl.getAttribLocation(m_program->getProgram(), "a_offset");
5587
5588         if (posLocation == -1)
5589                 throw tcu::TestError("a_position location was -1");
5590         if (offsetLocation == -1)
5591                 throw tcu::TestError("a_offset location was -1");
5592
5593         gl.useProgram(m_program->getProgram());
5594
5595         gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5596         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5597         gl.enableVertexAttribArray(posLocation);
5598
5599         gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
5600         gl.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5601         gl.enableVertexAttribArray(offsetLocation);
5602
5603         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
5604         GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
5605
5606         m_testCtx.getLog() << tcu::TestLog::Message << "Calling BeginTransformFeedback(" << glu::getPrimitiveTypeStr(basePrimitive) << ")" << tcu::TestLog::EndMessage;
5607         gl.beginTransformFeedback(basePrimitive);
5608         GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
5609
5610         switch (m_method)
5611         {
5612                 case METHOD_DRAW_ARRAYS:
5613                 {
5614                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArrays(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5615                         gl.drawArrays(outputPrimitive, 0, 4);
5616                         break;
5617                 }
5618
5619                 case METHOD_DRAW_ARRAYS_INSTANCED:
5620                 {
5621                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArraysInstanced(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5622                         gl.vertexAttribDivisor(offsetLocation, 2);
5623                         gl.drawArraysInstanced(outputPrimitive, 0, 3, 2);
5624                         break;
5625                 }
5626
5627                 case METHOD_DRAW_ELEMENTS:
5628                 {
5629                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElements(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5630                         gl.drawElements(outputPrimitive, 4, GL_UNSIGNED_SHORT, DE_NULL);
5631                         break;
5632                 }
5633
5634                 case METHOD_DRAW_ELEMENTS_INSTANCED:
5635                 {
5636                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsInstanced(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5637                         gl.drawElementsInstanced(outputPrimitive, 3, GL_UNSIGNED_SHORT, DE_NULL, 2);
5638                         break;
5639                 }
5640
5641                 case METHOD_DRAW_ARRAYS_INDIRECT:
5642                 {
5643                         struct DrawArraysIndirectCommand
5644                         {
5645                                 deUint32 count;
5646                                 deUint32 instanceCount;
5647                                 deUint32 first;
5648                                 deUint32 reservedMustBeZero;
5649                         } params;
5650
5651                         DE_STATIC_ASSERT(sizeof(DrawArraysIndirectCommand) == sizeof(deUint32[4]));
5652
5653                         params.count = 4;
5654                         params.instanceCount = 1;
5655                         params.first = 0;
5656                         params.reservedMustBeZero = 0;
5657
5658                         gl.genBuffers(1, &m_indirectBuffer);
5659                         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
5660                         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
5661
5662                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5663                         gl.drawArraysIndirect(outputPrimitive, DE_NULL);
5664                         break;
5665                 }
5666
5667                 case METHOD_DRAW_ELEMENTS_INDIRECT:
5668                 {
5669                         struct DrawElementsIndirectCommand
5670                         {
5671                                 deUint32        count;
5672                                 deUint32        instanceCount;
5673                                 deUint32        firstIndex;
5674                                 deInt32         baseVertex;
5675                                 deUint32        reservedMustBeZero;
5676                         } params;
5677
5678                         DE_STATIC_ASSERT(sizeof(DrawElementsIndirectCommand) == sizeof(deUint32[5]));
5679
5680                         params.count = 4;
5681                         params.instanceCount = 1;
5682                         params.firstIndex = 0;
5683                         params.baseVertex = 0;
5684                         params.reservedMustBeZero = 0;
5685
5686                         gl.genBuffers(1, &m_indirectBuffer);
5687                         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
5688                         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
5689
5690                         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5691                         gl.drawElementsIndirect(outputPrimitive, GL_UNSIGNED_SHORT, DE_NULL);
5692                         break;
5693                 }
5694
5695                 default:
5696                         DE_ASSERT(false);
5697         }
5698         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
5699
5700         gl.endTransformFeedback();
5701         GLU_EXPECT_NO_ERROR(gl.getError(), "endTransformFeedback");
5702
5703         m_testCtx.getLog() << tcu::TestLog::Message << "No errors." << tcu::TestLog::EndMessage;
5704         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5705
5706         return STOP;
5707 }
5708
5709 glu::ShaderProgram* VertexFeedbackCase::genProgram (void)
5710 {
5711         static const char* const vertexSource =         "${GLSL_VERSION_DECL}\n"
5712                                                                                                 "in highp vec4 a_position;\n"
5713                                                                                                 "in highp vec4 a_offset;\n"
5714                                                                                                 "out highp vec4 tf_value;\n"
5715                                                                                                 "void main (void)\n"
5716                                                                                                 "{\n"
5717                                                                                                 "       gl_Position = a_position;\n"
5718                                                                                                 "       tf_value = a_position + a_offset;\n"
5719                                                                                                 "}\n";
5720         static const char* const fragmentSource =       "${GLSL_VERSION_DECL}\n"
5721                                                                                                 "layout(location = 0) out mediump vec4 fragColor;\n"
5722                                                                                                 "void main (void)\n"
5723                                                                                                 "{\n"
5724                                                                                                 "       fragColor = vec4(1.0);\n"
5725                                                                                                 "}\n";
5726
5727         return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5728                                                                                                                                 << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()))
5729                                                                                                                                 << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()))
5730                                                                                                                                 << glu::TransformFeedbackVarying("tf_value")
5731                                                                                                                                 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
5732 }
5733
5734 deUint32 VertexFeedbackCase::getOutputPrimitive (void)
5735 {
5736         switch(m_output)
5737         {
5738                 case PRIMITIVE_LINE_LOOP:               return GL_LINE_LOOP;
5739                 case PRIMITIVE_LINE_STRIP:              return GL_LINE_STRIP;
5740                 case PRIMITIVE_TRIANGLE_STRIP:  return GL_TRIANGLE_STRIP;
5741                 case PRIMITIVE_TRIANGLE_FAN:    return GL_TRIANGLE_FAN;
5742                 case PRIMITIVE_POINTS:                  return GL_POINTS;
5743                 default:
5744                         DE_ASSERT(false);
5745                         return 0;
5746         }
5747 }
5748
5749 deUint32 VertexFeedbackCase::getBasePrimitive (void)
5750 {
5751         switch(m_output)
5752         {
5753                 case PRIMITIVE_LINE_LOOP:               return GL_LINES;
5754                 case PRIMITIVE_LINE_STRIP:              return GL_LINES;
5755                 case PRIMITIVE_TRIANGLE_STRIP:  return GL_TRIANGLES;
5756                 case PRIMITIVE_TRIANGLE_FAN:    return GL_TRIANGLES;
5757                 case PRIMITIVE_POINTS:                  return GL_POINTS;
5758                 default:
5759                         DE_ASSERT(false);
5760                         return 0;
5761         }
5762 }
5763
5764 class VertexFeedbackOverflowCase : public TestCase
5765 {
5766 public:
5767         enum Method
5768         {
5769                 METHOD_DRAW_ARRAYS = 0,
5770                 METHOD_DRAW_ELEMENTS,
5771         };
5772
5773                                                 VertexFeedbackOverflowCase      (Context& context, const char* name, const char* description, Method method);
5774                                                 ~VertexFeedbackOverflowCase     (void);
5775
5776 private:
5777         void                            init                                            (void);
5778         void                            deinit                                          (void);
5779         IterateResult           iterate                                         (void);
5780         glu::ShaderProgram*     genProgram                                      (void);
5781
5782         const Method            m_method;
5783
5784         deUint32                        m_elementBuf;
5785         deUint32                        m_arrayBuf;
5786         deUint32                        m_feedbackBuf;
5787         glu::ShaderProgram*     m_program;
5788         glu::VertexArray*       m_vao;
5789 };
5790
5791 VertexFeedbackOverflowCase::VertexFeedbackOverflowCase (Context& context, const char* name, const char* description, Method method)
5792         : TestCase              (context, name, description)
5793         , m_method              (method)
5794         , m_elementBuf  (0)
5795         , m_arrayBuf    (0)
5796         , m_feedbackBuf (0)
5797         , m_program             (DE_NULL)
5798         , m_vao                 (DE_NULL)
5799 {
5800 }
5801
5802 VertexFeedbackOverflowCase::~VertexFeedbackOverflowCase (void)
5803 {
5804         deinit();
5805 }
5806
5807 void VertexFeedbackOverflowCase::init (void)
5808 {
5809         // requirements
5810
5811         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
5812                 TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5813
5814         // log what test tries to do
5815
5816         m_testCtx.getLog()
5817                 << tcu::TestLog::Message
5818                 << "Testing GL_EXT_geometry_shader transform feedback overflow behavior.\n"
5819                 << "Capturing vertex shader varying, rendering 2 triangles. Allocating feedback buffer for 5 vertices."
5820                 << tcu::TestLog::EndMessage;
5821
5822         // resources
5823
5824         {
5825                 static const deUint16   elementData[] =
5826                 {
5827                         0, 1, 2,
5828                         0, 1, 2,
5829                 };
5830                 static const tcu::Vec4  arrayData[] =
5831                 {
5832                         tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5833                         tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5834                         tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5835                         tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5836                 };
5837
5838                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
5839
5840                 m_vao = new glu::VertexArray(m_context.getRenderContext());
5841                 gl.bindVertexArray(**m_vao);
5842                 GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
5843
5844                 if (m_method == METHOD_DRAW_ELEMENTS)
5845                 {
5846                         gl.genBuffers(1, &m_elementBuf);
5847                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5848                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
5849                         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5850                 }
5851
5852                 gl.genBuffers(1, &m_arrayBuf);
5853                 gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5854                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
5855                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5856
5857                 {
5858                         const int                                       feedbackCount                   = 5 * 4; // 5x vec4
5859                         const std::vector<float>        initialBufferContents   (feedbackCount, -1.0f);
5860
5861                         m_testCtx.getLog() << tcu::TestLog::Message << "Filling feeback buffer with dummy value (-1.0)." << tcu::TestLog::EndMessage;
5862
5863                         gl.genBuffers(1, &m_feedbackBuf);
5864                         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
5865                         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(float) * initialBufferContents.size()), &initialBufferContents[0], GL_DYNAMIC_COPY);
5866                         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5867                 }
5868
5869                 m_program = genProgram();
5870
5871                 if (!m_program->isOk())
5872                 {
5873                         m_testCtx.getLog() << *m_program;
5874                         throw tcu::TestError("could not build program");
5875                 }
5876         }
5877 }
5878
5879 void VertexFeedbackOverflowCase::deinit (void)
5880 {
5881         if (m_elementBuf)
5882         {
5883                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
5884                 m_elementBuf = 0;
5885         }
5886
5887         if (m_arrayBuf)
5888         {
5889                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
5890                 m_arrayBuf = 0;
5891         }
5892
5893         if (m_feedbackBuf)
5894         {
5895                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
5896                 m_feedbackBuf = 0;
5897         }
5898
5899         delete m_program;
5900         m_program = DE_NULL;
5901
5902         delete m_vao;
5903         m_vao = DE_NULL;
5904 }
5905
5906 VertexFeedbackOverflowCase::IterateResult VertexFeedbackOverflowCase::iterate (void)
5907 {
5908         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
5909         const int                               posLocation             = gl.getAttribLocation(m_program->getProgram(), "a_position");
5910
5911         if (posLocation == -1)
5912                 throw tcu::TestError("a_position location was -1");
5913
5914         gl.useProgram(m_program->getProgram());
5915
5916         gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5917         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5918         gl.enableVertexAttribArray(posLocation);
5919
5920         if (m_method == METHOD_DRAW_ELEMENTS)
5921         {
5922                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5923                 GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
5924         }
5925
5926         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
5927         GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
5928
5929         m_testCtx.getLog() << tcu::TestLog::Message << "Capturing 2 triangles." << tcu::TestLog::EndMessage;
5930
5931         gl.beginTransformFeedback(GL_TRIANGLES);
5932
5933         if (m_method == METHOD_DRAW_ELEMENTS)
5934                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
5935         else if (m_method == METHOD_DRAW_ARRAYS)
5936                 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
5937         else
5938                 DE_ASSERT(false);
5939
5940         gl.endTransformFeedback();
5941         GLU_EXPECT_NO_ERROR(gl.getError(), "capture");
5942
5943         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying final triangle was not partially written to the feedback buffer." << tcu::TestLog::EndMessage;
5944
5945         {
5946                 const void*                             ptr             = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float[4]) * 5, GL_MAP_READ_BIT);
5947                 std::vector<float>              feedback;
5948                 bool                                    error   = false;
5949
5950                 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
5951                 if (!ptr)
5952                         throw tcu::TestError("mapBufferRange returned null");
5953
5954                 feedback.resize(5*4);
5955                 deMemcpy(&feedback[0], ptr, sizeof(float[4]) * 5);
5956
5957                 if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
5958                         throw tcu::TestError("unmapBuffer returned false");
5959
5960                 // Verify vertices 0 - 2
5961                 for (int vertex = 0; vertex < 3; ++vertex)
5962                 {
5963                         for (int component = 0; component < 4; ++component)
5964                         {
5965                                 if (feedback[vertex*4 + component] != 1.0f)
5966                                 {
5967                                         m_testCtx.getLog()
5968                                                 << tcu::TestLog::Message
5969                                                 << "Feedback buffer vertex " << vertex << ", component " << component << ": unexpected value, expected 1.0, got " << feedback[vertex*4 + component]
5970                                                 << tcu::TestLog::EndMessage;
5971                                         error = true;
5972                                 }
5973                         }
5974                 }
5975
5976                 // Verify vertices 3 - 4
5977                 for (int vertex = 3; vertex < 5; ++vertex)
5978                 {
5979                         for (int component = 0; component < 4; ++component)
5980                         {
5981                                 if (feedback[vertex*4 + component] != -1.0f)
5982                                 {
5983                                         m_testCtx.getLog()
5984                                                 << tcu::TestLog::Message
5985                                                 << "Feedback buffer vertex " << vertex << ", component " << component << ": unexpected value, expected -1.0, got " << feedback[vertex*4 + component]
5986                                                 << tcu::TestLog::EndMessage;
5987                                         error = true;
5988                                 }
5989                         }
5990                 }
5991
5992                 if (error)
5993                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Feedback result validation failed");
5994                 else
5995                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5996         }
5997
5998         return STOP;
5999 }
6000
6001 glu::ShaderProgram* VertexFeedbackOverflowCase::genProgram (void)
6002 {
6003         static const char* const vertexSource =         "${GLSL_VERSION_DECL}\n"
6004                                                                                                 "in highp vec4 a_position;\n"
6005                                                                                                 "void main (void)\n"
6006                                                                                                 "{\n"
6007                                                                                                 "       gl_Position = a_position;\n"
6008                                                                                                 "}\n";
6009         static const char* const fragmentSource =       "${GLSL_VERSION_DECL}\n"
6010                                                                                                 "layout(location = 0) out mediump vec4 fragColor;\n"
6011                                                                                                 "void main (void)\n"
6012                                                                                                 "{\n"
6013                                                                                                 "       fragColor = vec4(1.0);\n"
6014                                                                                                 "}\n";
6015
6016         return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6017                                                                                                                                 << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()))
6018                                                                                                                                 << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()))
6019                                                                                                                                 << glu::TransformFeedbackVarying("gl_Position")
6020                                                                                                                                 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
6021 }
6022
6023 } // anonymous
6024
6025 GeometryShaderTests::GeometryShaderTests (Context& context)
6026         : TestCaseGroup(context, "geometry_shading", "Geometry shader tests")
6027 {
6028 }
6029
6030 GeometryShaderTests::~GeometryShaderTests (void)
6031 {
6032 }
6033
6034 void GeometryShaderTests::init (void)
6035 {
6036         struct PrimitiveTestSpec
6037         {
6038                 deUint32        primitiveType;
6039                 const char* name;
6040                 deUint32        outputType;
6041         };
6042
6043         struct EmitTestSpec
6044         {
6045                 deUint32        outputType;
6046                 int                     emitCountA;             //!< primitive A emit count
6047                 int                     endCountA;              //!< primitive A end count
6048                 int                     emitCountB;             //!<
6049                 int                     endCountB;              //!<
6050                 const char* name;
6051         };
6052
6053         static const struct LayeredTarget
6054         {
6055                 LayeredRenderCase::LayeredRenderTargetType      target;
6056                 const char*                                                                     name;
6057                 const char*                                                                     desc;
6058         } layerTargets[] =
6059         {
6060                 { LayeredRenderCase::TARGET_CUBE,                       "cubemap",                              "cubemap"                                               },
6061                 { LayeredRenderCase::TARGET_3D,                         "3d",                                   "3D texture"                                    },
6062                 { LayeredRenderCase::TARGET_2D_ARRAY,           "2d_array",                             "2D array texture"                              },
6063                 { LayeredRenderCase::TARGET_2D_MS_ARRAY,        "2d_multisample_array", "2D multisample array texture"  },
6064         };
6065
6066         tcu::TestCaseGroup* const queryGroup                            = new tcu::TestCaseGroup(m_testCtx, "query", "Query tests.");
6067         tcu::TestCaseGroup* const basicGroup                            = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic tests.");
6068         tcu::TestCaseGroup* const inputPrimitiveGroup           = new tcu::TestCaseGroup(m_testCtx, "input", "Different input primitives.");
6069         tcu::TestCaseGroup* const conversionPrimitiveGroup      = new tcu::TestCaseGroup(m_testCtx, "conversion", "Different input and output primitives.");
6070         tcu::TestCaseGroup* const emitGroup                                     = new tcu::TestCaseGroup(m_testCtx, "emit", "Different emit counts.");
6071         tcu::TestCaseGroup* const varyingGroup                          = new tcu::TestCaseGroup(m_testCtx, "varying", "Test varyings.");
6072         tcu::TestCaseGroup* const layeredGroup                          = new tcu::TestCaseGroup(m_testCtx, "layered", "Layered rendering.");
6073         tcu::TestCaseGroup* const instancedGroup                        = new tcu::TestCaseGroup(m_testCtx, "instanced", "Instanced rendering.");
6074         tcu::TestCaseGroup* const negativeGroup                         = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests.");
6075         tcu::TestCaseGroup* const feedbackGroup                         = new tcu::TestCaseGroup(m_testCtx, "vertex_transform_feedback", "Transform feedback.");
6076
6077         this->addChild(queryGroup);
6078         this->addChild(basicGroup);
6079         this->addChild(inputPrimitiveGroup);
6080         this->addChild(conversionPrimitiveGroup);
6081         this->addChild(emitGroup);
6082         this->addChild(varyingGroup);
6083         this->addChild(layeredGroup);
6084         this->addChild(instancedGroup);
6085         this->addChild(negativeGroup);
6086         this->addChild(feedbackGroup);
6087
6088         // query test
6089         {
6090                 // limits with a corresponding glsl constant
6091                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_input_components",                           "", GL_MAX_GEOMETRY_INPUT_COMPONENTS,                           "MaxGeometryInputComponents",           64));
6092                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_components",                          "", GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,                          "MaxGeometryOutputComponents",          64));
6093                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_image_uniforms",                                     "", GL_MAX_GEOMETRY_IMAGE_UNIFORMS,                                     "MaxGeometryImageUniforms",                     0));
6094                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_texture_image_units",                        "", GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,                        "MaxGeometryTextureImageUnits",         16));
6095                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_vertices",                            "", GL_MAX_GEOMETRY_OUTPUT_VERTICES,                            "MaxGeometryOutputVertices",            256));
6096                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_total_output_components",            "", GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,            "MaxGeometryTotalOutputComponents",     1024));
6097                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_uniform_components",                         "", GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,                         "MaxGeometryUniformComponents",         1024));
6098                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counters",                            "", GL_MAX_GEOMETRY_ATOMIC_COUNTERS,                            "MaxGeometryAtomicCounters",            0));
6099                 queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counter_buffers",                     "", GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,                     "MaxGeometryAtomicCounterBuffers",      0));
6100
6101                 // program queries
6102                 queryGroup->addChild(new GeometryShaderVerticesQueryCase        (m_context, "geometry_linked_vertices_out",     "GL_GEOMETRY_LINKED_VERTICES_OUT"));
6103                 queryGroup->addChild(new GeometryShaderInputQueryCase           (m_context, "geometry_linked_input_type",       "GL_GEOMETRY_LINKED_INPUT_TYPE"));
6104                 queryGroup->addChild(new GeometryShaderOutputQueryCase          (m_context, "geometry_linked_output_type",      "GL_GEOMETRY_LINKED_OUTPUT_TYPE"));
6105                 queryGroup->addChild(new GeometryShaderInvocationsQueryCase     (m_context, "geometry_shader_invocations",      "GL_GEOMETRY_SHADER_INVOCATIONS"));
6106
6107                 // limits
6108                 queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_invocations",          "", GL_MAX_GEOMETRY_SHADER_INVOCATIONS,         32));
6109                 queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_uniform_blocks",                      "", GL_MAX_GEOMETRY_UNIFORM_BLOCKS,                     12));
6110                 queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_storage_blocks",       "", GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,      0));
6111
6112                 // layer_provoking_vertex_ext
6113                 queryGroup->addChild(new LayerProvokingVertexQueryCase(m_context, "layer_provoking_vertex", "GL_LAYER_PROVOKING_VERTEX"));
6114
6115                 // primitives_generated
6116                 queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_geometry",            "PRIMITIVES_GENERATED query with no geometry shader",                                                           PrimitivesGeneratedQueryCase::TEST_NO_GEOMETRY));
6117                 queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_amplification",       "PRIMITIVES_GENERATED query with non amplifying geometry shader",                                       PrimitivesGeneratedQueryCase::TEST_NO_AMPLIFICATION));
6118                 queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_amplification",          "PRIMITIVES_GENERATED query with amplifying geometry shader",                                           PrimitivesGeneratedQueryCase::TEST_AMPLIFICATION));
6119                 queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_partial_primitives", "PRIMITIVES_GENERATED query with geometry shader emitting partial primitives",              PrimitivesGeneratedQueryCase::TEST_PARTIAL_PRIMITIVES));
6120                 queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_instanced",                      "PRIMITIVES_GENERATED query with instanced geometry shader",                                            PrimitivesGeneratedQueryCase::TEST_INSTANCED));
6121
6122                 queryGroup->addChild(new PrimitivesGeneratedQueryObjectQueryCase(m_context, "primitives_generated", "Query bound PRIMITIVES_GENERATED query"));
6123
6124                 // fbo
6125                 queryGroup->addChild(new ImplementationLimitCase                                (m_context, "max_framebuffer_layers",                           "", GL_MAX_FRAMEBUFFER_LAYERS,  256));
6126                 queryGroup->addChild(new FramebufferDefaultLayersCase                   (m_context, "framebuffer_default_layers",                       ""));
6127                 queryGroup->addChild(new FramebufferAttachmentLayeredCase               (m_context, "framebuffer_attachment_layered",           ""));
6128                 queryGroup->addChild(new FramebufferIncompleteLayereTargetsCase (m_context, "framebuffer_incomplete_layer_targets",     ""));
6129
6130                 // resource query
6131                 queryGroup->addChild(new ReferencedByGeometryShaderCase                 (m_context, "referenced_by_geometry_shader",    ""));
6132
6133                 // combined limits
6134                 queryGroup->addChild(new CombinedGeometryUniformLimitCase               (m_context, "max_combined_geometry_uniform_components", "MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS"));
6135         }
6136
6137         // basic tests
6138         {
6139                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_10",                            "Output 10 vertices",                                                           OutputCountPatternSpec(10)));
6140                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_128",                           "Output 128 vertices",                                                          OutputCountPatternSpec(128)));
6141                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_256",                           "Output 256 vertices",                                                          OutputCountPatternSpec(256)));
6142                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_max",                           "Output max vertices",                                                          OutputCountPatternSpec(-1)));
6143                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_10_and_100",            "Output 10 and 100 vertices in two invocations",        OutputCountPatternSpec(10, 100)));
6144                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_100_and_10",            "Output 100 and 10 vertices in two invocations",        OutputCountPatternSpec(100, 10)));
6145                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_0_and_128",                     "Output 0 and 128 vertices in two invocations",         OutputCountPatternSpec(0, 128)));
6146                 basicGroup->addChild(new OutputCountCase                        (m_context,     "output_128_and_0",                     "Output 128 and 0 vertices in two invocations",         OutputCountPatternSpec(128, 0)));
6147
6148                 basicGroup->addChild(new VaryingOutputCountCase         (m_context,     "output_vary_by_attribute",     "Output varying number of vertices",                            VaryingOutputCountShader::READ_ATTRIBUTE,       VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6149                 basicGroup->addChild(new VaryingOutputCountCase         (m_context,     "output_vary_by_uniform",       "Output varying number of vertices",                            VaryingOutputCountShader::READ_UNIFORM,         VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6150                 basicGroup->addChild(new VaryingOutputCountCase         (m_context,     "output_vary_by_texture",       "Output varying number of vertices",                            VaryingOutputCountShader::READ_TEXTURE,         VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6151
6152                 basicGroup->addChild(new BuiltinVariableRenderTest      (m_context,     "point_size",                           "test gl_PointSize",                                                            BuiltinVariableShader::TEST_POINT_SIZE));
6153                 basicGroup->addChild(new BuiltinVariableRenderTest      (m_context,     "primitive_id_in",                      "test gl_PrimitiveIDIn",                                                        BuiltinVariableShader::TEST_PRIMITIVE_ID_IN));
6154                 basicGroup->addChild(new BuiltinVariableRenderTest      (m_context,     "primitive_id_in_restarted","test gl_PrimitiveIDIn with primitive restart",             BuiltinVariableShader::TEST_PRIMITIVE_ID_IN, GeometryShaderRenderTest::FLAG_USE_RESTART_INDEX | GeometryShaderRenderTest::FLAG_USE_INDICES));
6155                 basicGroup->addChild(new BuiltinVariableRenderTest      (m_context,     "primitive_id",                         "test gl_PrimitiveID",                                                          BuiltinVariableShader::TEST_PRIMITIVE_ID));
6156         }
6157
6158         // input primitives
6159         {
6160                 static const PrimitiveTestSpec inputPrimitives[] =
6161                 {
6162                         { GL_POINTS,                                    "points",                                       GL_POINTS                       },
6163                         { GL_LINES,                                             "lines",                                        GL_LINE_STRIP           },
6164                         { GL_LINE_LOOP,                                 "line_loop",                            GL_LINE_STRIP           },
6165                         { GL_LINE_STRIP,                                "line_strip",                           GL_LINE_STRIP           },
6166                         { GL_TRIANGLES,                                 "triangles",                            GL_TRIANGLE_STRIP       },
6167                         { GL_TRIANGLE_STRIP,                    "triangle_strip",                       GL_TRIANGLE_STRIP       },
6168                         { GL_TRIANGLE_FAN,                              "triangle_fan",                         GL_TRIANGLE_STRIP       },
6169                         { GL_LINES_ADJACENCY,                   "lines_adjacency",                      GL_LINE_STRIP           },
6170                         { GL_LINE_STRIP_ADJACENCY,              "line_strip_adjacency",         GL_LINE_STRIP           },
6171                         { GL_TRIANGLES_ADJACENCY,               "triangles_adjacency",          GL_TRIANGLE_STRIP       }
6172                 };
6173
6174                 tcu::TestCaseGroup* const basicPrimitiveGroup           = new tcu::TestCaseGroup(m_testCtx, "basic_primitive",                  "Different input and output primitives.");
6175                 tcu::TestCaseGroup* const triStripAdjacencyGroup        = new tcu::TestCaseGroup(m_testCtx, "triangle_strip_adjacency", "Different triangle_strip_adjacency vertex counts.");
6176
6177                 // more basic types
6178                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
6179                         basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(m_context, inputPrimitives[ndx].name, inputPrimitives[ndx].name, inputPrimitives[ndx].primitiveType, inputPrimitives[ndx].outputType));
6180
6181                 // triangle strip adjacency with different vtx counts
6182                 for (int vtxCount = 0; vtxCount <= 12; ++vtxCount)
6183                 {
6184                         const std::string name = "vertex_count_" + de::toString(vtxCount);
6185                         const std::string desc = "Vertex count is " + de::toString(vtxCount);
6186
6187                         triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(m_context, name.c_str(), desc.c_str(), vtxCount));
6188                 }
6189
6190                 inputPrimitiveGroup->addChild(basicPrimitiveGroup);
6191                 inputPrimitiveGroup->addChild(triStripAdjacencyGroup);
6192         }
6193
6194         // different type conversions
6195         {
6196                 static const PrimitiveTestSpec conversionPrimitives[] =
6197                 {
6198                         { GL_TRIANGLES,         "triangles_to_points",  GL_POINTS                       },
6199                         { GL_LINES,                     "lines_to_points",              GL_POINTS                       },
6200                         { GL_POINTS,            "points_to_lines",              GL_LINE_STRIP           },
6201                         { GL_TRIANGLES,         "triangles_to_lines",   GL_LINE_STRIP           },
6202                         { GL_POINTS,            "points_to_triangles",  GL_TRIANGLE_STRIP       },
6203                         { GL_LINES,                     "lines_to_triangles",   GL_TRIANGLE_STRIP       }
6204                 };
6205
6206                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
6207                         conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(m_context, conversionPrimitives[ndx].name, conversionPrimitives[ndx].name, conversionPrimitives[ndx].primitiveType, conversionPrimitives[ndx].outputType));
6208         }
6209
6210         // emit different amounts
6211         {
6212                 static const EmitTestSpec emitTests[] =
6213                 {
6214                         { GL_POINTS,                     0,             0,      0,      0,      "points"                        },
6215                         { GL_POINTS,                     0,             1,      0,      0,      "points"                        },
6216                         { GL_POINTS,                     1,             1,      0,      0,      "points"                        },
6217                         { GL_POINTS,                     0,             2,      0,      0,      "points"                        },
6218                         { GL_POINTS,                     1,             2,      0,      0,      "points"                        },
6219                         { GL_LINE_STRIP,                 0,             0,      0,      0,      "line_strip"            },
6220                         { GL_LINE_STRIP,                 0,             1,      0,      0,      "line_strip"            },
6221                         { GL_LINE_STRIP,                 1,             1,      0,      0,      "line_strip"            },
6222                         { GL_LINE_STRIP,                 2,             1,      0,      0,      "line_strip"            },
6223                         { GL_LINE_STRIP,                 0,             2,      0,      0,      "line_strip"            },
6224                         { GL_LINE_STRIP,                 1,             2,      0,      0,      "line_strip"            },
6225                         { GL_LINE_STRIP,                 2,             2,      0,      0,      "line_strip"            },
6226                         { GL_LINE_STRIP,                 2,             2,      2,      0,      "line_strip"            },
6227                         { GL_TRIANGLE_STRIP,     0,             0,      0,      0,      "triangle_strip"        },
6228                         { GL_TRIANGLE_STRIP,     0,             1,      0,      0,      "triangle_strip"        },
6229                         { GL_TRIANGLE_STRIP,     1,             1,      0,      0,      "triangle_strip"        },
6230                         { GL_TRIANGLE_STRIP,     2,             1,      0,      0,      "triangle_strip"        },
6231                         { GL_TRIANGLE_STRIP,     3,             1,      0,      0,      "triangle_strip"        },
6232                         { GL_TRIANGLE_STRIP,     0,             2,      0,      0,      "triangle_strip"        },
6233                         { GL_TRIANGLE_STRIP,     1,             2,      0,      0,      "triangle_strip"        },
6234                         { GL_TRIANGLE_STRIP,     2,             2,      0,      0,      "triangle_strip"        },
6235                         { GL_TRIANGLE_STRIP,     3,             2,      0,      0,      "triangle_strip"        },
6236                         { GL_TRIANGLE_STRIP,     3,             2,      3,      0,      "triangle_strip"        },
6237                 };
6238
6239                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(emitTests); ++ndx)
6240                 {
6241                         std::string name = std::string(emitTests[ndx].name) + "_emit_" + de::toString(emitTests[ndx].emitCountA) + "_end_" + de::toString(emitTests[ndx].endCountA);
6242                         std::string desc = std::string(emitTests[ndx].name) + " output, emit " + de::toString(emitTests[ndx].emitCountA) + " vertices, call EndPrimitive " + de::toString(emitTests[ndx].endCountA) + " times";
6243
6244                         if (emitTests[ndx].emitCountB)
6245                         {
6246                                 name += "_emit_" + de::toString(emitTests[ndx].emitCountB) + "_end_" + de::toString(emitTests[ndx].endCountB);
6247                                 desc += ", emit " + de::toString(emitTests[ndx].emitCountB) + " vertices, call EndPrimitive " + de::toString(emitTests[ndx].endCountB) + " times";
6248                         }
6249
6250                         emitGroup->addChild(new EmitTest(m_context, name.c_str(), desc.c_str(), emitTests[ndx].emitCountA, emitTests[ndx].endCountA, emitTests[ndx].emitCountB, emitTests[ndx].endCountB, emitTests[ndx].outputType));
6251                 }
6252         }
6253
6254         // varying
6255         {
6256                 struct VaryingTestSpec
6257                 {
6258                         int                     vertexOutputs;
6259                         int                     geometryOutputs;
6260                         const char*     name;
6261                         const char*     desc;
6262                 };
6263
6264                 static const VaryingTestSpec varyingTests[] =
6265                 {
6266                         { -1, 1, "vertex_no_op_geometry_out_1", "vertex_no_op_geometry_out_1" },
6267                         {  0, 1, "vertex_out_0_geometry_out_1", "vertex_out_0_geometry_out_1" },
6268                         {  0, 2, "vertex_out_0_geometry_out_2", "vertex_out_0_geometry_out_2" },
6269                         {  1, 0, "vertex_out_1_geometry_out_0", "vertex_out_1_geometry_out_0" },
6270                         {  1, 2, "vertex_out_1_geometry_out_2", "vertex_out_1_geometry_out_2" },
6271                 };
6272
6273                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(varyingTests); ++ndx)
6274                         varyingGroup->addChild(new VaryingTest(m_context, varyingTests[ndx].name, varyingTests[ndx].desc, varyingTests[ndx].vertexOutputs, varyingTests[ndx].geometryOutputs));
6275         }
6276
6277         // layered
6278         {
6279                 static const struct TestType
6280                 {
6281                         LayeredRenderCase::TestType     test;
6282                         const char*                                     testPrefix;
6283                         const char*                                     descPrefix;
6284                 } tests[] =
6285                 {
6286                         { LayeredRenderCase::TEST_DEFAULT_LAYER,                        "render_with_default_layer_",   "Render to all layers of "                                      },
6287                         { LayeredRenderCase::TEST_SINGLE_LAYER,                         "render_to_one_",                               "Render to one layer of "                                       },
6288                         { LayeredRenderCase::TEST_ALL_LAYERS,                           "render_to_all_",                               "Render to all layers of "                                      },
6289                         { LayeredRenderCase::TEST_DIFFERENT_LAYERS,                     "render_different_to_",                 "Render different data to different layers"     },
6290                         { LayeredRenderCase::TEST_LAYER_ID,                                     "fragment_layer_",                              "Read gl_Layer in fragment shader"                      },
6291                         { LayeredRenderCase::TEST_LAYER_PROVOKING_VERTEX,       "layer_provoking_vertex_",              "Verify LAYER_PROVOKING_VERTEX"                         },
6292                 };
6293
6294                 for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
6295                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6296                 {
6297                         const std::string name = std::string(tests[testNdx].testPrefix) + layerTargets[targetNdx].name;
6298                         const std::string desc = std::string(tests[testNdx].descPrefix) + layerTargets[targetNdx].desc;
6299
6300                         layeredGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, tests[testNdx].test));
6301                 }
6302         }
6303
6304         // instanced
6305         {
6306                 static const struct InvocationCase
6307                 {
6308                         const char* name;
6309                         int                     numInvocations;
6310                 } invocationCases[] =
6311                 {
6312                         { "1",          1  },
6313                         { "2",          2  },
6314                         { "8",          8  },
6315                         { "32",         32 },
6316                         { "max",        -1 },
6317                 };
6318                 static const int numDrawInstances[] = { 2, 4, 8 };
6319                 static const int numDrawInvocations[] = { 2, 8 };
6320
6321                 // same amount of content to all invocations
6322                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6323                         instancedGroup->addChild(new GeometryInvocationCase(m_context,
6324                                                                                                                                 (std::string("geometry_") + invocationCases[ndx].name + "_invocations").c_str(),
6325                                                                                                                                 (std::string("Geometry shader with ") + invocationCases[ndx].name + " invocation(s)").c_str(),
6326                                                                                                                                 invocationCases[ndx].numInvocations,
6327                                                                                                                                 GeometryInvocationCase::CASE_FIXED_OUTPUT_COUNTS));
6328
6329                 // different amount of content to each invocation
6330                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6331                         if (invocationCases[ndx].numInvocations != 1)
6332                                 instancedGroup->addChild(new GeometryInvocationCase(m_context,
6333                                                                                                                                         (std::string("geometry_output_different_") + invocationCases[ndx].name + "_invocations").c_str(),
6334                                                                                                                                         "Geometry shader invocation(s) with different emit counts",
6335                                                                                                                                         invocationCases[ndx].numInvocations,
6336                                                                                                                                         GeometryInvocationCase::CASE_DIFFERENT_OUTPUT_COUNTS));
6337
6338                 // invocation per layer
6339                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6340                 {
6341                         const std::string name = std::string("invocation_per_layer_") + layerTargets[targetNdx].name;
6342                         const std::string desc = std::string("Render to multiple layers with multiple invocations, one invocation per layer, target ") + layerTargets[targetNdx].desc;
6343
6344                         instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, LayeredRenderCase::TEST_INVOCATION_PER_LAYER));
6345                 }
6346
6347                 // multiple layers per invocation
6348                 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6349                 {
6350                         const std::string name = std::string("multiple_layers_per_invocation_") + layerTargets[targetNdx].name;
6351                         const std::string desc = std::string("Render to multiple layers with multiple invocations, multiple layers per invocation, target ") + layerTargets[targetNdx].desc;
6352
6353                         instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, LayeredRenderCase::TEST_MULTIPLE_LAYERS_PER_INVOCATION));
6354                 }
6355
6356                 // different invocation output counts depending on {uniform, attrib, texture}
6357                 instancedGroup->addChild(new VaryingOutputCountCase(m_context,  "invocation_output_vary_by_attribute",  "Output varying number of vertices", VaryingOutputCountShader::READ_ATTRIBUTE,  VaryingOutputCountCase::MODE_WITH_INSTANCING));
6358                 instancedGroup->addChild(new VaryingOutputCountCase(m_context,  "invocation_output_vary_by_uniform",    "Output varying number of vertices", VaryingOutputCountShader::READ_UNIFORM,    VaryingOutputCountCase::MODE_WITH_INSTANCING));
6359                 instancedGroup->addChild(new VaryingOutputCountCase(m_context,  "invocation_output_vary_by_texture",    "Output varying number of vertices", VaryingOutputCountShader::READ_TEXTURE,    VaryingOutputCountCase::MODE_WITH_INSTANCING));
6360
6361                 // with drawInstanced
6362                 for (int instanceNdx = 0; instanceNdx < DE_LENGTH_OF_ARRAY(numDrawInstances); ++instanceNdx)
6363                 for (int invocationNdx = 0; invocationNdx < DE_LENGTH_OF_ARRAY(numDrawInvocations); ++invocationNdx)
6364                 {
6365                         const std::string name = std::string("draw_") + de::toString(numDrawInstances[instanceNdx]) + "_instances_geometry_" + de::toString(numDrawInvocations[invocationNdx]) + "_invocations";
6366                         const std::string desc = std::string("Draw ") + de::toString(numDrawInstances[instanceNdx]) + " instances, with " + de::toString(numDrawInvocations[invocationNdx]) + " geometry shader invocations.";
6367
6368                         instancedGroup->addChild(new DrawInstancedGeometryInstancedCase(m_context, name.c_str(), desc.c_str(), numDrawInstances[instanceNdx], numDrawInvocations[invocationNdx]));
6369                 }
6370         }
6371
6372         // negative (wrong types)
6373         {
6374                 struct PrimitiveToInputTypeConversion
6375                 {
6376                         GLenum inputType;
6377                         GLenum primitiveType;
6378                 };
6379
6380                 static const PrimitiveToInputTypeConversion legalConversions[] =
6381                 {
6382                         { GL_POINTS,                            GL_POINTS                                       },
6383                         { GL_LINES,                                     GL_LINES                                        },
6384                         { GL_LINES,                                     GL_LINE_LOOP                            },
6385                         { GL_LINES,                                     GL_LINE_STRIP                           },
6386                         { GL_LINES_ADJACENCY,           GL_LINES_ADJACENCY                      },
6387                         { GL_LINES_ADJACENCY,           GL_LINE_STRIP_ADJACENCY         },
6388                         { GL_TRIANGLES,                         GL_TRIANGLES                            },
6389                         { GL_TRIANGLES,                         GL_TRIANGLE_STRIP                       },
6390                         { GL_TRIANGLES,                         GL_TRIANGLE_FAN                         },
6391                         { GL_TRIANGLES_ADJACENCY,       GL_TRIANGLES_ADJACENCY          },
6392                         { GL_TRIANGLES_ADJACENCY,       GL_TRIANGLE_STRIP_ADJACENCY     },
6393                 };
6394
6395                 static const GLenum inputTypes[] =
6396                 {
6397                         GL_POINTS,
6398                         GL_LINES,
6399                         GL_LINES_ADJACENCY,
6400                         GL_TRIANGLES,
6401                         GL_TRIANGLES_ADJACENCY
6402                 };
6403
6404                 static const GLenum primitiveTypes[] =
6405                 {
6406                         GL_POINTS,
6407                         GL_LINES,
6408                         GL_LINE_LOOP,
6409                         GL_LINE_STRIP,
6410                         GL_LINES_ADJACENCY,
6411                         GL_LINE_STRIP_ADJACENCY,
6412                         GL_TRIANGLES,
6413                         GL_TRIANGLE_STRIP,
6414                         GL_TRIANGLE_FAN,
6415                         GL_TRIANGLES_ADJACENCY,
6416                         GL_TRIANGLE_STRIP_ADJACENCY
6417                 };
6418
6419                 for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); ++inputTypeNdx)
6420                 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
6421                 {
6422                         const GLenum            inputType               = inputTypes[inputTypeNdx];
6423                         const GLenum            primitiveType   = primitiveTypes[primitiveTypeNdx];
6424                         const std::string       name                    = std::string("type_") + inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) + "_primitive_" + primitiveTypeToString(primitiveType);
6425                         const std::string       desc                    = std::string("Shader input type ") + inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) + ", draw primitive type " + primitiveTypeToString(primitiveType);
6426
6427                         bool isLegal = false;
6428
6429                         for (int legalNdx = 0; legalNdx < DE_LENGTH_OF_ARRAY(legalConversions); ++legalNdx)
6430                                 if (legalConversions[legalNdx].inputType == inputType && legalConversions[legalNdx].primitiveType == primitiveType)
6431                                         isLegal = true;
6432
6433                         // only illegal
6434                         if (!isLegal)
6435                                 negativeGroup->addChild(new NegativeDrawCase(m_context, name.c_str(), desc.c_str(), inputType, primitiveType));
6436                 }
6437         }
6438
6439         // vertex transform feedback
6440         {
6441                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_line_loop",                           "Capture line loop lines",                                                                      VertexFeedbackCase::METHOD_DRAW_ARRAYS,                         VertexFeedbackCase::PRIMITIVE_LINE_LOOP));
6442                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_line_strip",                          "Capture line strip lines",                                                                     VertexFeedbackCase::METHOD_DRAW_ARRAYS,                         VertexFeedbackCase::PRIMITIVE_LINE_STRIP));
6443                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_triangle_strip",                      "Capture triangle strip triangles",                                                     VertexFeedbackCase::METHOD_DRAW_ARRAYS,                         VertexFeedbackCase::PRIMITIVE_TRIANGLE_STRIP));
6444                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_triangle_fan",                        "Capture triangle fan triangles",                                                       VertexFeedbackCase::METHOD_DRAW_ARRAYS,                         VertexFeedbackCase::PRIMITIVE_TRIANGLE_FAN));
6445                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays",                         "Capture primitives generated with drawArrays",                         VertexFeedbackCase::METHOD_DRAW_ARRAYS,                         VertexFeedbackCase::PRIMITIVE_POINTS));
6446                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays_instanced",       "Capture primitives generated with drawArraysInstanced",        VertexFeedbackCase::METHOD_DRAW_ARRAYS_INSTANCED,       VertexFeedbackCase::PRIMITIVE_POINTS));
6447                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays_indirect",        "Capture primitives generated with drawArraysIndirect",         VertexFeedbackCase::METHOD_DRAW_ARRAYS_INDIRECT,        VertexFeedbackCase::PRIMITIVE_POINTS));
6448                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements",                       "Capture primitives generated with drawElements",                       VertexFeedbackCase::METHOD_DRAW_ELEMENTS,                       VertexFeedbackCase::PRIMITIVE_POINTS));
6449                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_instanced",     "Capture primitives generated with drawElementsInstanced",      VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INSTANCED,     VertexFeedbackCase::PRIMITIVE_POINTS));
6450                 feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_indirect",      "Capture primitives generated with drawElementsIndirect",       VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INDIRECT,      VertexFeedbackCase::PRIMITIVE_POINTS));
6451
6452                 feedbackGroup->addChild(new VertexFeedbackOverflowCase(m_context, "capture_vertex_draw_arrays_overflow_single_buffer",          "Capture triangles to too small a buffer", VertexFeedbackOverflowCase::METHOD_DRAW_ARRAYS));
6453                 feedbackGroup->addChild(new VertexFeedbackOverflowCase(m_context, "capture_vertex_draw_elements_overflow_single_buffer",        "Capture triangles to too small a buffer", VertexFeedbackOverflowCase::METHOD_DRAW_ELEMENTS));
6454         }
6455 }
6456
6457 } // Functional
6458 } // gles31
6459 } // deqp