Fix undefined behavior in record_variable_selection test.
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fTessellationGeometryInteractionTests.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 Tessellation and geometry shader interaction tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fTessellationGeometryInteractionTests.hpp"
25
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "gluStrUtil.hpp"
35 #include "gluContextInfo.hpp"
36 #include "gluObjectWrapper.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40 #include "deStringUtil.hpp"
41 #include "deUniquePtr.hpp"
42
43 #include <sstream>
44 #include <algorithm>
45 #include <iterator>
46
47 namespace deqp
48 {
49 namespace gles31
50 {
51 namespace Functional
52 {
53 namespace
54 {
55
56 static const char* const s_positionVertexShader =               "#version 310 es\n"
57                                                                                                                 "in highp vec4 a_position;\n"
58                                                                                                                 "void main (void)\n"
59                                                                                                                 "{\n"
60                                                                                                                 "       gl_Position = a_position;\n"
61                                                                                                                 "}\n";
62 static const char* const s_whiteOutputFragmentShader =  "#version 310 es\n"
63                                                                                                                 "layout(location = 0) out mediump vec4 fragColor;\n"
64                                                                                                                 "void main (void)\n"
65                                                                                                                 "{\n"
66                                                                                                                 "       fragColor = vec4(1.0);\n"
67                                                                                                                 "}\n";
68
69 static bool isBlack (const tcu::RGBA& c)
70 {
71         return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
72 }
73
74 class IdentityShaderCase : public TestCase
75 {
76 public:
77                                         IdentityShaderCase      (Context& context, const char* name, const char* description);
78
79 protected:
80         const char*             getVertexSource         (void) const;
81         const char*             getFragmentSource       (void) const;
82 };
83
84 IdentityShaderCase::IdentityShaderCase (Context& context, const char* name, const char* description)
85         : TestCase(context, name, description)
86 {
87 }
88
89 const char* IdentityShaderCase::getVertexSource (void) const
90 {
91         return  "#version 310 es\n"
92                         "in highp vec4 a_position;\n"
93                         "out highp vec4 v_vertex_color;\n"
94                         "void main (void)\n"
95                         "{\n"
96                         "       gl_Position = a_position;\n"
97                         "       v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
98                         "}\n";
99 }
100
101 const char* IdentityShaderCase::getFragmentSource (void) const
102 {
103         return  "#version 310 es\n"
104                         "in mediump vec4 v_fragment_color;\n"
105                         "layout(location = 0) out mediump vec4 fragColor;\n"
106                         "void main (void)\n"
107                         "{\n"
108                         "       fragColor = v_fragment_color;\n"
109                         "}\n";
110 }
111
112 class IdentityGeometryShaderCase : public IdentityShaderCase
113 {
114 public:
115         enum CaseType
116         {
117                 CASE_TRIANGLES = 0,
118                 CASE_QUADS,
119                 CASE_ISOLINES,
120         };
121
122                                         IdentityGeometryShaderCase                      (Context& context, const char* name, const char* description, CaseType caseType);
123                                         ~IdentityGeometryShaderCase                     (void);
124
125 private:
126         void                    init                                                            (void);
127         void                    deinit                                                          (void);
128         IterateResult   iterate                                                         (void);
129
130         std::string             getTessellationControlSource            (void) const;
131         std::string             getTessellationEvaluationSource         (bool geometryActive) const;
132         std::string             getGeometrySource                                       (void) const;
133
134         enum
135         {
136                 RENDER_SIZE = 128,
137         };
138
139         const CaseType  m_case;
140         deUint32                m_patchBuffer;
141 };
142
143 IdentityGeometryShaderCase::IdentityGeometryShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
144         : IdentityShaderCase    (context, name, description)
145         , m_case                                (caseType)
146         , m_patchBuffer                 (0)
147 {
148 }
149
150 IdentityGeometryShaderCase::~IdentityGeometryShaderCase (void)
151 {
152         deinit();
153 }
154
155 void IdentityGeometryShaderCase::init (void)
156 {
157         // Requirements
158
159         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
160                 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
161                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
162
163         if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
164                 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
165                 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
166
167         // Log
168
169         m_testCtx.getLog()
170                 << tcu::TestLog::Message
171                 << "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
172                 << "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
173                 << "Using additive blending to detect overlap.\n"
174                 << tcu::TestLog::EndMessage;
175
176         // Resources
177
178         {
179                 static const tcu::Vec4 patchBufferData[4] =
180                 {
181                         tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
182                         tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ),
183                         tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ),
184                         tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ),
185                 };
186
187                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
188
189                 gl.genBuffers(1, &m_patchBuffer);
190                 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
191                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
192                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
193         }
194 }
195
196 void IdentityGeometryShaderCase::deinit (void)
197 {
198         if (m_patchBuffer)
199         {
200                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
201                 m_patchBuffer = 0;
202         }
203 }
204
205 IdentityGeometryShaderCase::IterateResult IdentityGeometryShaderCase::iterate (void)
206 {
207         const float                             innerTessellationLevel  = 14.0f;
208         const float                             outerTessellationLevel  = 14.0f;
209         const glw::Functions&   gl                                              = m_context.getRenderContext().getFunctions();
210         tcu::Surface                    resultWithGeometry              (RENDER_SIZE, RENDER_SIZE);
211         tcu::Surface                    resultWithoutGeometry   (RENDER_SIZE, RENDER_SIZE);
212
213         const struct
214         {
215                 const char*                             name;
216                 const char*                             description;
217                 bool                                    containsGeometryShader;
218                 tcu::PixelBufferAccess  surfaceAccess;
219         } renderTargets[] =
220         {
221                 { "RenderWithGeometryShader",           "Render with geometry shader",          true,   resultWithGeometry.getAccess()          },
222                 { "RenderWithoutGeometryShader",        "Render without geometry shader",       false,  resultWithoutGeometry.getAccess()       },
223         };
224
225         gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
226         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
227         GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
228
229         gl.enable(GL_BLEND);
230         gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
231         gl.blendEquation(GL_FUNC_ADD);
232         GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
233
234         m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation level: inner " << innerTessellationLevel << ", outer " << outerTessellationLevel << tcu::TestLog::EndMessage;
235
236         // render with and without geometry shader
237         for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
238         {
239                 const tcu::ScopedLogSection     section (m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
240                 glu::ProgramSources                     sources;
241
242                 sources << glu::VertexSource(getVertexSource())
243                                 << glu::FragmentSource(getFragmentSource())
244                                 << glu::TessellationControlSource(getTessellationControlSource())
245                                 << glu::TessellationEvaluationSource(getTessellationEvaluationSource(renderTargets[renderNdx].containsGeometryShader));
246
247                 if (renderTargets[renderNdx].containsGeometryShader)
248                         sources << glu::GeometrySource(getGeometrySource());
249
250                 {
251                         const glu::ShaderProgram        program                                 (m_context.getRenderContext(), sources);
252                         const glu::VertexArray          vao                                             (m_context.getRenderContext());
253                         const int                                       posLocation                             = gl.getAttribLocation(program.getProgram(), "a_position");
254                         const int                                       innerTessellationLoc    = gl.getUniformLocation(program.getProgram(), "u_innerTessellationLevel");
255                         const int                                       outerTessellationLoc    = gl.getUniformLocation(program.getProgram(), "u_outerTessellationLevel");
256
257                         m_testCtx.getLog() << program;
258
259                         if (!program.isOk())
260                                 throw tcu::TestError("could not build program");
261                         if (posLocation == -1)
262                                 throw tcu::TestError("a_position location was -1");
263                         if (outerTessellationLoc == -1)
264                                 throw tcu::TestError("u_outerTessellationLevel location was -1");
265
266                         gl.bindVertexArray(*vao);
267                         gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
268                         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
269                         gl.enableVertexAttribArray(posLocation);
270                         GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
271
272                         gl.useProgram(program.getProgram());
273                         gl.uniform1f(outerTessellationLoc, outerTessellationLevel);
274
275                         if (innerTessellationLoc == -1)
276                                 gl.uniform1f(innerTessellationLoc, innerTessellationLevel);
277
278                         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
279
280                         gl.patchParameteri(GL_PATCH_VERTICES, (m_case == CASE_TRIANGLES) ? (3): (4));
281                         GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
282
283                         gl.clear(GL_COLOR_BUFFER_BIT);
284                         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
285
286                         gl.drawArrays(GL_PATCHES, 0, 4);
287                         GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
288
289                         glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
290                 }
291         }
292
293         if (tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
294                                                                                                   "ImageCompare",
295                                                                                                   "Image comparison",
296                                                                                                   resultWithoutGeometry.getAccess(),
297                                                                                                   resultWithGeometry.getAccess(),
298                                                                                                   tcu::UVec4(8, 8, 8, 255),
299                                                                                                   tcu::IVec3(1, 1, 0),
300                                                                                                   true,
301                                                                                                   tcu::COMPARE_LOG_RESULT))
302                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
303         else
304                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
305
306         return STOP;
307 }
308
309 std::string IdentityGeometryShaderCase::getTessellationControlSource (void) const
310 {
311         std::ostringstream buf;
312
313         buf <<  "#version 310 es\n"
314                         "#extension GL_EXT_tessellation_shader : require\n"
315                         "layout(vertices = 4) out;\n"
316                         "\n"
317                         "uniform highp float u_innerTessellationLevel;\n"
318                         "uniform highp float u_outerTessellationLevel;\n"
319                         "in highp vec4 v_vertex_color[];\n"
320                         "out highp vec4 v_patch_color[];\n"
321                         "\n"
322                         "void main (void)\n"
323                         "{\n"
324                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
325                         "       v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
326                         "\n";
327
328         if (m_case == CASE_TRIANGLES)
329                 buf <<  "       gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
330                                 "       gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
331                                 "       gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
332                                 "       gl_TessLevelInner[0] = u_innerTessellationLevel;\n";
333         else if (m_case == CASE_QUADS)
334                 buf <<  "       gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
335                                 "       gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
336                                 "       gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
337                                 "       gl_TessLevelOuter[3] = u_outerTessellationLevel;\n"
338                                 "       gl_TessLevelInner[0] = u_innerTessellationLevel;\n"
339                                 "       gl_TessLevelInner[1] = u_innerTessellationLevel;\n";
340         else if (m_case == CASE_ISOLINES)
341                 buf <<  "       gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
342                                 "       gl_TessLevelOuter[1] = u_outerTessellationLevel;\n";
343         else
344                 DE_ASSERT(false);
345
346         buf <<  "}\n";
347
348         return buf.str();
349 }
350
351 std::string IdentityGeometryShaderCase::getTessellationEvaluationSource (bool geometryActive) const
352 {
353         const char* const       colorOutputName = ((geometryActive) ? ("v_evaluated_color") : ("v_fragment_color"));
354         std::ostringstream      buf;
355
356         buf <<  "#version 310 es\n"
357                         "#extension GL_EXT_tessellation_shader : require\n"
358                         "layout("
359                                 << ((m_case == CASE_TRIANGLES) ? ("triangles") : (m_case == CASE_QUADS) ? ("quads") : ("isolines"))
360                                 << ") in;\n"
361                         "\n"
362                         "in highp vec4 v_patch_color[];\n"
363                         "out highp vec4 " << colorOutputName << ";\n"
364                         "\n"
365                         "void main (void)\n"
366                         "{\n";
367
368         if (m_case == CASE_TRIANGLES)
369                 buf <<  "       vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
370                                 "       vec3 cweights = gl_TessCoord;\n"
371                                 "       gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n"
372                                 "       " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
373         else if (m_case == CASE_QUADS || m_case == CASE_ISOLINES)
374                 buf <<  "       vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
375                                 "       vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
376                                 "       vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
377                                 "       vec2 cweights = gl_TessCoord.xy;\n"
378                                 "       gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n"
379                                 "       " << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n";
380         else
381                 DE_ASSERT(false);
382
383         buf <<  "}\n";
384
385         return buf.str();
386 }
387
388 std::string IdentityGeometryShaderCase::getGeometrySource (void) const
389 {
390         const char* const       geometryInputPrimitive                  = (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
391         const char* const       geometryOutputPrimitive                 = (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
392         const int                       numEmitVertices                                 = (m_case == CASE_ISOLINES) ? (2) : (3);
393         std::ostringstream      buf;
394
395         buf <<  "#version 310 es\n"
396                         "#extension GL_EXT_geometry_shader : require\n"
397                         "layout(" << geometryInputPrimitive << ") in;\n"
398                         "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
399                         "\n"
400                         "in highp vec4 v_evaluated_color[];\n"
401                         "out highp vec4 v_fragment_color;\n"
402                         "\n"
403                         "void main (void)\n"
404                         "{\n"
405                         "       for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
406                         "       {\n"
407                         "               gl_Position = gl_in[ndx].gl_Position;\n"
408                         "               v_fragment_color = v_evaluated_color[ndx];\n"
409                         "               EmitVertex();\n"
410                         "       }\n"
411                         "}\n";
412
413         return buf.str();
414 }
415
416 class IdentityTessellationShaderCase : public IdentityShaderCase
417 {
418 public:
419         enum CaseType
420         {
421                 CASE_TRIANGLES = 0,
422                 CASE_ISOLINES,
423         };
424
425                                         IdentityTessellationShaderCase          (Context& context, const char* name, const char* description, CaseType caseType);
426                                         ~IdentityTessellationShaderCase         (void);
427
428 private:
429         void                    init                                                            (void);
430         void                    deinit                                                          (void);
431         IterateResult   iterate                                                         (void);
432
433         std::string             getTessellationControlSource            (void) const;
434         std::string             getTessellationEvaluationSource         (void) const;
435         std::string             getGeometrySource                                       (bool tessellationActive) const;
436
437         enum
438         {
439                 RENDER_SIZE = 256,
440         };
441
442         const CaseType  m_case;
443         deUint32                m_dataBuffer;
444 };
445
446 IdentityTessellationShaderCase::IdentityTessellationShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
447         : IdentityShaderCase    (context, name, description)
448         , m_case                                (caseType)
449         , m_dataBuffer                  (0)
450 {
451 }
452
453 IdentityTessellationShaderCase::~IdentityTessellationShaderCase (void)
454 {
455         deinit();
456 }
457
458 void IdentityTessellationShaderCase::init (void)
459 {
460         // Requirements
461
462         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
463                 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
464                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
465
466         if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
467                 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
468                 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
469
470         // Log
471
472         m_testCtx.getLog()
473                 << tcu::TestLog::Message
474                 << "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
475                 << "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
476                 << "Using additive blending to detect overlap.\n"
477                 << tcu::TestLog::EndMessage;
478
479         // Resources
480
481         {
482                 static const tcu::Vec4  pointData[]     =
483                 {
484                         tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f ),
485                         tcu::Vec4(  0.0f, -0.5f, 0.0f, 1.0f ),
486                         tcu::Vec4(  0.4f,  0.4f, 0.0f, 1.0f ),
487                 };
488                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
489
490                 gl.genBuffers(1, &m_dataBuffer);
491                 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
492                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(pointData), pointData, GL_STATIC_DRAW);
493                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
494         }
495 }
496
497 void IdentityTessellationShaderCase::deinit (void)
498 {
499         if (m_dataBuffer)
500         {
501                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBuffer);
502                 m_dataBuffer = 0;
503         }
504 }
505
506 IdentityTessellationShaderCase::IterateResult IdentityTessellationShaderCase::iterate (void)
507 {
508         const glw::Functions&   gl                                                      = m_context.getRenderContext().getFunctions();
509         tcu::Surface                    resultWithTessellation          (RENDER_SIZE, RENDER_SIZE);
510         tcu::Surface                    resultWithoutTessellation       (RENDER_SIZE, RENDER_SIZE);
511         const int                               numPrimitiveVertices            = (m_case == CASE_TRIANGLES) ? (3) : (2);
512
513         const struct
514         {
515                 const char*                             name;
516                 const char*                             description;
517                 bool                                    containsTessellationShaders;
518                 tcu::PixelBufferAccess  surfaceAccess;
519         } renderTargets[] =
520         {
521                 { "RenderWithTessellationShader",               "Render with tessellation shader",              true,   resultWithTessellation.getAccess()              },
522                 { "RenderWithoutTessellationShader",    "Render without tessellation shader",   false,  resultWithoutTessellation.getAccess()   },
523         };
524
525         gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
526         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
527         GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
528
529         gl.enable(GL_BLEND);
530         gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
531         gl.blendEquation(GL_FUNC_ADD);
532         GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
533
534         // render with and without tessellation shader
535         for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
536         {
537                 const tcu::ScopedLogSection     section (m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
538                 glu::ProgramSources                     sources;
539
540                 sources << glu::VertexSource(getVertexSource())
541                                 << glu::FragmentSource(getFragmentSource())
542                                 << glu::GeometrySource(getGeometrySource(renderTargets[renderNdx].containsTessellationShaders));
543
544                 if (renderTargets[renderNdx].containsTessellationShaders)
545                         sources << glu::TessellationControlSource(getTessellationControlSource())
546                                         << glu::TessellationEvaluationSource(getTessellationEvaluationSource());
547
548                 {
549                         const glu::ShaderProgram        program                                 (m_context.getRenderContext(), sources);
550                         const glu::VertexArray          vao                                             (m_context.getRenderContext());
551                         const int                                       posLocation                             = gl.getAttribLocation(program.getProgram(), "a_position");
552
553                         m_testCtx.getLog() << program;
554
555                         if (!program.isOk())
556                                 throw tcu::TestError("could not build program");
557                         if (posLocation == -1)
558                                 throw tcu::TestError("a_position location was -1");
559
560                         gl.bindVertexArray(*vao);
561                         gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
562                         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
563                         gl.enableVertexAttribArray(posLocation);
564                         GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
565
566                         gl.useProgram(program.getProgram());
567                         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
568
569                         gl.clear(GL_COLOR_BUFFER_BIT);
570                         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
571
572                         if (renderTargets[renderNdx].containsTessellationShaders)
573                         {
574                                 gl.patchParameteri(GL_PATCH_VERTICES, numPrimitiveVertices);
575                                 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
576
577                                 gl.drawArrays(GL_PATCHES, 0, numPrimitiveVertices);
578                                 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
579                         }
580                         else
581                         {
582                                 gl.drawArrays((m_case == CASE_TRIANGLES) ? (GL_TRIANGLES) : (GL_LINES), 0, numPrimitiveVertices);
583                                 GLU_EXPECT_NO_ERROR(gl.getError(), "draw primitives");
584                         }
585
586                         glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
587                 }
588         }
589
590         // compare
591         {
592                 bool imageOk;
593
594                 if (m_context.getRenderTarget().getNumSamples() > 1)
595                         imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
596                                                                                 "ImageCompare",
597                                                                                 "Image comparison",
598                                                                                 resultWithoutTessellation.getAccess(),
599                                                                                 resultWithTessellation.getAccess(),
600                                                                                 0.03f,
601                                                                                 tcu::COMPARE_LOG_RESULT);
602                 else
603                         imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
604                                                                                                                                 "ImageCompare",
605                                                                                                                                 "Image comparison",
606                                                                                                                                 resultWithoutTessellation.getAccess(),
607                                                                                                                                 resultWithTessellation.getAccess(),
608                                                                                                                                 tcu::UVec4(8, 8, 8, 255),                               //!< threshold
609                                                                                                                                 tcu::IVec3(1, 1, 0),                                    //!< 3x3 search kernel
610                                                                                                                                 true,                                                                   //!< fragments may end up over the viewport, just ignore them
611                                                                                                                                 tcu::COMPARE_LOG_RESULT);
612
613                 if (imageOk)
614                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
615                 else
616                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
617         }
618
619         return STOP;
620 }
621
622 std::string IdentityTessellationShaderCase::getTessellationControlSource (void) const
623 {
624         std::ostringstream buf;
625
626         buf <<  "#version 310 es\n"
627                         "#extension GL_EXT_tessellation_shader : require\n"
628                         "layout(vertices = " << ((m_case == CASE_TRIANGLES) ? (3) : (2)) << ") out;\n"
629                         "\n"
630                         "in highp vec4 v_vertex_color[];\n"
631                         "out highp vec4 v_control_color[];\n"
632                         "\n"
633                         "void main (void)\n"
634                         "{\n"
635                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
636                         "       v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
637                         "\n";
638
639         if (m_case == CASE_TRIANGLES)
640                 buf <<  "       gl_TessLevelOuter[0] = 1.0;\n"
641                                 "       gl_TessLevelOuter[1] = 1.0;\n"
642                                 "       gl_TessLevelOuter[2] = 1.0;\n"
643                                 "       gl_TessLevelInner[0] = 1.0;\n";
644         else if (m_case == CASE_ISOLINES)
645                 buf <<  "       gl_TessLevelOuter[0] = 1.0;\n"
646                                 "       gl_TessLevelOuter[1] = 1.0;\n";
647         else
648                 DE_ASSERT(false);
649
650         buf <<  "}\n";
651
652         return buf.str();
653 }
654
655 std::string IdentityTessellationShaderCase::getTessellationEvaluationSource (void) const
656 {
657         std::ostringstream buf;
658
659         buf <<  "#version 310 es\n"
660                         "#extension GL_EXT_tessellation_shader : require\n"
661                         "layout("
662                                 << ((m_case == CASE_TRIANGLES) ? ("triangles") : ("isolines"))
663                                 << ") in;\n"
664                         "\n"
665                         "in highp vec4 v_control_color[];\n"
666                         "out highp vec4 v_evaluated_color;\n"
667                         "\n"
668                         "void main (void)\n"
669                         "{\n";
670
671         if (m_case == CASE_TRIANGLES)
672                 buf <<  "       gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
673                                 "       v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n";
674         else if (m_case == CASE_ISOLINES)
675                 buf <<  "       gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
676                                 "       v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
677         else
678                 DE_ASSERT(false);
679
680         buf <<  "}\n";
681
682         return buf.str();
683 }
684
685 std::string IdentityTessellationShaderCase::getGeometrySource (bool tessellationActive) const
686 {
687         const char* const       colorSourceName                 = (tessellationActive) ? ("v_evaluated_color") : ("v_vertex_color");
688         const char* const       geometryInputPrimitive  = (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
689         const char* const       geometryOutputPrimitive = (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
690         const int                       numEmitVertices                 = (m_case == CASE_ISOLINES) ? (11) : (8);
691         std::ostringstream      buf;
692
693         buf <<  "#version 310 es\n"
694                         "#extension GL_EXT_geometry_shader : require\n"
695                         "layout(" << geometryInputPrimitive << ") in;\n"
696                         "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
697                         "\n"
698                         "in highp vec4 " << colorSourceName << "[];\n"
699                         "out highp vec4 v_fragment_color;\n"
700                         "\n"
701                         "void main (void)\n"
702                         "{\n";
703
704         if (m_case == CASE_TRIANGLES)
705         {
706                 buf <<  "       vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
707                                 "\n"
708                                 "       for (int ndx = 0; ndx < 4; ++ndx)\n"
709                                 "       {\n"
710                                 "               gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
711                                 "               v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
712                                 "               EmitVertex();\n"
713                                 "\n"
714                                 "               gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
715                                 "               v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
716                                 "               EmitVertex();\n"
717                                 "       }\n";
718
719         }
720         else if (m_case == CASE_ISOLINES)
721         {
722                 buf <<  "       vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n"
723                                 "       for (int i = 0; i <= 10; ++i)\n"
724                                 "       {\n"
725                                 "               float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
726                                 "               float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
727                                 "               gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
728                                 "               v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
729                                 "               EmitVertex();\n"
730                                 "       }\n";
731         }
732         else
733                 DE_ASSERT(false);
734
735         buf <<  "}\n";
736
737         return buf.str();
738 }
739
740 class FeedbackPrimitiveTypeCase : public TestCase
741 {
742 public:
743         enum TessellationOutputType
744         {
745                 TESSELLATION_OUT_TRIANGLES = 0,
746                 TESSELLATION_OUT_QUADS,
747                 TESSELLATION_OUT_ISOLINES,
748
749                 TESSELLATION_OUT_LAST
750         };
751         enum TessellationPointMode
752         {
753                 TESSELLATION_POINTMODE_OFF = 0,
754                 TESSELLATION_POINTMODE_ON,
755
756                 TESSELLATION_POINTMODE_LAST
757         };
758         enum GeometryOutputType
759         {
760                 GEOMETRY_OUTPUT_POINTS = 0,
761                 GEOMETRY_OUTPUT_LINES,
762                 GEOMETRY_OUTPUT_TRIANGLES,
763
764                 GEOMETRY_OUTPUT_LAST
765         };
766
767                                                                         FeedbackPrimitiveTypeCase                               (Context& context,
768                                                                                                                                                          const char* name,
769                                                                                                                                                          const char* description,
770                                                                                                                                                          TessellationOutputType tessellationOutput,
771                                                                                                                                                          TessellationPointMode tessellationPointMode,
772                                                                                                                                                          GeometryOutputType geometryOutputType);
773                                                                         ~FeedbackPrimitiveTypeCase                              (void);
774
775 private:
776         void                                                    init                                                                    (void);
777         void                                                    deinit                                                                  (void);
778         IterateResult                                   iterate                                                                 (void);
779
780         void                                                    renderWithFeedback                                              (tcu::Surface& dst);
781         void                                                    renderWithoutFeedback                                   (tcu::Surface& dst);
782         void                                                    verifyFeedbackResults                                   (const std::vector<tcu::Vec4>& feedbackResult);
783         void                                                    verifyRenderedImage                                             (const tcu::Surface& image, const std::vector<tcu::Vec4>& vertices);
784
785         void                                                    genTransformFeedback                                    (void);
786         int                                                             getNumGeneratedElementsPerPrimitive             (void) const;
787         int                                                             getNumGeneratedPrimitives                               (void) const;
788         int                                                             getNumTessellatedPrimitives                             (void) const;
789         int                                                             getGeometryAmplification                                (void) const;
790
791         const char*                                             getVertexSource                                                 (void) const;
792         const char*                                             getFragmentSource                                               (void) const;
793         std::string                                             getTessellationControlSource                    (void) const;
794         std::string                                             getTessellationEvaluationSource                 (void) const;
795         std::string                                             getGeometrySource                                               (void) const;
796
797         static const char*                              getTessellationOutputDescription                (TessellationOutputType tessellationOutput,
798                                                                                                                                                          TessellationPointMode tessellationPointMode);
799         static const char*                              getGeometryInputDescription                             (TessellationOutputType tessellationOutput,
800                                                                                                                                                          TessellationPointMode tessellationPointMode);
801         static const char*                              getGeometryOutputDescription                    (GeometryOutputType geometryOutput);
802         glw::GLenum                                             getOutputPrimitiveGLType                                (void) const;
803
804         enum
805         {
806                 RENDER_SIZE = 128,
807         };
808
809         const TessellationOutputType    m_tessellationOutput;
810         const TessellationPointMode             m_tessellationPointMode;
811         const GeometryOutputType                m_geometryOutputType;
812
813         glu::ShaderProgram*                             m_feedbackProgram;
814         glu::ShaderProgram*                             m_nonFeedbackProgram;
815         deUint32                                                m_patchBuffer;
816         deUint32                                                m_feedbackID;
817         deUint32                                                m_feedbackBuffer;
818 };
819
820 FeedbackPrimitiveTypeCase::FeedbackPrimitiveTypeCase (Context& context,
821                                                                           const char* name,
822                                                                           const char* description,
823                                                                           TessellationOutputType tessellationOutput,
824                                                                           TessellationPointMode tessellationPointMode,
825                                                                           GeometryOutputType geometryOutputType)
826         : TestCase                                      (context, name, description)
827         , m_tessellationOutput          (tessellationOutput)
828         , m_tessellationPointMode       (tessellationPointMode)
829         , m_geometryOutputType          (geometryOutputType)
830         , m_feedbackProgram                     (DE_NULL)
831         , m_nonFeedbackProgram          (DE_NULL)
832         , m_patchBuffer                         (0)
833         , m_feedbackID                          (0)
834         , m_feedbackBuffer                      (0)
835 {
836         DE_ASSERT(tessellationOutput < TESSELLATION_OUT_LAST);
837         DE_ASSERT(tessellationPointMode < TESSELLATION_POINTMODE_LAST);
838         DE_ASSERT(geometryOutputType < GEOMETRY_OUTPUT_LAST);
839 }
840
841 FeedbackPrimitiveTypeCase::~FeedbackPrimitiveTypeCase (void)
842 {
843         deinit();
844 }
845
846 void FeedbackPrimitiveTypeCase::init (void)
847 {
848         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
849
850         // Requirements
851
852         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
853                 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
854                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
855
856         if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
857                 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
858                 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
859
860         // Log
861
862         m_testCtx.getLog()
863                 << tcu::TestLog::Message
864                 << "Testing "
865                         << getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode)
866                         << "->"
867                         << getGeometryInputDescription(m_tessellationOutput, m_tessellationPointMode)
868                         << " primitive conversion with and without transform feedback.\n"
869                 << "Sending a patch of 4 vertices (2x2 uniform grid) to tessellation control shader.\n"
870                 << "Control shader emits a patch of 9 vertices (3x3 uniform grid).\n"
871                 << "Setting outer tessellation level = 3, inner = 3.\n"
872                 << "Primitive generator emits " << getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode) << "\n"
873                 << "Geometry shader transforms emitted primitives to " << getGeometryOutputDescription(m_geometryOutputType) << "\n"
874                 << "Reading back vertex positions of generated primitives using transform feedback.\n"
875                 << "Verifying rendered image and feedback vertices are consistent.\n"
876                 << "Rendering scene again with identical shader program, but without setting feedback varying. Expecting similar output image."
877                 << tcu::TestLog::EndMessage;
878
879         // Resources
880
881         {
882                 static const tcu::Vec4 patchBufferData[4] =
883                 {
884                         tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
885                         tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ),
886                         tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ),
887                         tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ),
888                 };
889
890                 gl.genBuffers(1, &m_patchBuffer);
891                 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
892                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
893                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
894         }
895
896         m_feedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
897                                                                                            glu::ProgramSources()
898                                                                                                 << glu::VertexSource(getVertexSource())
899                                                                                                 << glu::FragmentSource(getFragmentSource())
900                                                                                                 << glu::TessellationControlSource(getTessellationControlSource())
901                                                                                                 << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
902                                                                                                 << glu::GeometrySource(getGeometrySource())
903                                                                                                 << glu::TransformFeedbackVarying("tf_someVertexPosition")
904                                                                                                 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
905         m_testCtx.getLog() << *m_feedbackProgram;
906         if (!m_feedbackProgram->isOk())
907                 throw tcu::TestError("failed to build program");
908
909         m_nonFeedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
910                                                                                                   glu::ProgramSources()
911                                                                                                         << glu::VertexSource(getVertexSource())
912                                                                                                         << glu::FragmentSource(getFragmentSource())
913                                                                                                         << glu::TessellationControlSource(getTessellationControlSource())
914                                                                                                         << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
915                                                                                                         << glu::GeometrySource(getGeometrySource()));
916         if (!m_nonFeedbackProgram->isOk())
917         {
918                 m_testCtx.getLog() << *m_nonFeedbackProgram;
919                 throw tcu::TestError("failed to build program");
920         }
921
922         genTransformFeedback();
923 }
924
925 void FeedbackPrimitiveTypeCase::deinit (void)
926 {
927         if (m_patchBuffer)
928         {
929                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
930                 m_patchBuffer = 0;
931         }
932
933         if (m_feedbackBuffer)
934         {
935                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuffer);
936                 m_feedbackBuffer = 0;
937         }
938
939         if (m_feedbackID)
940         {
941                 m_context.getRenderContext().getFunctions().deleteTransformFeedbacks(1, &m_feedbackID);
942                 m_feedbackID = 0;
943         }
944
945         if (m_feedbackProgram)
946         {
947                 delete m_feedbackProgram;
948                 m_feedbackProgram = DE_NULL;
949         }
950
951         if (m_nonFeedbackProgram)
952         {
953                 delete m_nonFeedbackProgram;
954                 m_nonFeedbackProgram = DE_NULL;
955         }
956 }
957
958 FeedbackPrimitiveTypeCase::IterateResult FeedbackPrimitiveTypeCase::iterate (void)
959 {
960         tcu::Surface feedbackResult             (RENDER_SIZE, RENDER_SIZE);
961         tcu::Surface nonFeedbackResult  (RENDER_SIZE, RENDER_SIZE);
962
963         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
964
965         // render with and without XFB
966         renderWithFeedback(feedbackResult);
967         renderWithoutFeedback(nonFeedbackResult);
968
969         // compare
970         {
971                 bool imageOk;
972
973                 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing the image rendered with no transform feedback against the image rendered with enabled transform feedback." << tcu::TestLog::EndMessage;
974
975                 if (m_context.getRenderTarget().getNumSamples() > 1)
976                         imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
977                                                                                 "ImageCompare",
978                                                                                 "Image comparison",
979                                                                                 feedbackResult.getAccess(),
980                                                                                 nonFeedbackResult.getAccess(),
981                                                                                 0.03f,
982                                                                                 tcu::COMPARE_LOG_RESULT);
983                 else
984                         imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
985                                                                                                                                 "ImageCompare",
986                                                                                                                                 "Image comparison",
987                                                                                                                                 feedbackResult.getAccess(),
988                                                                                                                                 nonFeedbackResult.getAccess(),
989                                                                                                                                 tcu::UVec4(8, 8, 8, 255),                                               //!< threshold
990                                                                                                                                 tcu::IVec3(1, 1, 0),                                                    //!< 3x3 search kernel
991                                                                                                                                 true,                                                                                   //!< fragments may end up over the viewport, just ignore them
992                                                                                                                                 tcu::COMPARE_LOG_RESULT);
993
994                 if (!imageOk)
995                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
996         }
997
998         return STOP;
999 }
1000
1001 void FeedbackPrimitiveTypeCase::renderWithFeedback(tcu::Surface& dst)
1002 {
1003         const glw::Functions&                   gl                                                      = m_context.getRenderContext().getFunctions();
1004         const glu::VertexArray                  vao                                                     (m_context.getRenderContext());
1005         const glu::Query                                primitivesGeneratedQuery        (m_context.getRenderContext());
1006         const int                                               posLocation                                     = gl.getAttribLocation(m_feedbackProgram->getProgram(), "a_position");
1007         const glw::GLenum                               feedbackPrimitiveMode           = getOutputPrimitiveGLType();
1008
1009         if (posLocation == -1)
1010                 throw tcu::TestError("a_position was -1");
1011
1012         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering with transform feedback" << tcu::TestLog::EndMessage;
1013
1014         gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1015         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1016         gl.clear(GL_COLOR_BUFFER_BIT);
1017         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1018
1019         gl.bindVertexArray(*vao);
1020         gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
1021         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1022         gl.enableVertexAttribArray(posLocation);
1023         GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
1024
1025         gl.useProgram(m_feedbackProgram->getProgram());
1026         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1027
1028         gl.patchParameteri(GL_PATCH_VERTICES, 4);
1029         GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1030
1031         gl.beginQuery(GL_PRIMITIVES_GENERATED, *primitivesGeneratedQuery);
1032         GLU_EXPECT_NO_ERROR(gl.getError(), "begin GL_PRIMITIVES_GENERATED query");
1033
1034         m_testCtx.getLog() << tcu::TestLog::Message << "Begin transform feedback with mode " << glu::getPrimitiveTypeStr(feedbackPrimitiveMode) << tcu::TestLog::EndMessage;
1035
1036         gl.beginTransformFeedback(feedbackPrimitiveMode);
1037         GLU_EXPECT_NO_ERROR(gl.getError(), "begin xfb");
1038
1039         m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
1040
1041         gl.drawArrays(GL_PATCHES, 0, 4);
1042         GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1043
1044         gl.endTransformFeedback();
1045         GLU_EXPECT_NO_ERROR(gl.getError(), "end xfb");
1046
1047         gl.endQuery(GL_PRIMITIVES_GENERATED);
1048         GLU_EXPECT_NO_ERROR(gl.getError(), "end GL_PRIMITIVES_GENERATED query");
1049
1050         glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1051         GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
1052
1053         // verify GL_PRIMITIVES_GENERATED
1054         {
1055                 glw::GLuint primitivesGeneratedResult = 0;
1056                 gl.getQueryObjectuiv(*primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGeneratedResult);
1057                 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_PRIMITIVES_GENERATED value");
1058
1059                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying GL_PRIMITIVES_GENERATED, expecting " << getNumGeneratedPrimitives() << tcu::TestLog::EndMessage;
1060
1061                 if ((int)primitivesGeneratedResult != getNumGeneratedPrimitives())
1062                 {
1063                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, GL_PRIMITIVES_GENERATED was " << primitivesGeneratedResult << tcu::TestLog::EndMessage;
1064                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected GL_PRIMITIVES_GENERATED");
1065                 }
1066                 else
1067                         m_testCtx.getLog() << tcu::TestLog::Message << "GL_PRIMITIVES_GENERATED valid." << tcu::TestLog::EndMessage;
1068         }
1069
1070         // feedback
1071         {
1072                 std::vector<tcu::Vec4>  feedbackResults         (getNumGeneratedElementsPerPrimitive() * getNumGeneratedPrimitives());
1073                 const void*                             mappedPtr                       = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (glw::GLsizeiptr)(feedbackResults.size() * sizeof(tcu::Vec4)), GL_MAP_READ_BIT);
1074                 glw::GLboolean                  unmapResult;
1075
1076                 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
1077
1078                 m_testCtx.getLog() << tcu::TestLog::Message << "Reading transform feedback buffer." << tcu::TestLog::EndMessage;
1079                 if (!mappedPtr)
1080                         throw tcu::TestError("mapBufferRange returned null");
1081
1082                 deMemcpy(feedbackResults[0].getPtr(), mappedPtr, (int)(feedbackResults.size() * sizeof(tcu::Vec4)));
1083
1084                 unmapResult = gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1085                 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer");
1086
1087                 if (unmapResult != GL_TRUE)
1088                         throw tcu::TestError("unmapBuffer failed, did not return true");
1089
1090                 // verify transform results
1091                 verifyFeedbackResults(feedbackResults);
1092
1093                 // verify feedback results are consistent with rendered image
1094                 verifyRenderedImage(dst, feedbackResults);
1095         }
1096 }
1097
1098 void FeedbackPrimitiveTypeCase::renderWithoutFeedback (tcu::Surface& dst)
1099 {
1100         const glw::Functions&                   gl                                                      = m_context.getRenderContext().getFunctions();
1101         const glu::VertexArray                  vao                                                     (m_context.getRenderContext());
1102         const int                                               posLocation                                     = gl.getAttribLocation(m_nonFeedbackProgram->getProgram(), "a_position");
1103
1104         if (posLocation == -1)
1105                 throw tcu::TestError("a_position was -1");
1106
1107         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering without transform feedback" << tcu::TestLog::EndMessage;
1108
1109         gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1110         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1111         gl.clear(GL_COLOR_BUFFER_BIT);
1112         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1113
1114         gl.bindVertexArray(*vao);
1115         gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
1116         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1117         gl.enableVertexAttribArray(posLocation);
1118         GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
1119
1120         gl.useProgram(m_nonFeedbackProgram->getProgram());
1121         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1122
1123         gl.patchParameteri(GL_PATCH_VERTICES, 4);
1124         GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1125
1126         m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
1127
1128         gl.drawArrays(GL_PATCHES, 0, 4);
1129         GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1130
1131         glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1132         GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
1133 }
1134
1135 void FeedbackPrimitiveTypeCase::verifyFeedbackResults (const std::vector<tcu::Vec4>& feedbackResult)
1136 {
1137         const int       geometryAmplification   = getGeometryAmplification();
1138         const int       elementsPerPrimitive    = getNumGeneratedElementsPerPrimitive();
1139         const int       errorFloodThreshold             = 8;
1140         int                     readNdx                                 = 0;
1141         int                     numErrors                               = 0;
1142
1143         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying feedback results." << tcu::TestLog::EndMessage;
1144
1145         for (int tessellatedPrimitiveNdx = 0; tessellatedPrimitiveNdx < getNumTessellatedPrimitives(); ++tessellatedPrimitiveNdx)
1146         {
1147                 const tcu::Vec4 primitiveVertex = feedbackResult[readNdx];
1148
1149                 // check the generated vertices are in the proper range (range: -0.4 <-> 0.4)
1150                 {
1151                         const float     equalThreshold  =       1.0e-6f;
1152                         const bool      centroidOk              =       (primitiveVertex.x() >= -0.4f - equalThreshold) &&
1153                                                                                         (primitiveVertex.x() <=  0.4f + equalThreshold) &&
1154                                                                                         (primitiveVertex.y() >= -0.4f - equalThreshold) &&
1155                                                                                         (primitiveVertex.y() <=  0.4f + equalThreshold) &&
1156                                                                                         (de::abs(primitiveVertex.z()) < equalThreshold) &&
1157                                                                                         (de::abs(primitiveVertex.w() - 1.0f) < equalThreshold);
1158
1159                         if (!centroidOk && numErrors++ < errorFloodThreshold)
1160                         {
1161                                 m_testCtx.getLog()
1162                                         << tcu::TestLog::Message
1163                                         << "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ")\n"
1164                                         << "\texpected vertex in range: ( [-0.4, 0.4], [-0.4, 0.4], 0.0, 1.0 )\n"
1165                                         << "\tgot: " << primitiveVertex
1166                                         << tcu::TestLog::EndMessage;
1167
1168                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid feedback output");
1169
1170                                 ++readNdx;
1171                                 continue;
1172                         }
1173                 }
1174
1175                 // check all other primitives generated from this tessellated primitive have the same feedback value
1176                 for (int generatedPrimitiveNdx = 0; generatedPrimitiveNdx < geometryAmplification; ++generatedPrimitiveNdx)
1177                 for (int primitiveVertexNdx = 0; primitiveVertexNdx < elementsPerPrimitive; ++primitiveVertexNdx)
1178                 {
1179                         const tcu::Vec4 generatedElementVertex  = feedbackResult[readNdx];
1180                         const tcu::Vec4 equalThreshold                  (1.0e-6f);
1181
1182                         if (tcu::boolAny(tcu::greaterThan(tcu::abs(primitiveVertex - generatedElementVertex), equalThreshold)))
1183                         {
1184                                 if (numErrors++ < errorFloodThreshold)
1185                                 {
1186                                         m_testCtx.getLog()
1187                                                 << tcu::TestLog::Message
1188                                                 << "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ", geometry primitive " << generatedPrimitiveNdx << ", emitted vertex " << primitiveVertexNdx << "):\n"
1189                                                 << "\tfeedback result was not contant over whole primitive.\n"
1190                                                 << "\tfirst emitted value: " << primitiveVertex << "\n"
1191                                                 << "\tcurrent emitted value:" << generatedElementVertex << "\n"
1192                                                 << tcu::TestLog::EndMessage;
1193                                 }
1194
1195                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got multiple different feedback values for a single primitive");
1196                         }
1197
1198                         readNdx++;
1199                 }
1200         }
1201
1202         if (numErrors > errorFloodThreshold)
1203                 m_testCtx.getLog() << tcu::TestLog::Message << "Omitted " << (numErrors - errorFloodThreshold) << " error(s)." << tcu::TestLog::EndMessage;
1204 }
1205
1206 static bool feedbackResultCompare (const tcu::Vec4& a, const tcu::Vec4& b)
1207 {
1208         if (a.x() < b.x())
1209                 return true;
1210         if (a.x() > b.x())
1211                 return false;
1212
1213         return a.y() < b.y();
1214 }
1215
1216 void FeedbackPrimitiveTypeCase::verifyRenderedImage (const tcu::Surface& image, const std::vector<tcu::Vec4>& tfVertices)
1217 {
1218         std::vector<tcu::Vec4> vertices;
1219
1220         m_testCtx.getLog() << tcu::TestLog::Message << "Comparing result image against feedback results." << tcu::TestLog::EndMessage;
1221
1222         // Check only unique vertices
1223         std::unique_copy(tfVertices.begin(), tfVertices.end(), std::back_insert_iterator<std::vector<tcu::Vec4> >(vertices));
1224         std::sort(vertices.begin(), vertices.end(), feedbackResultCompare);
1225         vertices.erase(std::unique(vertices.begin(), vertices.end()), vertices.end());
1226
1227         // Verifying vertices recorded with feedback actually ended up on the result image
1228         for (int ndx = 0; ndx < (int)vertices.size(); ++ndx)
1229         {
1230                 // Rasterization (of lines) may deviate by one pixel. In addition to that, allow minimal errors in rasterized position vs. feedback result.
1231                 // This minimal error could result in a difference in rounding => allow one additional pixel in deviation
1232
1233                 const int                       rasterDeviation = 2;
1234                 const tcu::IVec2        rasterPos               ((int)deFloatRound((vertices[ndx].x() * 0.5f + 0.5f) * image.getWidth()), (int)deFloatRound((vertices[ndx].y() * 0.5f + 0.5f) * image.getHeight()));
1235
1236                 // Find produced rasterization results
1237                 bool                            found                   = false;
1238
1239                 for (int dy = -rasterDeviation; dy <= rasterDeviation && !found; ++dy)
1240                 for (int dx = -rasterDeviation; dx <= rasterDeviation && !found; ++dx)
1241                 {
1242                         // Raster result could end up outside the viewport
1243                         if (rasterPos.x() + dx < 0 || rasterPos.x() + dx >= image.getWidth() ||
1244                                 rasterPos.y() + dy < 0 || rasterPos.y() + dy >= image.getHeight())
1245                                 found = true;
1246                         else
1247                         {
1248                                 const tcu::RGBA result = image.getPixel(rasterPos.x() + dx, rasterPos.y() + dy);
1249
1250                                 if(!isBlack(result))
1251                                         found = true;
1252                         }
1253                 }
1254
1255                 if (!found)
1256                 {
1257                         m_testCtx.getLog()
1258                                 << tcu::TestLog::Message
1259                                 << "Vertex " << vertices[ndx] << "\n"
1260                                 << "\tCould not find rasterization output for vertex.\n"
1261                                 << "\tExpected non-black pixels near " << rasterPos
1262                                 << tcu::TestLog::EndMessage;
1263
1264                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid result image");
1265                 }
1266         }
1267 }
1268
1269 void FeedbackPrimitiveTypeCase::genTransformFeedback (void)
1270 {
1271         const glw::Functions&                   gl                                              = m_context.getRenderContext().getFunctions();
1272         const int                                               elementsPerPrimitive    = getNumGeneratedElementsPerPrimitive();
1273         const int                                               feedbackPrimitives              = getNumGeneratedPrimitives();
1274         const int                                               feedbackElements                = elementsPerPrimitive * feedbackPrimitives;
1275         const std::vector<tcu::Vec4>    initialBuffer                   (feedbackElements, tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f));
1276
1277         gl.genTransformFeedbacks(1, &m_feedbackID);
1278         gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_feedbackID);
1279         GLU_EXPECT_NO_ERROR(gl.getError(), "gen transform feedback");
1280
1281         gl.genBuffers(1, &m_feedbackBuffer);
1282         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuffer);
1283         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(tcu::Vec4) * initialBuffer.size(), initialBuffer[0].getPtr(), GL_STATIC_COPY);
1284         GLU_EXPECT_NO_ERROR(gl.getError(), "gen feedback buffer");
1285
1286         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuffer);
1287         GLU_EXPECT_NO_ERROR(gl.getError(), "bind feedback buffer");
1288 }
1289
1290 static int getTriangleNumOutputPrimitives (int tessellationLevel)
1291 {
1292         if (tessellationLevel == 1)
1293                 return 1;
1294         else if (tessellationLevel == 2)
1295                 return 6;
1296         else
1297                 return 3 * (2 + 2 * (tessellationLevel - 2)) + getTriangleNumOutputPrimitives(tessellationLevel - 2);
1298 }
1299
1300 static int getTriangleNumOutputPrimitivesPoints (int tessellationLevel)
1301 {
1302         if (tessellationLevel == 0)
1303                 return 1;
1304         else if (tessellationLevel == 1)
1305                 return 3;
1306         else
1307                 return 3 + 3 * (tessellationLevel - 1) + getTriangleNumOutputPrimitivesPoints(tessellationLevel - 2);
1308 }
1309
1310 int FeedbackPrimitiveTypeCase::getNumGeneratedElementsPerPrimitive (void) const
1311 {
1312         if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
1313                 return 3;
1314         else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
1315                 return 2;
1316         else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
1317                 return 1;
1318         else
1319         {
1320                 DE_ASSERT(false);
1321                 return -1;
1322         }
1323 }
1324
1325 int FeedbackPrimitiveTypeCase::getNumGeneratedPrimitives (void) const
1326 {
1327         return getNumTessellatedPrimitives() * getGeometryAmplification();
1328 }
1329
1330 int FeedbackPrimitiveTypeCase::getNumTessellatedPrimitives (void) const
1331 {
1332         const int tessellationLevel = 3;
1333
1334         if (m_tessellationPointMode == TESSELLATION_POINTMODE_OFF)
1335         {
1336                 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1337                         return getTriangleNumOutputPrimitives(tessellationLevel);
1338                 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1339                         return tessellationLevel * tessellationLevel * 2; // tessellated as triangles
1340                 else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1341                         return tessellationLevel * tessellationLevel;
1342         }
1343         else if (m_tessellationPointMode == TESSELLATION_POINTMODE_ON)
1344         {
1345                 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1346                         return getTriangleNumOutputPrimitivesPoints(tessellationLevel);
1347                 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1348                         return (tessellationLevel + 1) * (tessellationLevel + 1);
1349                 else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1350                         return tessellationLevel * (tessellationLevel + 1);
1351         }
1352
1353         DE_ASSERT(false);
1354         return -1;
1355 }
1356
1357 int FeedbackPrimitiveTypeCase::getGeometryAmplification (void) const
1358 {
1359         const int outputAmplification   = (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (2) : (1);
1360         const int numInputVertices              = (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
1361
1362         return outputAmplification * numInputVertices;
1363 }
1364
1365 glw::GLenum FeedbackPrimitiveTypeCase::getOutputPrimitiveGLType (void) const
1366 {
1367         if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
1368                 return GL_TRIANGLES;
1369         else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
1370                 return GL_LINES;
1371         else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
1372                 return GL_POINTS;
1373         else
1374         {
1375                 DE_ASSERT(false);
1376                 return -1;
1377         }
1378 }
1379
1380 const char* FeedbackPrimitiveTypeCase::getVertexSource (void) const
1381 {
1382         return s_positionVertexShader;
1383 }
1384
1385 const char* FeedbackPrimitiveTypeCase::getFragmentSource (void) const
1386 {
1387         return s_whiteOutputFragmentShader;
1388 }
1389
1390 std::string FeedbackPrimitiveTypeCase::getTessellationControlSource (void) const
1391 {
1392         std::ostringstream buf;
1393
1394         buf <<  "#version 310 es\n"
1395                         "#extension GL_EXT_tessellation_shader : require\n"
1396                         "layout(vertices = 9) out;\n"
1397                         "\n"
1398                         "uniform highp float u_innerTessellationLevel;\n"
1399                         "uniform highp float u_outerTessellationLevel;\n"
1400                         "\n"
1401                         "void main (void)\n"
1402                         "{\n"
1403                         "       if (gl_PatchVerticesIn != 4)\n"
1404                         "               return;\n"
1405                         "\n"
1406                         "       // Convert input 2x2 grid to 3x3 grid\n"
1407                         "       float xweight = float(gl_InvocationID % 3) / 2.0f;\n"
1408                         "       float yweight = float(gl_InvocationID / 3) / 2.0f;\n"
1409                         "\n"
1410                         "       vec4 y0 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, yweight);\n"
1411                         "       vec4 y1 = mix(gl_in[2].gl_Position, gl_in[3].gl_Position, yweight);\n"
1412                         "\n"
1413                         "       gl_out[gl_InvocationID].gl_Position = mix(y0, y1, xweight);\n"
1414                         "\n";
1415
1416         if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1417                 buf <<  "       gl_TessLevelOuter[0] = 3.0;\n"
1418                                 "       gl_TessLevelOuter[1] = 3.0;\n"
1419                                 "       gl_TessLevelOuter[2] = 3.0;\n"
1420                                 "       gl_TessLevelInner[0] = 3.0;\n";
1421         else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1422                 buf <<  "       gl_TessLevelOuter[0] = 3.0;\n"
1423                                 "       gl_TessLevelOuter[1] = 3.0;\n"
1424                                 "       gl_TessLevelOuter[2] = 3.0;\n"
1425                                 "       gl_TessLevelOuter[3] = 3.0;\n"
1426                                 "       gl_TessLevelInner[0] = 3.0;\n"
1427                                 "       gl_TessLevelInner[1] = 3.0;\n";
1428         else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1429                 buf <<  "       gl_TessLevelOuter[0] = 3.0;\n"
1430                                 "       gl_TessLevelOuter[1] = 3.0;\n";
1431         else
1432                 DE_ASSERT(false);
1433
1434         buf <<  "}\n";
1435
1436         return buf.str();
1437 }
1438
1439 std::string FeedbackPrimitiveTypeCase::getTessellationEvaluationSource (void) const
1440 {
1441         std::ostringstream buf;
1442
1443         buf <<  "#version 310 es\n"
1444                         "#extension GL_EXT_tessellation_shader : require\n"
1445                         "layout("
1446                                 << ((m_tessellationOutput == TESSELLATION_OUT_TRIANGLES) ? ("triangles") : (m_tessellationOutput == TESSELLATION_OUT_QUADS) ? ("quads") : ("isolines"))
1447                                 << ((m_tessellationPointMode) ? (", point_mode") : (""))
1448                                 << ") in;\n"
1449                         "\n"
1450                         "out highp vec4 v_tessellationCoords;\n"
1451                         "\n"
1452                         "void main (void)\n"
1453                         "{\n"
1454                         "       if (gl_PatchVerticesIn != 9)\n"
1455                         "               return;\n"
1456                         "\n"
1457                         "       vec4 patchCentroid = vec4(0.0);\n"
1458                         "       for (int ndx = 0; ndx < gl_PatchVerticesIn; ++ndx)\n"
1459                         "               patchCentroid += gl_in[ndx].gl_Position;\n"
1460                         "       patchCentroid /= patchCentroid.w;\n"
1461                         "\n";
1462
1463         if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1464                 buf <<  "       // map barycentric coords to 2d coords\n"
1465                                 "       const vec3 tessDirX = vec3( 0.4,  0.4, 0.0);\n"
1466                                 "       const vec3 tessDirY = vec3( 0.0, -0.4, 0.0);\n"
1467                                 "       const vec3 tessDirZ = vec3(-0.4,  0.4, 0.0);\n"
1468                                 "       gl_Position = patchCentroid + vec4(gl_TessCoord.x * tessDirX + gl_TessCoord.y * tessDirY + gl_TessCoord.z * tessDirZ, 0.0);\n";
1469         else if (m_tessellationOutput == TESSELLATION_OUT_QUADS || m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1470                 buf <<  "       gl_Position = patchCentroid + vec4(gl_TessCoord.x * 0.8 - 0.4, gl_TessCoord.y * 0.8 - 0.4, 0.0, 0.0);\n";
1471         else
1472                 DE_ASSERT(false);
1473
1474         buf <<  "       v_tessellationCoords = vec4(gl_TessCoord, 0.0);\n"
1475                         "}\n";
1476
1477         return buf.str();
1478 }
1479
1480 std::string FeedbackPrimitiveTypeCase::getGeometrySource (void) const
1481 {
1482         const char* const       geometryInputPrimitive                  = (m_tessellationPointMode) ? ("points") : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? ("lines") : ("triangles");
1483         const char* const       geometryOutputPrimitive                 = (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? ("points") : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? ("line_strip") : ("triangle_strip");
1484         const int                       numInputVertices                                = (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
1485         const int                       numSingleVertexOutputVertices   = (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? (1) : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (4) : (3);
1486         const int                       numEmitVertices                                 = numInputVertices * numSingleVertexOutputVertices;
1487         std::ostringstream      buf;
1488
1489         buf <<  "#version 310 es\n"
1490                         "#extension GL_EXT_geometry_shader : require\n"
1491                         "layout(" << geometryInputPrimitive << ") in;\n"
1492                         "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
1493                         "\n"
1494                         "in highp vec4 v_tessellationCoords[];\n"
1495                         "out highp vec4 tf_someVertexPosition;\n"
1496                         "\n"
1497                         "void main (void)\n"
1498                         "{\n"
1499                         "       // Emit primitive\n"
1500                         "       for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
1501                         "       {\n";
1502
1503         switch (m_geometryOutputType)
1504         {
1505                 case GEOMETRY_OUTPUT_POINTS:
1506                         buf <<  "               // Draw point on vertex\n"
1507                                         "               gl_Position = gl_in[ndx].gl_Position;\n"
1508                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1509                                         "               EmitVertex();\n";
1510                         break;
1511
1512                 case GEOMETRY_OUTPUT_LINES:
1513                         buf <<  "               // Draw cross on vertex\n"
1514                                         "               gl_Position = gl_in[ndx].gl_Position + vec4(-0.02, -0.02, 0.0, 0.0);\n"
1515                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1516                                         "               EmitVertex();\n"
1517                                         "               gl_Position = gl_in[ndx].gl_Position + vec4( 0.02,  0.02, 0.0, 0.0);\n"
1518                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1519                                         "               EmitVertex();\n"
1520                                         "               EndPrimitive();\n"
1521                                         "               gl_Position = gl_in[ndx].gl_Position + vec4( 0.02, -0.02, 0.0, 0.0);\n"
1522                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1523                                         "               EmitVertex();\n"
1524                                         "               gl_Position = gl_in[ndx].gl_Position + vec4(-0.02,  0.02, 0.0, 0.0);\n"
1525                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1526                                         "               EmitVertex();\n"
1527                                         "               EndPrimitive();\n";
1528                         break;
1529
1530                 case GEOMETRY_OUTPUT_TRIANGLES:
1531                         buf <<  "               // Draw triangle on vertex\n"
1532                                         "               gl_Position = gl_in[ndx].gl_Position + vec4(  0.00, -0.02, 0.0, 0.0);\n"
1533                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1534                                         "               EmitVertex();\n"
1535                                         "               gl_Position = gl_in[ndx].gl_Position + vec4(  0.02,  0.00, 0.0, 0.0);\n"
1536                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1537                                         "               EmitVertex();\n"
1538                                         "               gl_Position = gl_in[ndx].gl_Position + vec4( -0.02,  0.00, 0.0, 0.0);\n"
1539                                         "               tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1540                                         "               EmitVertex();\n"
1541                                         "               EndPrimitive();\n";
1542                         break;
1543
1544                 default:
1545                         DE_ASSERT(false);
1546                         return "";
1547         }
1548
1549         buf <<  "       }\n"
1550                         "}\n";
1551
1552         return buf.str();
1553 }
1554
1555 const char* FeedbackPrimitiveTypeCase::getTessellationOutputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
1556 {
1557         switch (tessellationOutput)
1558         {
1559                 case TESSELLATION_OUT_TRIANGLES:        return (pointMode) ? ("points (triangles in point mode)") : ("triangles");
1560                 case TESSELLATION_OUT_QUADS:            return (pointMode) ? ("points (quads in point mode)")     : ("quads");
1561                 case TESSELLATION_OUT_ISOLINES:         return (pointMode) ? ("points (isolines in point mode)")  : ("isolines");
1562                 default:
1563                         DE_ASSERT(false);
1564                         return DE_NULL;
1565         }
1566 }
1567
1568 const char* FeedbackPrimitiveTypeCase::getGeometryInputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
1569 {
1570         switch (tessellationOutput)
1571         {
1572                 case TESSELLATION_OUT_TRIANGLES:        return (pointMode) ? ("points") : ("triangles");
1573                 case TESSELLATION_OUT_QUADS:            return (pointMode) ? ("points") : ("triangles");
1574                 case TESSELLATION_OUT_ISOLINES:         return (pointMode) ? ("points") : ("lines");
1575                 default:
1576                         DE_ASSERT(false);
1577                         return DE_NULL;
1578         }
1579 }
1580
1581 const char* FeedbackPrimitiveTypeCase::getGeometryOutputDescription (GeometryOutputType geometryOutput)
1582 {
1583         switch (geometryOutput)
1584         {
1585                 case GEOMETRY_OUTPUT_POINTS:            return "points";
1586                 case GEOMETRY_OUTPUT_LINES:                     return "lines";
1587                 case GEOMETRY_OUTPUT_TRIANGLES:         return "triangles";
1588                 default:
1589                         DE_ASSERT(false);
1590                         return DE_NULL;
1591         }
1592 }
1593
1594 class PointSizeCase : public TestCase
1595 {
1596 public:
1597         enum Flags
1598         {
1599                 FLAG_VERTEX_SET                                         = 0x01,         // !< set gl_PointSize in vertex shader
1600                 FLAG_TESSELLATION_CONTROL_SET           = 0x02,         // !< set gl_PointSize in tessellation evaluation shader
1601                 FLAG_TESSELLATION_EVALUATION_SET        = 0x04,         // !< set gl_PointSize in tessellation control shader
1602                 FLAG_TESSELLATION_ADD                           = 0x08,         // !< read and add to gl_PointSize in tessellation shader pair
1603                 FLAG_TESSELLATION_DONT_SET                      = 0x10,         // !< don't set gl_PointSize in tessellation shader
1604                 FLAG_GEOMETRY_SET                                       = 0x20,         // !< set gl_PointSize in geometry shader
1605                 FLAG_GEOMETRY_ADD                                       = 0x40,         // !< read and add to gl_PointSize in geometry shader
1606                 FLAG_GEOMETRY_DONT_SET                          = 0x80,         // !< don't set gl_PointSize in geometry shader
1607         };
1608
1609                                                 PointSizeCase                                   (Context& context, const char* name, const char* description, int flags);
1610                                                 ~PointSizeCase                                  (void);
1611
1612         static std::string      genTestCaseName                                 (int flags);
1613         static std::string      genTestCaseDescription                  (int flags);
1614
1615 private:
1616         void                            init                                                    (void);
1617         void                            deinit                                                  (void);
1618         IterateResult           iterate                                                 (void);
1619
1620         void                            checkExtensions                                 (void) const;
1621         void                            checkPointSizeRequirements              (void) const;
1622
1623         void                            renderTo                                                (tcu::Surface& dst);
1624         bool                            verifyImage                                             (const tcu::Surface& src);
1625         int                                     getExpectedPointSize                    (void) const;
1626
1627         std::string                     genVertexSource                                 (void) const;
1628         const char*                     genFragmentSource                               (void) const;
1629         std::string                     genTessellationControlSource    (void) const;
1630         std::string                     genTessellationEvaluationSource (void) const;
1631         std::string                     genGeometrySource                               (void) const;
1632
1633         enum
1634         {
1635                 RENDER_SIZE = 32,
1636         };
1637
1638         const int                       m_flags;
1639         glu::ShaderProgram*     m_program;
1640 };
1641
1642 PointSizeCase::PointSizeCase (Context& context, const char* name, const char* description, int flags)
1643         : TestCase      (context, name, description)
1644         , m_flags       (flags)
1645         , m_program     (DE_NULL)
1646 {
1647 }
1648
1649 PointSizeCase::~PointSizeCase (void)
1650 {
1651         deinit();
1652 }
1653
1654 std::string PointSizeCase::genTestCaseName (int flags)
1655 {
1656         std::ostringstream buf;
1657
1658         // join per-bit descriptions into a single string with '_' separator
1659         if (flags & FLAG_VERTEX_SET)                                    buf                                                                                                                                             << "vertex_set";
1660         if (flags & FLAG_TESSELLATION_CONTROL_SET)              buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))             ? ("_") : ("")) << "control_set";
1661         if (flags & FLAG_TESSELLATION_EVALUATION_SET)   buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))  ? ("_") : ("")) << "evaluation_set";
1662         if (flags & FLAG_TESSELLATION_ADD)                              buf << ((flags & (FLAG_TESSELLATION_ADD-1))                             ? ("_") : ("")) << "control_pass_eval_add";
1663         if (flags & FLAG_TESSELLATION_DONT_SET)                 buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))                ? ("_") : ("")) << "eval_default";
1664         if (flags & FLAG_GEOMETRY_SET)                                  buf << ((flags & (FLAG_GEOMETRY_SET-1))                                 ? ("_") : ("")) << "geometry_set";
1665         if (flags & FLAG_GEOMETRY_ADD)                                  buf << ((flags & (FLAG_GEOMETRY_ADD-1))                                 ? ("_") : ("")) << "geometry_add";
1666         if (flags & FLAG_GEOMETRY_DONT_SET)                             buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))                    ? ("_") : ("")) << "geometry_default";
1667
1668         return buf.str();
1669 }
1670
1671 std::string PointSizeCase::genTestCaseDescription (int flags)
1672 {
1673         std::ostringstream buf;
1674
1675         // join per-bit descriptions into a single string with ", " separator
1676         if (flags & FLAG_VERTEX_SET)                                    buf                                                                                                                                                     << "set point size in vertex shader";
1677         if (flags & FLAG_TESSELLATION_CONTROL_SET)              buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))             ? (", ") : (""))        << "set point size in tessellation control shader";
1678         if (flags & FLAG_TESSELLATION_EVALUATION_SET)   buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))  ? (", ") : (""))        << "set point size in tessellation evaluation shader";
1679         if (flags & FLAG_TESSELLATION_ADD)                              buf << ((flags & (FLAG_TESSELLATION_ADD-1))                             ? (", ") : (""))        << "add to point size in tessellation shader";
1680         if (flags & FLAG_TESSELLATION_DONT_SET)                 buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))                ? (", ") : (""))        << "don't set point size in tessellation evaluation shader";
1681         if (flags & FLAG_GEOMETRY_SET)                                  buf << ((flags & (FLAG_GEOMETRY_SET-1))                                 ? (", ") : (""))        << "set point size in geometry shader";
1682         if (flags & FLAG_GEOMETRY_ADD)                                  buf << ((flags & (FLAG_GEOMETRY_ADD-1))                                 ? (", ") : (""))        << "add to point size in geometry shader";
1683         if (flags & FLAG_GEOMETRY_DONT_SET)                             buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))                    ? (", ") : (""))        << "don't set point size in geometry shader";
1684
1685         return buf.str();
1686 }
1687
1688 void PointSizeCase::init (void)
1689 {
1690         checkExtensions();
1691         checkPointSizeRequirements();
1692
1693         // log
1694
1695         if (m_flags & FLAG_VERTEX_SET)
1696                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
1697         if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
1698                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation control shader to 4.0. (And ignoring it in evaluation)." << tcu::TestLog::EndMessage;
1699         if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
1700                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
1701         if (m_flags & FLAG_TESSELLATION_ADD)
1702                 m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
1703         if (m_flags & FLAG_TESSELLATION_DONT_SET)
1704                 m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in tessellation evaluation shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
1705         if (m_flags & FLAG_GEOMETRY_SET)
1706                 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
1707         if (m_flags & FLAG_GEOMETRY_ADD)
1708                 m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
1709         if (m_flags & FLAG_GEOMETRY_DONT_SET)
1710                 m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in geometry shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
1711
1712         // program
1713
1714         {
1715                 glu::ProgramSources sources;
1716                 sources << glu::VertexSource(genVertexSource())
1717                                 << glu::FragmentSource(genFragmentSource());
1718
1719                 if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
1720                         sources << glu::TessellationControlSource(genTessellationControlSource())
1721                                         << glu::TessellationEvaluationSource(genTessellationEvaluationSource());
1722
1723                 if (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET))
1724                         sources << glu::GeometrySource(genGeometrySource());
1725
1726                 m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
1727
1728                 m_testCtx.getLog() << *m_program;
1729                 if (!m_program->isOk())
1730                         throw tcu::TestError("failed to build program");
1731         }
1732 }
1733
1734 void PointSizeCase::deinit (void)
1735 {
1736         delete m_program;
1737         m_program = DE_NULL;
1738 }
1739
1740 PointSizeCase::IterateResult PointSizeCase::iterate (void)
1741 {
1742         tcu::Surface resultImage(RENDER_SIZE, RENDER_SIZE);
1743
1744         renderTo(resultImage);
1745
1746         if (verifyImage(resultImage))
1747                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1748         else
1749                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1750
1751         return STOP;
1752 }
1753
1754 void PointSizeCase::checkExtensions (void) const
1755 {
1756         std::vector<std::string>        requiredExtensions;
1757         bool                                            allOk                           = true;
1758
1759         if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
1760                 requiredExtensions.push_back("GL_EXT_tessellation_shader");
1761
1762         if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD))
1763                 requiredExtensions.push_back("GL_EXT_tessellation_point_size");
1764
1765         if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET)))
1766                 requiredExtensions.push_back("GL_EXT_geometry_shader");
1767
1768         if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD)))
1769                 requiredExtensions.push_back("GL_EXT_geometry_point_size");
1770
1771         for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
1772                 if (!m_context.getContextInfo().isExtensionSupported(requiredExtensions[ndx].c_str()))
1773                         allOk = false;
1774
1775         if (!allOk)
1776         {
1777                 std::ostringstream extensionList;
1778
1779                 for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
1780                 {
1781                         if (ndx != 0)
1782                                 extensionList << ", ";
1783                         extensionList << requiredExtensions[ndx];
1784                 }
1785
1786                 throw tcu::NotSupportedError("Test requires {" + extensionList.str() + "} extension(s)");
1787         }
1788 }
1789
1790 void PointSizeCase::checkPointSizeRequirements (void) const
1791 {
1792         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
1793         float                                   aliasedSizeRange[2]     = { 0.0f, 0.0f };
1794         const int                               requiredSize            = getExpectedPointSize();
1795
1796         gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, aliasedSizeRange);
1797
1798         if (float(requiredSize) > aliasedSizeRange[1])
1799                 throw tcu::NotSupportedError("Test requires point size " + de::toString(requiredSize));
1800 }
1801
1802 void PointSizeCase::renderTo (tcu::Surface& dst)
1803 {
1804         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
1805         const bool                              tessellationActive      = (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET)) != 0;
1806         const int                               positionLocation        = gl.getAttribLocation(m_program->getProgram(), "a_position");
1807         const glu::VertexArray  vao                                     (m_context.getRenderContext());
1808
1809         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point." << tcu::TestLog::EndMessage;
1810
1811         if (positionLocation == -1)
1812                 throw tcu::TestError("Attribute a_position location was -1");
1813
1814         gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
1815         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1816         gl.clear(GL_COLOR_BUFFER_BIT);
1817         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1818
1819         gl.bindVertexArray(*vao);
1820         GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
1821
1822         gl.useProgram(m_program->getProgram());
1823         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1824
1825         gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
1826
1827         if (tessellationActive)
1828         {
1829                 gl.patchParameteri(GL_PATCH_VERTICES, 1);
1830                 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1831
1832                 gl.drawArrays(GL_PATCHES, 0, 1);
1833                 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1834         }
1835         else
1836         {
1837                 gl.drawArrays(GL_POINTS, 0, 1);
1838                 GLU_EXPECT_NO_ERROR(gl.getError(), "draw points");
1839         }
1840
1841         glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1842 }
1843
1844 bool PointSizeCase::verifyImage (const tcu::Surface& src)
1845 {
1846         const bool MSAATarget   = (m_context.getRenderTarget().getNumSamples() > 1);
1847         const int expectedSize  = getExpectedPointSize();
1848
1849         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
1850         m_testCtx.getLog() << tcu::TestLog::Image("RenderImage", "Rendered image", src.getAccess());
1851
1852         {
1853                 bool            resultAreaFound = false;
1854                 tcu::IVec4      resultArea;
1855
1856                 // Find rasterization output area
1857
1858                 for (int y = 0; y < src.getHeight(); ++y)
1859                 for (int x = 0; x < src.getWidth();  ++x)
1860                 {
1861                         if (!isBlack(src.getPixel(x, y)))
1862                         {
1863                                 if (!resultAreaFound)
1864                                 {
1865                                         // first fragment
1866                                         resultArea = tcu::IVec4(x, y, x + 1, y + 1);
1867                                         resultAreaFound = true;
1868                                 }
1869                                 else
1870                                 {
1871                                         // union area
1872                                         resultArea.x() = de::min(resultArea.x(), x);
1873                                         resultArea.y() = de::min(resultArea.y(), y);
1874                                         resultArea.z() = de::max(resultArea.z(), x+1);
1875                                         resultArea.w() = de::max(resultArea.w(), y+1);
1876                                 }
1877                         }
1878                 }
1879
1880                 if (!resultAreaFound)
1881                 {
1882                         m_testCtx.getLog() << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
1883                         return false;
1884                 }
1885
1886                 // verify area size
1887                 if (MSAATarget)
1888                 {
1889                         const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
1890
1891                         // MSAA: edges may be a little fuzzy
1892                         if (de::abs(pointSize.x() - pointSize.y()) > 1)
1893                         {
1894                                 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Detected point size was " << pointSize << tcu::TestLog::EndMessage;
1895                                 return false;
1896                         }
1897
1898                         // MSAA may produce larger areas, allow one pixel larger
1899                         if (expectedSize != de::max(pointSize.x(), pointSize.y()) && (expectedSize+1) != de::max(pointSize.x(), pointSize.y()))
1900                         {
1901                                 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << de::max(pointSize.x(), pointSize.y()) << tcu::TestLog::EndMessage;
1902                                 return false;
1903                         }
1904                 }
1905                 else
1906                 {
1907                         const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
1908
1909                         if (pointSize.x() != pointSize.y())
1910                         {
1911                                 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
1912                                 return false;
1913                         }
1914
1915                         if (pointSize.x() != expectedSize)
1916                         {
1917                                 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
1918                                 return false;
1919                         }
1920                 }
1921         }
1922
1923         return true;
1924 }
1925
1926 int PointSizeCase::getExpectedPointSize (void) const
1927 {
1928         int addition = 0;
1929
1930         // geometry
1931         if (m_flags & FLAG_GEOMETRY_DONT_SET)
1932                 return 1;
1933         else if (m_flags & FLAG_GEOMETRY_SET)
1934                 return 6;
1935         else if (m_flags & FLAG_GEOMETRY_ADD)
1936                 addition += 2;
1937
1938         // tessellation
1939         if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
1940                 return 4 + addition;
1941         else if (m_flags & FLAG_TESSELLATION_ADD)
1942                 addition += 2;
1943         else if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_DONT_SET))
1944         {
1945                 DE_ASSERT((m_flags & FLAG_GEOMETRY_ADD) == 0); // reading pointSize undefined
1946                 return 1;
1947         }
1948
1949         // vertex
1950         if (m_flags & FLAG_VERTEX_SET)
1951                 return 2 + addition;
1952
1953         // undefined
1954         DE_ASSERT(false);
1955         return -1;
1956 }
1957
1958 std::string PointSizeCase::genVertexSource (void) const
1959 {
1960         std::ostringstream buf;
1961
1962         buf     << "#version 310 es\n"
1963                 << "in highp vec4 a_position;\n"
1964                 << "void main ()\n"
1965                 << "{\n"
1966                 << "    gl_Position = a_position;\n";
1967
1968         if (m_flags & FLAG_VERTEX_SET)
1969                 buf << "        gl_PointSize = 2.0;\n";
1970
1971         buf     << "}\n";
1972
1973         return buf.str();
1974 }
1975
1976 const char* PointSizeCase::genFragmentSource (void) const
1977 {
1978         return s_whiteOutputFragmentShader;
1979 }
1980
1981 std::string PointSizeCase::genTessellationControlSource (void) const
1982 {
1983         std::ostringstream buf;
1984
1985         buf     << "#version 310 es\n"
1986                 << "#extension GL_EXT_tessellation_shader : require\n"
1987                 << ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
1988                 << "layout(vertices = 1) out;\n"
1989                 << "void main ()\n"
1990                 << "{\n"
1991                 << "    gl_TessLevelOuter[0] = 3.0;\n"
1992                 << "    gl_TessLevelOuter[1] = 3.0;\n"
1993                 << "    gl_TessLevelOuter[2] = 3.0;\n"
1994                 << "    gl_TessLevelInner[0] = 3.0;\n"
1995                 << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
1996
1997         if (m_flags & FLAG_TESSELLATION_ADD)
1998                 buf << "        // pass as is to eval\n"
1999                         << "    gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
2000         else if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
2001                 buf << "        // thrown away\n"
2002                         << "    gl_out[gl_InvocationID].gl_PointSize = 4.0;\n";
2003
2004         buf     << "}\n";
2005
2006         return buf.str();
2007 }
2008
2009 std::string PointSizeCase::genTessellationEvaluationSource (void) const
2010 {
2011         std::ostringstream buf;
2012
2013         buf     << "#version 310 es\n"
2014                 << "#extension GL_EXT_tessellation_shader : require\n"
2015                 << ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
2016                 << "layout(triangles, point_mode) in;\n"
2017                 << "void main ()\n"
2018                 << "{\n"
2019                 << "    // hide all but one vertex\n"
2020                 << "    if (gl_TessCoord.x < 0.99)\n"
2021                 << "            gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
2022                 << "    else\n"
2023                 << "            gl_Position = gl_in[0].gl_Position;\n";
2024
2025         if (m_flags & FLAG_TESSELLATION_ADD)
2026                 buf << "\n"
2027                         << "    // add to point size\n"
2028                         << "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
2029         else if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
2030                 buf << "\n"
2031                         << "    // set point size\n"
2032                         << "    gl_PointSize = 4.0;\n";
2033
2034         buf     << "}\n";
2035
2036         return buf.str();
2037 }
2038
2039 std::string PointSizeCase::genGeometrySource (void) const
2040 {
2041         std::ostringstream buf;
2042
2043         buf     << "#version 310 es\n"
2044                 << "#extension GL_EXT_geometry_shader : require\n"
2045                 << ((m_flags & FLAG_GEOMETRY_DONT_SET) ? ("") : ("#extension GL_EXT_geometry_point_size : require\n"))
2046                 << "layout (points) in;\n"
2047                 << "layout (points, max_vertices=1) out;\n"
2048                 << "\n"
2049                 << "void main ()\n"
2050                 << "{\n";
2051
2052         if (m_flags & FLAG_GEOMETRY_SET)
2053                 buf     << "    gl_Position = gl_in[0].gl_Position;\n"
2054                         << "    gl_PointSize = 6.0;\n";
2055         else if (m_flags & FLAG_GEOMETRY_ADD)
2056                 buf     << "    gl_Position = gl_in[0].gl_Position;\n"
2057                         << "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
2058         else if (m_flags & FLAG_GEOMETRY_DONT_SET)
2059                 buf     << "    gl_Position = gl_in[0].gl_Position;\n";
2060
2061         buf     << "    EmitVertex();\n"
2062                 << "}\n";
2063
2064         return buf.str();
2065 }
2066
2067 class AllowedRenderFailureException : public std::runtime_error
2068 {
2069 public:
2070         AllowedRenderFailureException (const char* message) : std::runtime_error(message) { }
2071 };
2072
2073 class GridRenderCase : public TestCase
2074 {
2075 public:
2076         enum Flags
2077         {
2078                 FLAG_TESSELLATION_MAX_SPEC                                              = 0x0001,
2079                 FLAG_TESSELLATION_MAX_IMPLEMENTATION                    = 0x0002,
2080                 FLAG_GEOMETRY_MAX_SPEC                                                  = 0x0004,
2081                 FLAG_GEOMETRY_MAX_IMPLEMENTATION                                = 0x0008,
2082                 FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC                              = 0x0010,
2083                 FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION    = 0x0020,
2084
2085                 FLAG_GEOMETRY_SCATTER_INSTANCES                                 = 0x0040,
2086                 FLAG_GEOMETRY_SCATTER_PRIMITIVES                                = 0x0080,
2087                 FLAG_GEOMETRY_SEPARATE_PRIMITIVES                               = 0x0100, //!< if set, geometry shader outputs separate grid cells and not continuous slices
2088                 FLAG_GEOMETRY_SCATTER_LAYERS                                    = 0x0200,
2089
2090                 FLAG_ALLOW_OUT_OF_MEMORY                                                = 0x0400, //!< allow draw command to set GL_OUT_OF_MEMORY
2091         };
2092
2093                                                 GridRenderCase                                  (Context& context, const char* name, const char* description, int flags);
2094                                                 ~GridRenderCase                                 (void);
2095
2096 private:
2097         void                            init                                                    (void);
2098         void                            deinit                                                  (void);
2099         IterateResult           iterate                                                 (void);
2100
2101         void                            renderTo                                                (std::vector<tcu::Surface>& dst);
2102         bool                            verifyResultLayer                               (int layerNdx, const tcu::Surface& dst);
2103
2104         const char*                     getVertexSource                                 (void);
2105         const char*                     getFragmentSource                               (void);
2106         std::string                     getTessellationControlSource    (int tessLevel);
2107         std::string                     getTessellationEvaluationSource (int tessLevel);
2108         std::string                     getGeometryShaderSource                 (int numPrimitives, int numInstances, int tessLevel);
2109
2110         enum
2111         {
2112                 RENDER_SIZE = 256
2113         };
2114
2115         const int                       m_flags;
2116
2117         glu::ShaderProgram*     m_program;
2118         deUint32                        m_texture;
2119         int                                     m_numLayers;
2120 };
2121
2122 GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags)
2123         : TestCase              (context, name, description)
2124         , m_flags               (flags)
2125         , m_program             (DE_NULL)
2126         , m_texture             (0)
2127         , m_numLayers   (1)
2128 {
2129         DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0)                 || ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0));
2130         DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0)                             || ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0));
2131         DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0));
2132         DE_ASSERT(((m_flags & (FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS)) != 0) == ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0));
2133 }
2134
2135 GridRenderCase::~GridRenderCase (void)
2136 {
2137         deinit();
2138 }
2139
2140 void GridRenderCase::init (void)
2141 {
2142         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2143
2144         // Requirements
2145
2146         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
2147                 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2148                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
2149
2150         if ((m_flags & FLAG_GEOMETRY_SCATTER_LAYERS) == 0)
2151         {
2152                 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
2153                         m_context.getRenderTarget().getHeight() < RENDER_SIZE)
2154                         throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
2155         }
2156
2157         // Log
2158
2159         m_testCtx.getLog()
2160                 << tcu::TestLog::Message
2161                 << "Testing tessellation and geometry shaders that output a large number of primitives.\n"
2162                 << getDescription()
2163                 << tcu::TestLog::EndMessage;
2164
2165         // Render target
2166         if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2167         {
2168                 // set limits
2169                 m_numLayers = 8;
2170
2171                 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to 2d texture array, numLayers = " << m_numLayers << tcu::TestLog::EndMessage;
2172
2173                 gl.genTextures(1, &m_texture);
2174                 gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
2175                 gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, RENDER_SIZE, RENDER_SIZE, m_numLayers);
2176
2177                 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2178                 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2179                 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2180                 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2181
2182                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
2183         }
2184
2185         // Gen program
2186         {
2187                 glu::ProgramSources     sources;
2188                 int                                     tessGenLevel = -1;
2189
2190                 sources << glu::VertexSource(getVertexSource())
2191                                 << glu::FragmentSource(getFragmentSource());
2192
2193                 // Tessellation limits
2194                 {
2195                         if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION)
2196                         {
2197                                 gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel);
2198                                 GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits");
2199                         }
2200                         else if (m_flags & FLAG_TESSELLATION_MAX_SPEC)
2201                         {
2202                                 tessGenLevel = 64;
2203                         }
2204                         else
2205                         {
2206                                 tessGenLevel = 5;
2207                         }
2208
2209                         m_testCtx.getLog()
2210                                         << tcu::TestLog::Message
2211                                         << "Tessellation level: " << tessGenLevel << ", mode = quad.\n"
2212                                         << "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n"
2213                                         << tcu::TestLog::EndMessage;
2214
2215                         sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel))
2216                                         << glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel));
2217                 }
2218
2219                 // Geometry limits
2220                 {
2221                         int             geometryOutputComponents                = -1;
2222                         int             geometryOutputVertices                  = -1;
2223                         int             geometryTotalOutputComponents   = -1;
2224                         int             geometryShaderInvocations               = -1;
2225                         bool    logGeometryLimits                               = false;
2226                         bool    logInvocationLimits                             = false;
2227
2228                         if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION)
2229                         {
2230                                 m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage;
2231
2232                                 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents);
2233                                 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices);
2234                                 gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents);
2235                                 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits");
2236
2237                                 logGeometryLimits = true;
2238                         }
2239                         else if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
2240                         {
2241                                 m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage;
2242
2243                                 geometryOutputComponents = 128;
2244                                 geometryOutputVertices = 256;
2245                                 geometryTotalOutputComponents = 1024;
2246                                 logGeometryLimits = true;
2247                         }
2248                         else
2249                         {
2250                                 geometryOutputComponents = 128;
2251                                 geometryOutputVertices = 16;
2252                                 geometryTotalOutputComponents = 1024;
2253                         }
2254
2255                         if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION)
2256                         {
2257                                 gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations);
2258                                 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits");
2259
2260                                 logInvocationLimits = true;
2261                         }
2262                         else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
2263                         {
2264                                 geometryShaderInvocations = 32;
2265                                 logInvocationLimits = true;
2266                         }
2267                         else
2268                         {
2269                                 geometryShaderInvocations = 4;
2270                         }
2271
2272                         if (logGeometryLimits || logInvocationLimits)
2273                         {
2274                                 tcu::MessageBuilder msg(&m_testCtx.getLog());
2275
2276                                 msg << "Geometry shader, targeting following limits:\n";
2277
2278                                 if (logGeometryLimits)
2279                                         msg     << "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n"
2280                                                 << "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n"
2281                                                 << "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n";
2282
2283                                 if (logInvocationLimits)
2284                                         msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations;
2285
2286                                 msg << tcu::TestLog::EndMessage;
2287                         }
2288
2289                         {
2290                                 const bool      separatePrimitives                      = (m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0;
2291                                 const int       numComponentsPerVertex          = 8; // vec4 pos, vec4 color
2292                                 int                     numVerticesPerInvocation;
2293                                 int                     numPrimitivesPerInvocation;
2294                                 int                     geometryVerticesPerPrimitive;
2295                                 int                     geometryPrimitivesOutPerPrimitive;
2296
2297                                 if (separatePrimitives)
2298                                 {
2299                                         const int       numComponentLimit       = geometryTotalOutputComponents / (4 * numComponentsPerVertex);
2300                                         const int       numOutputLimit          = geometryOutputVertices / 4;
2301
2302                                         numPrimitivesPerInvocation              = de::min(numComponentLimit, numOutputLimit);
2303                                         numVerticesPerInvocation                = numPrimitivesPerInvocation * 4;
2304                                 }
2305                                 else
2306                                 {
2307                                         // If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
2308                                         // Each slice is a triangle strip and is generated by a single shader invocation.
2309                                         // One slice with 4 segment ends (nodes) and 3 segments:
2310                                         //    .__.__.__.
2311                                         //    |\ |\ |\ |
2312                                         //    |_\|_\|_\|
2313
2314                                         const int       numSliceNodesComponentLimit     = geometryTotalOutputComponents / (2 * numComponentsPerVertex);                 // each node 2 vertices
2315                                         const int       numSliceNodesOutputLimit        = geometryOutputVertices / 2;                                                                                   // each node 2 vertices
2316                                         const int       numSliceNodes                           = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
2317
2318                                         numVerticesPerInvocation                                = numSliceNodes * 2;
2319                                         numPrimitivesPerInvocation                              = (numSliceNodes - 1) * 2;
2320                                 }
2321
2322                                 geometryVerticesPerPrimitive = numVerticesPerInvocation * geometryShaderInvocations;
2323                                 geometryPrimitivesOutPerPrimitive = numPrimitivesPerInvocation * geometryShaderInvocations;
2324
2325                                 m_testCtx.getLog()
2326                                         << tcu::TestLog::Message
2327                                         << "Geometry shader:\n"
2328                                         << "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n"
2329                                         << "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n"
2330                                         << "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n"
2331                                         << "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n"
2332                                         << "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n"
2333                                         << tcu::TestLog::EndMessage;
2334
2335                                 sources << glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations, tessGenLevel));
2336
2337                                 m_testCtx.getLog()
2338                                         << tcu::TestLog::Message
2339                                         << "Program:\n"
2340                                         << "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
2341                                         << "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
2342                                         << tcu::TestLog::EndMessage;
2343                         }
2344                 }
2345
2346                 m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
2347                 m_testCtx.getLog() << *m_program;
2348                 if (!m_program->isOk())
2349                         throw tcu::TestError("failed to build program");
2350         }
2351 }
2352
2353 void GridRenderCase::deinit (void)
2354 {
2355         delete m_program;
2356         m_program = DE_NULL;
2357
2358         if (m_texture)
2359         {
2360                 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
2361                 m_texture = 0;
2362         }
2363 }
2364
2365 GridRenderCase::IterateResult GridRenderCase::iterate (void)
2366 {
2367         std::vector<tcu::Surface>       renderedLayers  (m_numLayers);
2368         bool                                            allLayersOk             = true;
2369
2370         for (int ndx = 0; ndx < m_numLayers; ++ndx)
2371                 renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE);
2372
2373         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage;
2374
2375         try
2376         {
2377                 renderTo(renderedLayers);
2378         }
2379         catch (const AllowedRenderFailureException& ex)
2380         {
2381                 // Got accepted failure
2382                 m_testCtx.getLog()
2383                         << tcu::TestLog::Message
2384                         << "Could not render, reason: " << ex.what() << "\n"
2385                         << "Failure is allowed."
2386                         << tcu::TestLog::EndMessage;
2387
2388                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2389                 return STOP;
2390         }
2391
2392         for (int ndx = 0; ndx < m_numLayers; ++ndx)
2393                 allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]);
2394
2395         if (allLayersOk)
2396                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2397         else
2398                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2399         return STOP;
2400 }
2401
2402 void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst)
2403 {
2404         const glw::Functions&                   gl                                      = m_context.getRenderContext().getFunctions();
2405         const int                                               positionLocation        = gl.getAttribLocation(m_program->getProgram(), "a_position");
2406         const glu::VertexArray                  vao                                     (m_context.getRenderContext());
2407         de::MovePtr<glu::Framebuffer>   fbo;
2408
2409         if (positionLocation == -1)
2410                 throw tcu::TestError("Attribute a_position location was -1");
2411
2412         gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight());
2413         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2414         GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
2415
2416         gl.bindVertexArray(*vao);
2417         GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
2418
2419         gl.useProgram(m_program->getProgram());
2420         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
2421
2422         gl.patchParameteri(GL_PATCH_VERTICES, 1);
2423         GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
2424
2425         gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
2426
2427         if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2428         {
2429                 // clear texture contents
2430                 {
2431                         glu::Framebuffer clearFbo(m_context.getRenderContext());
2432                         gl.bindFramebuffer(GL_FRAMEBUFFER, *clearFbo);
2433
2434                         for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
2435                         {
2436                                 gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
2437                                 gl.clear(GL_COLOR_BUFFER_BIT);
2438                         }
2439
2440                         GLU_EXPECT_NO_ERROR(gl.getError(), "clear tex contents");
2441                 }
2442
2443                 // create and bind layered fbo
2444
2445                 fbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
2446
2447                 gl.bindFramebuffer(GL_FRAMEBUFFER, **fbo);
2448                 gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
2449                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
2450         }
2451         else
2452         {
2453                 // clear viewport
2454                 gl.clear(GL_COLOR_BUFFER_BIT);
2455         }
2456
2457         // draw
2458         {
2459                 glw::GLenum glerror;
2460
2461                 gl.drawArrays(GL_PATCHES, 0, 1);
2462
2463                 glerror = gl.getError();
2464                 if (glerror == GL_OUT_OF_MEMORY && (m_flags & FLAG_ALLOW_OUT_OF_MEMORY))
2465                         throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing");
2466
2467                 GLU_EXPECT_NO_ERROR(glerror, "draw patches");
2468         }
2469
2470         // Read layers
2471
2472         if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2473         {
2474                 glu::Framebuffer readFbo(m_context.getRenderContext());
2475                 gl.bindFramebuffer(GL_FRAMEBUFFER, *readFbo);
2476
2477                 for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
2478                 {
2479                         gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
2480                         glu::readPixels(m_context.getRenderContext(), 0, 0, dst[layerNdx].getAccess());
2481                         GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
2482                 }
2483         }
2484         else
2485         {
2486                 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess());
2487                 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
2488         }
2489 }
2490
2491 bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image)
2492 {
2493         tcu::Surface    errorMask       (image.getWidth(), image.getHeight());
2494         bool                    foundError      = false;
2495
2496         tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
2497
2498         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx  << tcu::TestLog::EndMessage;
2499
2500         for (int y = 0; y < image.getHeight(); ++y)
2501         for (int x = 0; x < image.getWidth(); ++x)
2502         {
2503                 const int               threshold       = 8;
2504                 const tcu::RGBA color           = image.getPixel(x, y);
2505
2506                 // Color must be a linear combination of green and yellow
2507                 if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
2508                 {
2509                         errorMask.setPixel(x, y, tcu::RGBA::red);
2510                         foundError = true;
2511                 }
2512         }
2513
2514         if (!foundError)
2515         {
2516                 m_testCtx.getLog()
2517                         << tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
2518                         << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
2519                         << tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
2520                         << tcu::TestLog::EndImageSet;
2521                 return true;
2522         }
2523         else
2524         {
2525                 m_testCtx.getLog()
2526                         << tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
2527                         << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
2528                         << tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
2529                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
2530                         << tcu::TestLog::EndImageSet;
2531                 return false;
2532         }
2533 }
2534
2535 const char* GridRenderCase::getVertexSource (void)
2536 {
2537         return s_positionVertexShader;
2538 }
2539
2540 const char* GridRenderCase::getFragmentSource (void)
2541 {
2542         return  "#version 310 es\n"
2543                         "flat in mediump vec4 v_color;\n"
2544                         "layout(location = 0) out mediump vec4 fragColor;\n"
2545                         "void main (void)\n"
2546                         "{\n"
2547                         "       fragColor = v_color;\n"
2548                         "}\n";
2549 }
2550
2551 std::string GridRenderCase::getTessellationControlSource (int tessLevel)
2552 {
2553         std::ostringstream buf;
2554
2555         buf <<  "#version 310 es\n"
2556                         "#extension GL_EXT_tessellation_shader : require\n"
2557                         "layout(vertices=1) out;\n"
2558                         "\n"
2559                         "void main()\n"
2560                         "{\n"
2561                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2562                         "       gl_TessLevelOuter[0] = " << tessLevel << ".0;\n"
2563                         "       gl_TessLevelOuter[1] = " << tessLevel << ".0;\n"
2564                         "       gl_TessLevelOuter[2] = " << tessLevel << ".0;\n"
2565                         "       gl_TessLevelOuter[3] = " << tessLevel << ".0;\n"
2566                         "       gl_TessLevelInner[0] = " << tessLevel << ".0;\n"
2567                         "       gl_TessLevelInner[1] = " << tessLevel << ".0;\n"
2568                         "}\n";
2569
2570         return buf.str();
2571 }
2572
2573 std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel)
2574 {
2575         std::ostringstream buf;
2576
2577         buf <<  "#version 310 es\n"
2578                         "#extension GL_EXT_tessellation_shader : require\n"
2579                         "layout(quads) in;\n"
2580                         "\n"
2581                         "out mediump ivec2 v_tessellationGridPosition;\n"
2582                         "\n"
2583                         "void main (void)\n"
2584                         "{\n";
2585
2586         if (m_flags & (FLAG_GEOMETRY_SCATTER_INSTANCES | FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS))
2587                 buf <<  "       // Cover only a small area in a corner. The area will be expanded in geometry shader to cover whole viewport\n"
2588                                 "       gl_Position = vec4(gl_TessCoord.x * 0.3 - 1.0, gl_TessCoord.y * 0.3 - 1.0, 0.0, 1.0);\n";
2589         else
2590                 buf <<  "       // Fill the whole viewport\n"
2591                                 "       gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n";
2592
2593         buf <<  "       // Calculate position in tessellation grid\n"
2594                         "       v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n"
2595                         "}\n";
2596
2597         return buf.str();
2598 }
2599
2600 std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances, int tessLevel)
2601 {
2602         std::ostringstream buf;
2603
2604         buf     <<      "#version 310 es\n"
2605                         "#extension GL_EXT_geometry_shader : require\n"
2606                         "layout(triangles, invocations=" << numInstances << ") in;\n"
2607                         "layout(triangle_strip, max_vertices=" << ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) ? (4 * numPrimitives) : (numPrimitives + 2)) << ") out;\n"
2608                         "\n"
2609                         "in mediump ivec2 v_tessellationGridPosition[];\n"
2610                         "flat out highp vec4 v_color;\n"
2611                         "\n"
2612                         "void main ()\n"
2613                         "{\n"
2614                         "       const float equalThreshold = 0.001;\n"
2615                         "       const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n"
2616                         "\n"
2617                         "       // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
2618                         "       // Original rectangle can be found by finding the bounding AABB of the triangle\n"
2619                         "       vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
2620                         "                        min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
2621                         "                        max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
2622                         "                        max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
2623                         "\n"
2624                         "       // Location in tessellation grid\n"
2625                         "       ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
2626                         "\n"
2627                         "       // Which triangle of the two that split the grid cell\n"
2628                         "       int numVerticesOnBottomEdge = 0;\n"
2629                         "       for (int ndx = 0; ndx < 3; ++ndx)\n"
2630                         "               if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
2631                         "                       ++numVerticesOnBottomEdge;\n"
2632                         "       bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
2633                         "\n";
2634
2635         if (m_flags & FLAG_GEOMETRY_SCATTER_PRIMITIVES)
2636         {
2637                 // scatter primitives
2638                 buf <<  "       // Draw grid cells\n"
2639                                 "       int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2640                                 "       for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
2641                                 "       {\n"
2642                                 "               ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", 2 * " << tessLevel << " * " << numInstances << ");\n"
2643                                 "               ivec2 dstGridNdx = ivec2(" << tessLevel << " * ndx + gridPosition.x, " << tessLevel << " * inputTriangleNdx + 2 * gridPosition.y + ndx * 127) % dstGridSize;\n"
2644                                 "               vec4 dstArea;\n"
2645                                 "               dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
2646                                 "               dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
2647                                 "               dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
2648                                 "               dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
2649                                 "\n"
2650                                 "               vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2651                                 "               vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2652                                 "               vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
2653                                 "\n"
2654                                 "               gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
2655                                 "               v_color = outputColor;\n"
2656                                 "               EmitVertex();\n"
2657                                 "\n"
2658                                 "               gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
2659                                 "               v_color = outputColor;\n"
2660                                 "               EmitVertex();\n"
2661                                 "\n"
2662                                 "               gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
2663                                 "               v_color = outputColor;\n"
2664                                 "               EmitVertex();\n"
2665                                 "\n"
2666                                 "               gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
2667                                 "               v_color = outputColor;\n"
2668                                 "               EmitVertex();\n"
2669                                 "               EndPrimitive();\n"
2670                                 "       }\n";
2671         }
2672         else if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2673         {
2674                 // Number of subrectangle instances = num layers
2675                 DE_ASSERT(m_numLayers == numInstances * 2);
2676
2677                 buf <<  "       // Draw grid cells, send each primitive to a separate layer\n"
2678                                 "       int baseLayer = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2679                                 "       for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
2680                                 "       {\n"
2681                                 "               ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", " << tessLevel << ");\n"
2682                                 "               ivec2 dstGridNdx = ivec2((gridPosition.x * " << numPrimitives << " * 7 + ndx)*13, (gridPosition.y * 127 + ndx) * 19) % dstGridSize;\n"
2683                                 "               vec4 dstArea;\n"
2684                                 "               dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
2685                                 "               dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
2686                                 "               dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
2687                                 "               dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
2688                                 "\n"
2689                                 "               vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2690                                 "               vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2691                                 "               vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
2692                                 "\n"
2693                                 "               gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
2694                                 "               v_color = outputColor;\n"
2695                                 "               gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2696                                 "               EmitVertex();\n"
2697                                 "\n"
2698                                 "               gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
2699                                 "               v_color = outputColor;\n"
2700                                 "               gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2701                                 "               EmitVertex();\n"
2702                                 "\n"
2703                                 "               gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
2704                                 "               v_color = outputColor;\n"
2705                                 "               gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2706                                 "               EmitVertex();\n"
2707                                 "\n"
2708                                 "               gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
2709                                 "               v_color = outputColor;\n"
2710                                 "               gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2711                                 "               EmitVertex();\n"
2712                                 "               EndPrimitive();\n"
2713                                 "       }\n";
2714         }
2715         else
2716         {
2717                 if (m_flags & FLAG_GEOMETRY_SCATTER_INSTANCES)
2718                 {
2719                         buf <<  "       // Scatter slices\n"
2720                                         "       int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2721                                         "       ivec2 srcSliceNdx = ivec2(gridPosition.x, gridPosition.y * " << (numInstances*2) << " + inputTriangleNdx);\n"
2722                                         "       ivec2 dstSliceNdx = ivec2(7 * srcSliceNdx.x, 127 * srcSliceNdx.y) % ivec2(" << tessLevel << ", " << tessLevel << " * " << (numInstances*2) << ");\n"
2723                                         "\n"
2724                                         "       // Draw slice to the dstSlice slot\n"
2725                                         "       vec4 outputSliceArea;\n"
2726                                         "       outputSliceArea.x = float(dstSliceNdx.x) / float(" << tessLevel << ") * 2.0 - 1.0 - gapOffset;\n"
2727                                         "       outputSliceArea.y = float(dstSliceNdx.y) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 - gapOffset;\n"
2728                                         "       outputSliceArea.z = float(dstSliceNdx.x+1) / float(" << tessLevel << ") * 2.0 - 1.0 + gapOffset;\n"
2729                                         "       outputSliceArea.w = float(dstSliceNdx.y+1) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 + gapOffset;\n";
2730                 }
2731                 else
2732                 {
2733                         buf <<  "       // Fill the input area with slices\n"
2734                                         "       // Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
2735                                         "       float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
2736                                         "       // Each slice is a invocation\n"
2737                                         "       float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n"
2738                                         "       float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
2739                                         "\n"
2740                                         "       vec4 outputSliceArea;\n"
2741                                         "       outputSliceArea.x = aabb.x - gapOffset;\n"
2742                                         "       outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
2743                                         "       outputSliceArea.z = aabb.z + gapOffset;\n"
2744                                         "       outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n";
2745                 }
2746
2747                 buf <<  "\n"
2748                                 "       // Draw slice\n"
2749                                 "       for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
2750                                 "       {\n"
2751                                 "               vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2752                                 "               vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2753                                 "               vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
2754                                 "               float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
2755                                 "\n"
2756                                 "               gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
2757                                 "               v_color = outputColor;\n"
2758                                 "               EmitVertex();\n"
2759                                 "\n"
2760                                 "               gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
2761                                 "               v_color = outputColor;\n"
2762                                 "               EmitVertex();\n"
2763                                 "       }\n";
2764         }
2765
2766         buf <<  "}\n";
2767
2768         return buf.str();
2769 }
2770
2771 class FeedbackRecordVariableSelectionCase : public TestCase
2772 {
2773 public:
2774                                                 FeedbackRecordVariableSelectionCase             (Context& context, const char* name, const char* description);
2775                                                 ~FeedbackRecordVariableSelectionCase    (void);
2776
2777 private:
2778         void                            init                                                                    (void);
2779         void                            deinit                                                                  (void);
2780         IterateResult           iterate                                                                 (void);
2781
2782         const char*                     getVertexSource                                                 (void);
2783         const char*                     getFragmentSource                                               (void);
2784         const char*                     getTessellationControlSource                    (void);
2785         const char*                     getTessellationEvaluationSource                 (void);
2786         const char*                     getGeometrySource                                               (void);
2787
2788         glu::ShaderProgram*     m_program;
2789         deUint32                        m_xfbBuf;
2790 };
2791
2792 FeedbackRecordVariableSelectionCase::FeedbackRecordVariableSelectionCase (Context& context, const char* name, const char* description)
2793         : TestCase      (context, name, description)
2794         , m_program     (DE_NULL)
2795         , m_xfbBuf      (0)
2796 {
2797 }
2798
2799 FeedbackRecordVariableSelectionCase::~FeedbackRecordVariableSelectionCase (void)
2800 {
2801         deinit();
2802 }
2803
2804 void FeedbackRecordVariableSelectionCase::init (void)
2805 {
2806         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
2807                 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2808                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
2809
2810         m_testCtx.getLog() << tcu::TestLog::Message << "Declaring multiple output variables with the same name in multiple shader stages. Capturing the value of the varying using transform feedback." << tcu::TestLog::EndMessage;
2811
2812         // gen feedback buffer fit for 1 triangle (4 components)
2813         {
2814                 static const tcu::Vec4 initialData[3] =
2815                 {
2816                         tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2817                         tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2818                         tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2819                 };
2820
2821                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2822
2823                 m_testCtx.getLog() << tcu::TestLog::Message << "Creating buffer for transform feedback. Allocating storage for one triangle. Filling with -1.0" << tcu::TestLog::EndMessage;
2824
2825                 gl.genBuffers(1, &m_xfbBuf);
2826                 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfbBuf);
2827                 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(tcu::Vec4[3])), initialData, GL_DYNAMIC_READ);
2828                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen xfb buf");
2829         }
2830
2831         // gen shader
2832         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2833                                                                                                                                          << glu::VertexSource(getVertexSource())
2834                                                                                                                                          << glu::FragmentSource(getFragmentSource())
2835                                                                                                                                          << glu::TessellationControlSource(getTessellationControlSource())
2836                                                                                                                                          << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
2837                                                                                                                                          << glu::GeometrySource(getGeometrySource())
2838                                                                                                                                          << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
2839                                                                                                                                          << glu::TransformFeedbackVarying("tf_feedback"));
2840         m_testCtx.getLog() << *m_program;
2841
2842         if (!m_program->isOk())
2843                 throw tcu::TestError("could not build program");
2844 }
2845
2846 void FeedbackRecordVariableSelectionCase::deinit (void)
2847 {
2848         delete m_program;
2849         m_program = DE_NULL;
2850
2851         if (m_xfbBuf)
2852         {
2853                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_xfbBuf);
2854                 m_xfbBuf = 0;
2855         }
2856 }
2857
2858 FeedbackRecordVariableSelectionCase::IterateResult FeedbackRecordVariableSelectionCase::iterate (void)
2859 {
2860         const glw::Functions&   gl              = m_context.getRenderContext().getFunctions();
2861         const int                               posLoc  = gl.getAttribLocation(m_program->getProgram(), "a_position");
2862         const glu::VertexArray  vao             (m_context.getRenderContext());
2863
2864         if (posLoc == -1)
2865                 throw tcu::TestError("a_position attribute location was -1");
2866
2867         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2868
2869         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering a patch of size 3." << tcu::TestLog::EndMessage;
2870
2871         // Render and feed back
2872
2873         gl.viewport(0, 0, 1, 1);
2874         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2875         gl.clear(GL_COLOR_BUFFER_BIT);
2876         GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
2877
2878         gl.bindVertexArray(*vao);
2879         GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
2880
2881         gl.vertexAttrib4f(posLoc, 0.0f, 0.0f, 0.0f, 1.0f);
2882         GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttrib4f");
2883
2884         gl.useProgram(m_program->getProgram());
2885         GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
2886
2887         gl.patchParameteri(GL_PATCH_VERTICES, 3);
2888         GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
2889
2890         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfbBuf);
2891         GLU_EXPECT_NO_ERROR(gl.getError(), "bind xfb buf");
2892
2893         gl.beginTransformFeedback(GL_TRIANGLES);
2894         GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
2895
2896         gl.drawArrays(GL_PATCHES, 0, 3);
2897         GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
2898
2899         gl.endTransformFeedback();
2900         GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
2901
2902         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying the value of tf_feedback using transform feedback, expecting (3.0, 3.0, 3.0, 3.0)." << tcu::TestLog::EndMessage;
2903
2904         // Read back result (one triangle)
2905         {
2906                 tcu::Vec4       feedbackValues[3];
2907                 const void* mapPtr                              = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (int)sizeof(feedbackValues), GL_MAP_READ_BIT);
2908                 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
2909
2910                 if (mapPtr == DE_NULL)
2911                         throw tcu::TestError("mapBufferRange returned null");
2912
2913                 deMemcpy(feedbackValues, mapPtr, sizeof(feedbackValues));
2914
2915                 if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
2916                         throw tcu::TestError("unmapBuffer did not return TRUE");
2917
2918                 for (int ndx = 0; ndx < 3; ++ndx)
2919                 {
2920                         if (!tcu::boolAll(tcu::lessThan(tcu::abs(feedbackValues[ndx] - tcu::Vec4(3.0f)), tcu::Vec4(0.001f))))
2921                         {
2922                                 m_testCtx.getLog() << tcu::TestLog::Message << "Feedback vertex " << ndx << ": expected (3.0, 3.0, 3.0, 3.0), got " << feedbackValues[ndx] << tcu::TestLog::EndMessage;
2923                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected feedback results");
2924                         }
2925                 }
2926         }
2927
2928         return STOP;
2929 }
2930
2931 const char* FeedbackRecordVariableSelectionCase::getVertexSource (void)
2932 {
2933         return  "#version 310 es\n"
2934                         "in highp vec4 a_position;\n"
2935                         "out highp vec4 tf_feedback;\n"
2936                         "void main()\n"
2937                         "{\n"
2938                         "       gl_Position = a_position;\n"
2939                         "       tf_feedback = vec4(1.0, 1.0, 1.0, 1.0);\n"
2940                         "}\n";
2941 }
2942
2943 const char* FeedbackRecordVariableSelectionCase::getFragmentSource (void)
2944 {
2945         return s_whiteOutputFragmentShader;
2946 }
2947
2948 const char* FeedbackRecordVariableSelectionCase::getTessellationControlSource (void)
2949 {
2950         return  "#version 310 es\n"
2951                         "#extension GL_EXT_tessellation_shader : require\n"
2952                         "layout(vertices=3) out;\n"
2953                         "void main()\n"
2954                         "{\n"
2955                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2956                         "       gl_TessLevelOuter[0] = 1.0;\n"
2957                         "       gl_TessLevelOuter[1] = 1.0;\n"
2958                         "       gl_TessLevelOuter[2] = 1.0;\n"
2959                         "       gl_TessLevelInner[0] = 1.0;\n"
2960                         "}\n";
2961 }
2962
2963 const char* FeedbackRecordVariableSelectionCase::getTessellationEvaluationSource (void)
2964 {
2965         return  "#version 310 es\n"
2966                         "#extension GL_EXT_tessellation_shader : require\n"
2967                         "layout(triangles) in;\n"
2968                         "out highp vec4 tf_feedback;\n"
2969                         "void main()\n"
2970                         "{\n"
2971                         "       gl_Position = gl_in[0].gl_Position * gl_TessCoord.x + gl_in[1].gl_Position * gl_TessCoord.y + gl_in[2].gl_Position * gl_TessCoord.z;\n"
2972                         "       tf_feedback = vec4(2.0, 2.0, 2.0, 2.0);\n"
2973                         "}\n";
2974 }
2975
2976 const char* FeedbackRecordVariableSelectionCase::getGeometrySource (void)
2977 {
2978         return  "#version 310 es\n"
2979                         "#extension GL_EXT_geometry_shader : require\n"
2980                         "layout (triangles) in;\n"
2981                         "layout (triangle_strip, max_vertices=3) out;\n"
2982                         "out highp vec4 tf_feedback;\n"
2983                         "void main()\n"
2984                         "{\n"
2985                         "       for (int ndx = 0; ndx < 3; ++ndx)\n"
2986                         "       {\n"
2987                         "               gl_Position = gl_in[ndx].gl_Position + vec4(float(ndx), float(ndx)*float(ndx), 0.0, 0.0);\n"
2988                         "               tf_feedback = vec4(3.0, 3.0, 3.0, 3.0);\n"
2989                         "               EmitVertex();\n"
2990                         "       }\n"
2991                         "       EndPrimitive();\n"
2992                         "}\n";
2993 }
2994
2995 } // anonymous
2996
2997 TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context)
2998         : TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction tests")
2999 {
3000 }
3001
3002 TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void)
3003 {
3004 }
3005
3006 void TessellationGeometryInteractionTests::init (void)
3007 {
3008         tcu::TestCaseGroup* const renderGroup           = new tcu::TestCaseGroup(m_testCtx, "render",           "Various render tests");
3009         tcu::TestCaseGroup* const feedbackGroup         = new tcu::TestCaseGroup(m_testCtx, "feedback",         "Test transform feedback");
3010         tcu::TestCaseGroup* const pointSizeGroup        = new tcu::TestCaseGroup(m_testCtx, "point_size",       "Test point size");
3011
3012         addChild(renderGroup);
3013         addChild(feedbackGroup);
3014         addChild(pointSizeGroup);
3015
3016         // .render
3017         {
3018                 tcu::TestCaseGroup* const passthroughGroup      = new tcu::TestCaseGroup(m_testCtx, "passthrough",      "Render various types with either passthrough geometry or tessellation shader");
3019                 tcu::TestCaseGroup* const limitGroup            = new tcu::TestCaseGroup(m_testCtx, "limits",           "Render with properties near their limits");
3020                 tcu::TestCaseGroup* const scatterGroup          = new tcu::TestCaseGroup(m_testCtx, "scatter",          "Scatter output primitives");
3021
3022                 renderGroup->addChild(passthroughGroup);
3023                 renderGroup->addChild(limitGroup);
3024                 renderGroup->addChild(scatterGroup);
3025
3026                 // .passthrough
3027                 {
3028                         // tessellate_tris_passthrough_geometry_no_change
3029                         // tessellate_quads_passthrough_geometry_no_change
3030                         // tessellate_isolines_passthrough_geometry_no_change
3031                         passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_tris_passthrough_geometry_no_change",          "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_TRIANGLES));
3032                         passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_quads_passthrough_geometry_no_change",         "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_QUADS));
3033                         passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_isolines_passthrough_geometry_no_change",      "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_ISOLINES));
3034
3035                         // passthrough_tessellation_geometry_shade_triangles_no_change
3036                         // passthrough_tessellation_geometry_shade_lines_no_change
3037                         passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_triangles_no_change", "Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_TRIANGLES));
3038                         passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_lines_no_change",             "Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_ISOLINES));
3039                 }
3040
3041                 // .limits
3042                 {
3043                         static const struct LimitCaseDef
3044                         {
3045                                 const char*     name;
3046                                 const char*     desc;
3047                                 int                     flags;
3048                         } cases[] =
3049                         {
3050                                 // Test single limit
3051                                 {
3052                                         "output_required_max_tessellation",
3053                                         "Minimum maximum tessellation level",
3054                                         GridRenderCase::FLAG_TESSELLATION_MAX_SPEC
3055                                 },
3056                                 {
3057                                         "output_implementation_max_tessellation",
3058                                         "Maximum tessellation level supported by the implementation",
3059                                         GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION
3060                                 },
3061                                 {
3062                                         "output_required_max_geometry",
3063                                         "Output minimum maximum number of vertices the geometry shader",
3064                                         GridRenderCase::FLAG_GEOMETRY_MAX_SPEC
3065                                 },
3066                                 {
3067                                         "output_implementation_max_geometry",
3068                                         "Output maximum number of vertices in the geometry shader supported by the implementation",
3069                                         GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION
3070                                 },
3071                                 {
3072                                         "output_required_max_invocations",
3073                                         "Minimum maximum number of geometry shader invocations",
3074                                         GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
3075                                 },
3076                                 {
3077                                         "output_implementation_max_invocations",
3078                                         "Maximum number of geometry shader invocations supported by the implementation",
3079                                         GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
3080                                 },
3081                         };
3082
3083                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
3084                                 limitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
3085                 }
3086
3087                 // .scatter
3088                 {
3089                         scatterGroup->addChild(new GridRenderCase(m_context,
3090                                                                                                           "geometry_scatter_instances",
3091                                                                                                           "Each geometry shader instance outputs its primitives far from other instances of the same execution",
3092                                                                                                           GridRenderCase::FLAG_GEOMETRY_SCATTER_INSTANCES));
3093                         scatterGroup->addChild(new GridRenderCase(m_context,
3094                                                                                                           "geometry_scatter_primitives",
3095                                                                                                           "Each geometry shader instance outputs its primitives far from other primitives of the same instance",
3096                                                                                                           GridRenderCase::FLAG_GEOMETRY_SCATTER_PRIMITIVES | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
3097                         scatterGroup->addChild(new GridRenderCase(m_context,
3098                                                                                                           "geometry_scatter_layers",
3099                                                                                                           "Each geometry shader instance outputs its primitives to multiple layers and far from other primitives of the same instance",
3100                                                                                                           GridRenderCase::FLAG_GEOMETRY_SCATTER_LAYERS | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
3101                 }
3102         }
3103
3104         // .feedback
3105         {
3106                 static const struct PrimitiveCaseConfig
3107                 {
3108                         const char*                                                                                     name;
3109                         const char*                                                                                     description;
3110                         FeedbackPrimitiveTypeCase::TessellationOutputType       tessellationOutput;
3111                         FeedbackPrimitiveTypeCase::TessellationPointMode        tessellationPointMode;
3112                         FeedbackPrimitiveTypeCase::GeometryOutputType           geometryOutputType;
3113                 } caseConfigs[] =
3114                 {
3115                         // tess output triangles -> geo input triangles, output points
3116                         {
3117                                 "tessellation_output_triangles_geometry_output_points",
3118                                 "Tessellation outputs triangles, geometry outputs points",
3119                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
3120                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3121                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3122                         },
3123
3124                         // tess output quads <-> geo input triangles, output points
3125                         {
3126                                 "tessellation_output_quads_geometry_output_points",
3127                                 "Tessellation outputs quads, geometry outputs points",
3128                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
3129                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3130                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3131                         },
3132
3133                         // tess output isolines <-> geo input lines, output points
3134                         {
3135                                 "tessellation_output_isolines_geometry_output_points",
3136                                 "Tessellation outputs isolines, geometry outputs points",
3137                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
3138                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3139                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3140                         },
3141
3142                         // tess output triangles, point_mode <-> geo input points, output lines
3143                         {
3144                                 "tessellation_output_triangles_point_mode_geometry_output_lines",
3145                                 "Tessellation outputs triangles in point mode, geometry outputs lines",
3146                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
3147                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3148                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
3149                         },
3150
3151                         // tess output quads, point_mode <-> geo input points, output lines
3152                         {
3153                                 "tessellation_output_quads_point_mode_geometry_output_lines",
3154                                 "Tessellation outputs quads in point mode, geometry outputs lines",
3155                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
3156                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3157                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
3158                         },
3159
3160                         // tess output isolines, point_mode <-> geo input points, output triangles
3161                         {
3162                                 "tessellation_output_isolines_point_mode_geometry_output_triangles",
3163                                 "Tessellation outputs isolines in point mode, geometry outputs triangles",
3164                                 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
3165                                 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3166                                 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_TRIANGLES
3167                         },
3168                 };
3169
3170                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseConfigs); ++ndx)
3171                 {
3172                         feedbackGroup->addChild(new FeedbackPrimitiveTypeCase(m_context,
3173                                                                                                                                   caseConfigs[ndx].name,
3174                                                                                                                                   caseConfigs[ndx].description,
3175                                                                                                                                   caseConfigs[ndx].tessellationOutput,
3176                                                                                                                                   caseConfigs[ndx].tessellationPointMode,
3177                                                                                                                                   caseConfigs[ndx].geometryOutputType));
3178                 }
3179
3180                 feedbackGroup->addChild(new FeedbackRecordVariableSelectionCase(m_context, "record_variable_selection", "Record a variable that has been declared as an output variable in multiple shader stages"));
3181         }
3182
3183         // .point_size
3184         {
3185                 static const int caseFlags[] =
3186                 {
3187                         PointSizeCase::FLAG_VERTEX_SET,
3188                                                                                                 PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
3189                                                                                                                                                                                                                 PointSizeCase::FLAG_GEOMETRY_SET,
3190                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_CONTROL_SET,
3191                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
3192                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_DONT_SET,
3193                         PointSizeCase::FLAG_VERTEX_SET  |                                                                                                                       PointSizeCase::FLAG_GEOMETRY_SET,
3194                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET         |       PointSizeCase::FLAG_GEOMETRY_SET,
3195                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_ADD                            |       PointSizeCase::FLAG_GEOMETRY_ADD,
3196                         PointSizeCase::FLAG_VERTEX_SET  |       PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET         |       PointSizeCase::FLAG_GEOMETRY_DONT_SET,
3197                 };
3198
3199                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
3200                 {
3201                         const std::string name = PointSizeCase::genTestCaseName(caseFlags[ndx]);
3202                         const std::string desc = PointSizeCase::genTestCaseDescription(caseFlags[ndx]);
3203
3204                         pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), desc.c_str(), caseFlags[ndx]));
3205                 }
3206         }
3207 }
3208
3209 } // Functional
3210 } // gles31
3211 } // deqp