Merge vk-gl-cts/vulkan-cts-1.1.4 into vk-gl-cts/vulkan-cts-1.1.5
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / tessellation / vktTessellationGeometryGridRenderTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tessellation Geometry Interaction - Grid render (limits, scatter)
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationGeometryGridRenderTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28
29 #include "tcuTestLog.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuRGBA.hpp"
33
34 #include "vkDefs.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42
43 #include "deUniquePtr.hpp"
44
45 #include <string>
46 #include <vector>
47
48 namespace vkt
49 {
50 namespace tessellation
51 {
52
53 using namespace vk;
54
55 namespace
56 {
57
58 enum Constants
59 {
60         RENDER_SIZE = 256,
61 };
62
63 enum FlagBits
64 {
65         FLAG_TESSELLATION_MAX_SPEC                      = 1u << 0,
66         FLAG_GEOMETRY_MAX_SPEC                          = 1u << 1,
67         FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC      = 1u << 2,
68
69         FLAG_GEOMETRY_SCATTER_INSTANCES         = 1u << 3,
70         FLAG_GEOMETRY_SCATTER_PRIMITIVES        = 1u << 4,
71         FLAG_GEOMETRY_SEPARATE_PRIMITIVES       = 1u << 5, //!< if set, geometry shader outputs separate grid cells and not continuous slices
72         FLAG_GEOMETRY_SCATTER_LAYERS            = 1u << 6,
73 };
74 typedef deUint32 Flags;
75
76 class GridRenderTestCase : public TestCase
77 {
78 public:
79         void                    initPrograms                    (vk::SourceCollections& programCollection) const;
80         TestInstance*   createInstance                  (Context& context) const;
81
82                                         GridRenderTestCase              (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Flags flags);
83
84 private:
85         const Flags             m_flags;
86         const int               m_tessGenLevel;
87         const int               m_numGeometryInvocations;
88         const int               m_numLayers;
89         int                             m_numGeometryPrimitivesPerInvocation;
90 };
91
92 GridRenderTestCase::GridRenderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Flags flags)
93         : TestCase                                      (testCtx, name, description)
94         , m_flags                                       (flags)
95         , m_tessGenLevel                        ((m_flags & FLAG_TESSELLATION_MAX_SPEC)                 ? 64 : 5)
96         , m_numGeometryInvocations      ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) ? 32 : 4)
97         , m_numLayers                           ((m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)               ? 8  : 1)
98 {
99         DE_ASSERT(((flags & (FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS)) != 0) == ((flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0));
100
101         testCtx.getLog()
102                 << tcu::TestLog::Message
103                 << "Testing tessellation and geometry shaders that output a large number of primitives.\n"
104                 << getDescription()
105                 << tcu::TestLog::EndMessage;
106
107         if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
108                 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to 2d texture array, numLayers = " << m_numLayers << tcu::TestLog::EndMessage;
109
110         m_testCtx.getLog()
111                 << tcu::TestLog::Message
112                 << "Tessellation level: " << m_tessGenLevel << ", mode = quad.\n"
113                 << "\tEach input patch produces " << (m_tessGenLevel*m_tessGenLevel) << " (" << (m_tessGenLevel*m_tessGenLevel*2) << " triangles)\n"
114                 << tcu::TestLog::EndMessage;
115
116         int geometryOutputComponents      = 0;
117         int geometryOutputVertices                = 0;
118         int geometryTotalOutputComponents = 0;
119
120         if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
121         {
122                 m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader minimum maximum output limits." << tcu::TestLog::EndMessage;
123
124                 geometryOutputComponents          = 64;
125                 geometryOutputVertices            = 256;
126                 geometryTotalOutputComponents = 1024;
127         }
128         else
129         {
130                 geometryOutputComponents          = 64;
131                 geometryOutputVertices            = 16;
132                 geometryTotalOutputComponents = 1024;
133         }
134
135         if ((m_flags & FLAG_GEOMETRY_MAX_SPEC) || (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC))
136         {
137                 tcu::MessageBuilder msg(&m_testCtx.getLog());
138
139                 msg << "Geometry shader, targeting following limits:\n";
140
141                 if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
142                         msg     << "\tmaxGeometryOutputComponents = "      << geometryOutputComponents << "\n"
143                                 << "\tmaxGeometryOutputVertices = "                << geometryOutputVertices << "\n"
144                                 << "\tmaxGeometryTotalOutputComponents = " << geometryTotalOutputComponents << "\n";
145
146                 if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
147                         msg << "\tmaxGeometryShaderInvocations = "         << m_numGeometryInvocations;
148
149                 msg << tcu::TestLog::EndMessage;
150         }
151
152         const bool      separatePrimitives                                = (m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0;
153         const int       numComponentsPerVertex                    = 8; // vec4 pos, vec4 color
154         int                     numVerticesPerInvocation                  = 0;
155         int                     geometryVerticesPerPrimitive      = 0;
156         int                     geometryPrimitivesOutPerPrimitive = 0;
157
158         if (separatePrimitives)
159         {
160                 const int       numComponentLimit                = geometryTotalOutputComponents / (4 * numComponentsPerVertex);
161                 const int       numOutputLimit                   = geometryOutputVertices / 4;
162
163                 m_numGeometryPrimitivesPerInvocation = de::min(numComponentLimit, numOutputLimit);
164                 numVerticesPerInvocation                         = m_numGeometryPrimitivesPerInvocation * 4;
165         }
166         else
167         {
168                 // If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
169                 // Each slice is a triangle strip and is generated by a single shader invocation.
170                 // One slice with 4 segment ends (nodes) and 3 segments:
171                 //    .__.__.__.
172                 //    |\ |\ |\ |
173                 //    |_\|_\|_\|
174
175                 const int       numSliceNodesComponentLimit     = geometryTotalOutputComponents / (2 * numComponentsPerVertex);                 // each node 2 vertices
176                 const int       numSliceNodesOutputLimit        = geometryOutputVertices / 2;                                                                                   // each node 2 vertices
177                 const int       numSliceNodes                           = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
178
179                 numVerticesPerInvocation                                = numSliceNodes * 2;
180                 m_numGeometryPrimitivesPerInvocation    = (numSliceNodes - 1) * 2;
181         }
182
183         geometryVerticesPerPrimitive      = numVerticesPerInvocation * m_numGeometryInvocations;
184         geometryPrimitivesOutPerPrimitive = m_numGeometryPrimitivesPerInvocation * m_numGeometryInvocations;
185
186         m_testCtx.getLog()
187                 << tcu::TestLog::Message
188                 << "Geometry shader:\n"
189                 << "\tTotal output vertex count per invocation: "                 << numVerticesPerInvocation << "\n"
190                 << "\tTotal output primitive count per invocation: "      << m_numGeometryPrimitivesPerInvocation << "\n"
191                 << "\tNumber of invocations per primitive: "                      << m_numGeometryInvocations << "\n"
192                 << "\tTotal output vertex count per input primitive: "    << geometryVerticesPerPrimitive << "\n"
193                 << "\tTotal output primitive count per input primitive: " << geometryPrimitivesOutPerPrimitive << "\n"
194                 << tcu::TestLog::EndMessage;
195
196         m_testCtx.getLog()
197                 << tcu::TestLog::Message
198                 << "Program:\n"
199                 << "\tTotal program output vertices count per input patch: "  << (m_tessGenLevel*m_tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
200                 << "\tTotal program output primitive count per input patch: " << (m_tessGenLevel*m_tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
201                 << tcu::TestLog::EndMessage;
202 }
203
204 void GridRenderTestCase::initPrograms (SourceCollections& programCollection) const
205 {
206         // Vertex shader
207         {
208                 std::ostringstream src;
209                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
210                         << "\n"
211                         << "void main (void)\n"
212                         << "{\n"
213                         << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
214                         << "}\n";
215
216                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
217         }
218
219         // Fragment shader
220         {
221                 std::ostringstream src;
222                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
223                         << "layout(location = 0) flat in highp   vec4 v_color;\n"
224                         << "layout(location = 0) out     mediump vec4 fragColor;\n"
225                         << "\n"
226                         << "void main (void)\n"
227                         << "{\n"
228                         << "    fragColor = v_color;\n"
229                         << "}\n";
230
231                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
232         }
233
234         // Tessellation control
235         {
236                 std::ostringstream src;
237                 src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
238                                 "#extension GL_EXT_tessellation_shader : require\n"
239                                 "layout(vertices = 1) out;\n"
240                                 "\n"
241                                 "void main (void)\n"
242                                 "{\n"
243                                 "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
244                                 "    gl_TessLevelInner[0] = float(" << m_tessGenLevel << ");\n"
245                                 "    gl_TessLevelInner[1] = float(" << m_tessGenLevel << ");\n"
246                                 "    gl_TessLevelOuter[0] = float(" << m_tessGenLevel << ");\n"
247                                 "    gl_TessLevelOuter[1] = float(" << m_tessGenLevel << ");\n"
248                                 "    gl_TessLevelOuter[2] = float(" << m_tessGenLevel << ");\n"
249                                 "    gl_TessLevelOuter[3] = float(" << m_tessGenLevel << ");\n"
250                                 "}\n";
251
252                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
253         }
254
255         // Tessellation evaluation
256         {
257                 std::ostringstream src;
258                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
259                         << "#extension GL_EXT_tessellation_shader : require\n"
260                         << "layout(quads) in;\n"
261                         << "\n"
262                         << "layout(location = 0) out mediump ivec2 v_tessellationGridPosition;\n"
263                         << "\n"
264                         << "// note: No need to use precise gl_Position since position does not depend on order\n"
265                         << "void main (void)\n"
266                         << "{\n";
267
268                 if (m_flags & (FLAG_GEOMETRY_SCATTER_INSTANCES | FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS))
269                         src << "    // Cover only a small area in a corner. The area will be expanded in geometry shader to cover whole viewport\n"
270                                 << "    gl_Position = vec4(gl_TessCoord.x * 0.3 - 1.0, gl_TessCoord.y * 0.3 - 1.0, 0.0, 1.0);\n";
271                 else
272                         src << "    // Fill the whole viewport\n"
273                                 << "    gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n";
274
275                 src << "    // Calculate position in tessellation grid\n"
276                         << "    v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << m_tessGenLevel << ")));\n"
277                         << "}\n";
278
279                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
280         }
281
282         // Geometry shader
283         {
284                 const int numInvocations = m_numGeometryInvocations;
285                 const int numPrimitives  = m_numGeometryPrimitivesPerInvocation;
286
287                 std::ostringstream src;
288
289                 src     << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
290                         << "#extension GL_EXT_geometry_shader : require\n"
291                         << "layout(triangles, invocations = " << numInvocations << ") in;\n"
292                         << "layout(triangle_strip, max_vertices = " << ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) ? (4 * numPrimitives) : (numPrimitives + 2)) << ") out;\n"
293                         << "\n"
294                         << "layout(location = 0) in       mediump ivec2 v_tessellationGridPosition[];\n"
295                         << "layout(location = 0) flat out highp   vec4  v_color;\n"
296                         << "\n"
297                         << "void main (void)\n"
298                         << "{\n"
299                         << "    const float equalThreshold = 0.001;\n"
300                         << "    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"
301                         << "\n"
302                         << "    // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
303                         << "    // Original rectangle can be found by finding the bounding AABB of the triangle\n"
304                         << "    vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
305                         << "                     min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
306                         << "                     max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
307                         << "                     max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
308                         << "\n"
309                         << "    // Location in tessellation grid\n"
310                         << "    ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
311                         << "\n"
312                         << "    // Which triangle of the two that split the grid cell\n"
313                         << "    int numVerticesOnBottomEdge = 0;\n"
314                         << "    for (int ndx = 0; ndx < 3; ++ndx)\n"
315                         << "        if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
316                         << "            ++numVerticesOnBottomEdge;\n"
317                         << "    bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
318                         << "\n";
319
320                 if (m_flags & FLAG_GEOMETRY_SCATTER_PRIMITIVES)
321                 {
322                         // scatter primitives
323                         src << "    // Draw grid cells\n"
324                                 << "    int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
325                                 << "    for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
326                                 << "    {\n"
327                                 << "        ivec2 dstGridSize = ivec2(" << m_tessGenLevel << " * " << numPrimitives << ", 2 * " << m_tessGenLevel << " * " << numInvocations << ");\n"
328                                 << "        ivec2 dstGridNdx = ivec2(" << m_tessGenLevel << " * ndx + gridPosition.x, " << m_tessGenLevel << " * inputTriangleNdx + 2 * gridPosition.y + ndx * 127) % dstGridSize;\n"
329                                 << "        vec4 dstArea;\n"
330                                 << "        dstArea.x = float(dstGridNdx.x)   / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
331                                 << "        dstArea.y = float(dstGridNdx.y)   / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
332                                 << "        dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
333                                 << "        dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
334                                 << "\n"
335                                 << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
336                                 << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
337                                 << "        vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
338                                 << "\n"
339                                 << "        gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
340                                 << "        v_color = outputColor;\n"
341                                 << "        EmitVertex();\n"
342                                 << "\n"
343                                 << "        gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
344                                 << "        v_color = outputColor;\n"
345                                 << "        EmitVertex();\n"
346                                 << "\n"
347                                 << "        gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
348                                 << "        v_color = outputColor;\n"
349                                 << "        EmitVertex();\n"
350                                 << "\n"
351                                 << "        gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
352                                 << "        v_color = outputColor;\n"
353                                 << "        EmitVertex();\n"
354                                 << "        EndPrimitive();\n"
355                                 << "    }\n";
356                 }
357                 else if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
358                 {
359                         // Number of subrectangle instances = num layers
360                         DE_ASSERT(m_numLayers == numInvocations * 2);
361
362                         src << "    // Draw grid cells, send each primitive to a separate layer\n"
363                                 << "    int baseLayer = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
364                                 << "    for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
365                                 << "    {\n"
366                                 << "        ivec2 dstGridSize = ivec2(" << m_tessGenLevel << " * " << numPrimitives << ", " << m_tessGenLevel << ");\n"
367                                 << "        ivec2 dstGridNdx = ivec2((gridPosition.x * " << numPrimitives << " * 7 + ndx)*13, (gridPosition.y * 127 + ndx) * 19) % dstGridSize;\n"
368                                 << "        vec4 dstArea;\n"
369                                 << "        dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
370                                 << "        dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
371                                 << "        dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
372                                 << "        dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
373                                 << "\n"
374                                 << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
375                                 << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
376                                 << "        vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
377                                 << "\n"
378                                 << "        gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
379                                 << "        v_color = outputColor;\n"
380                                 << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
381                                 << "        EmitVertex();\n"
382                                 << "\n"
383                                 << "        gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
384                                 << "        v_color = outputColor;\n"
385                                 << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
386                                 << "        EmitVertex();\n"
387                                 << "\n"
388                                 << "        gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
389                                 << "        v_color = outputColor;\n"
390                                 << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
391                                 << "        EmitVertex();\n"
392                                 << "\n"
393                                 << "        gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
394                                 << "        v_color = outputColor;\n"
395                                 << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
396                                 << "        EmitVertex();\n"
397                                 << "        EndPrimitive();\n"
398                                 << "    }\n";
399                 }
400                 else
401                 {
402                         if (m_flags & FLAG_GEOMETRY_SCATTER_INSTANCES)
403                         {
404                                 src << "    // Scatter slices\n"
405                                         << "    int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
406                                         << "    ivec2 srcSliceNdx = ivec2(gridPosition.x, gridPosition.y * " << (numInvocations*2) << " + inputTriangleNdx);\n"
407                                         << "    ivec2 dstSliceNdx = ivec2(7 * srcSliceNdx.x, 127 * srcSliceNdx.y) % ivec2(" << m_tessGenLevel << ", " << m_tessGenLevel << " * " << (numInvocations*2) << ");\n"
408                                         << "\n"
409                                         << "    // Draw slice to the dstSlice slot\n"
410                                         << "    vec4 outputSliceArea;\n"
411                                         << "    outputSliceArea.x = float(dstSliceNdx.x)   / float(" << m_tessGenLevel << ") * 2.0 - 1.0 - gapOffset;\n"
412                                         << "    outputSliceArea.y = float(dstSliceNdx.y)   / float(" << (m_tessGenLevel * numInvocations * 2) << ") * 2.0 - 1.0 - gapOffset;\n"
413                                         << "    outputSliceArea.z = float(dstSliceNdx.x+1) / float(" << m_tessGenLevel << ") * 2.0 - 1.0 + gapOffset;\n"
414                                         << "    outputSliceArea.w = float(dstSliceNdx.y+1) / float(" << (m_tessGenLevel * numInvocations * 2) << ") * 2.0 - 1.0 + gapOffset;\n";
415                         }
416                         else
417                         {
418                                 src << "    // Fill the input area with slices\n"
419                                         << "    // Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
420                                         << "    float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
421                                         << "    // Each slice is a invocation\n"
422                                         << "    float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInvocations << ");\n"
423                                         << "    float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
424                                         << "\n"
425                                         << "    vec4 outputSliceArea;\n"
426                                         << "    outputSliceArea.x = aabb.x - gapOffset;\n"
427                                         << "    outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
428                                         << "    outputSliceArea.z = aabb.z + gapOffset;\n"
429                                         << "    outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n";
430                         }
431
432                         src << "\n"
433                                 << "    // Draw slice\n"
434                                 << "    for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
435                                 << "    {\n"
436                                 << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
437                                 << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
438                                 << "        vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
439                                 << "        float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
440                                 << "\n"
441                                 << "        gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
442                                 << "        v_color = outputColor;\n"
443                                 << "        EmitVertex();\n"
444                                 << "\n"
445                                 << "        gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
446                                 << "        v_color = outputColor;\n"
447                                 << "        EmitVertex();\n"
448                                 << "    }\n";
449                 }
450
451                 src <<  "}\n";
452
453                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
454         }
455 }
456
457 class GridRenderTestInstance : public TestInstance
458 {
459 public:
460         struct Params
461         {
462                 Flags   flags;
463                 int             numLayers;
464
465                 Params (void) : flags(), numLayers() {}
466         };
467                                                 GridRenderTestInstance  (Context& context, const Params& params) : TestInstance(context), m_params(params) {}
468         tcu::TestStatus         iterate                                 (void);
469
470 private:
471         Params                          m_params;
472 };
473
474 TestInstance* GridRenderTestCase::createInstance (Context& context) const
475 {
476         GridRenderTestInstance::Params params;
477
478         params.flags     = m_flags;
479         params.numLayers = m_numLayers;
480
481         return new GridRenderTestInstance(context, params);
482 }
483
484 bool verifyResultLayer (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& image, const int layerNdx)
485 {
486         tcu::Surface errorMask  (image.getWidth(), image.getHeight());
487         bool             foundError     = false;
488
489         tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
490
491         log << tcu::TestLog::Message << "Verifying output layer " << layerNdx  << tcu::TestLog::EndMessage;
492
493         for (int y = 0; y < image.getHeight(); ++y)
494         for (int x = 0; x < image.getWidth(); ++x)
495         {
496                 const int               threshold       = 8;
497                 const tcu::RGBA color           (image.getPixel(x, y));
498
499                 // Color must be a linear combination of green and yellow
500                 if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
501                 {
502                         errorMask.setPixel(x, y, tcu::RGBA::red());
503                         foundError = true;
504                 }
505         }
506
507         if (!foundError)
508         {
509                 log << tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
510                         << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
511                         << tcu::TestLog::Image("Result", "Rendered result", image)
512                         << tcu::TestLog::EndImageSet;
513                 return true;
514         }
515         else
516         {
517                 log     << tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
518                         << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
519                         << tcu::TestLog::Image("Result", "Rendered result", image)
520                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
521                         << tcu::TestLog::EndImageSet;
522                 return false;
523         }
524 }
525
526 tcu::TestStatus GridRenderTestInstance::iterate (void)
527 {
528         requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER);
529
530         m_context.getTestContext().getLog()
531                 << tcu::TestLog::Message
532                 << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)."
533                 << tcu::TestLog::EndMessage;
534
535         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
536         const VkDevice                  device                          = m_context.getDevice();
537         const VkQueue                   queue                           = m_context.getUniversalQueue();
538         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
539         Allocator&                              allocator                       = m_context.getDefaultAllocator();
540
541         // Color attachment
542
543         const tcu::IVec2                          renderSize                       = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
544         const VkFormat                            colorFormat                      = VK_FORMAT_R8G8B8A8_UNORM;
545         const VkImageSubresourceRange colorImageAllLayersRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.numLayers);
546         const VkImageCreateInfo           colorImageCreateInfo     = makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, m_params.numLayers);
547         const VkImageViewType             colorAttachmentViewType  = (m_params.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
548         const Image                                       colorAttachmentImage     (vk, device, allocator, colorImageCreateInfo, MemoryRequirement::Any);
549
550         // Color output buffer: image will be copied here for verification (big enough for all layers).
551
552         const VkDeviceSize      colorBufferSizeBytes    = renderSize.x()*renderSize.y() * m_params.numLayers * tcu::getPixelSize(mapVkFormat(colorFormat));
553         const Buffer            colorBuffer                             (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
554
555         // Pipeline: no vertex input attributes nor descriptors.
556
557         const Unique<VkImageView>               colorAttachmentView     (makeImageView                  (vk, device, *colorAttachmentImage, colorAttachmentViewType, colorFormat, colorImageAllLayersRange));
558         const Unique<VkRenderPass>              renderPass                      (makeRenderPass                 (vk, device, colorFormat));
559         const Unique<VkFramebuffer>             framebuffer                     (makeFramebuffer                (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), m_params.numLayers));
560         const Unique<VkPipelineLayout>  pipelineLayout          (makePipelineLayout             (vk, device));
561         const Unique<VkCommandPool>             cmdPool                         (makeCommandPool                (vk, device, queueFamilyIndex));
562         const Unique<VkCommandBuffer>   cmdBuffer                       (allocateCommandBuffer  (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
563
564         const Unique<VkPipeline> pipeline (GraphicsPipelineBuilder()
565                 .setRenderSize  (renderSize)
566                 .setShader              (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                  m_context.getBinaryCollection().get("vert"), DE_NULL)
567                 .setShader              (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                m_context.getBinaryCollection().get("frag"), DE_NULL)
568                 .setShader              (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), DE_NULL)
569                 .setShader              (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
570                 .setShader              (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                                m_context.getBinaryCollection().get("geom"), DE_NULL)
571                 .build                  (vk, device, *pipelineLayout, *renderPass));
572
573         beginCommandBuffer(vk, *cmdBuffer);
574
575         // Change color attachment image layout
576         {
577                 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
578                         (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
579                         VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
580                         *colorAttachmentImage, colorImageAllLayersRange);
581
582                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
583                         0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
584         }
585
586         // Begin render pass
587         {
588                 const VkRect2D  renderArea      = makeRect2D(renderSize);
589                 const tcu::Vec4 clearColor      (0.0f, 0.0f, 0.0f, 1.0f);
590
591                 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
592         }
593
594         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
595
596         vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
597         endRenderPass(vk, *cmdBuffer);
598
599         // Copy render result to a host-visible buffer
600         copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, m_params.numLayers);
601
602         endCommandBuffer(vk, *cmdBuffer);
603         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
604
605         // Verify results
606         {
607                 const Allocation&                                       alloc                   (colorBuffer.getAllocation());
608
609                 invalidateAlloc(vk, device, alloc);
610
611                 const tcu::ConstPixelBufferAccess       imageAllLayers  (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), m_params.numLayers, alloc.getHostPtr());
612                 bool                                                            allOk                   (true);
613
614                 for (int ndx = 0; ndx < m_params.numLayers; ++ndx)
615                         allOk = allOk && verifyResultLayer(m_context.getTestContext().getLog(),
616                                                                                            tcu::getSubregion(imageAllLayers, 0, 0, ndx, renderSize.x(), renderSize.y(), 1),
617                                                                                            ndx);
618
619                 return (allOk ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed"));
620         }
621 }
622
623 struct TestCaseDescription
624 {
625         const char*     name;
626         const char*     desc;
627         Flags           flags;
628 };
629
630 } // anonymous
631
632 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.limits.*
633 //! \note Tests that check implementation defined limits were omitted, because they rely on runtime shader source generation
634 //!       (e.g. changing the number of vertices output from geometry shader). CTS currently doesn't support that,
635 //!       because some platforms require precompiled shaders.
636 tcu::TestCaseGroup* createGeometryGridRenderLimitsTests  (tcu::TestContext& testCtx)
637 {
638         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "limits", "Render with properties near their limits"));
639
640         static const TestCaseDescription cases[] =
641         {
642                 {
643                         "output_required_max_tessellation",
644                         "Minimum maximum tessellation level",
645                         FLAG_TESSELLATION_MAX_SPEC
646                 },
647                 {
648                         "output_required_max_geometry",
649                         "Output minimum maximum number of vertices the geometry shader",
650                         FLAG_GEOMETRY_MAX_SPEC
651                 },
652                 {
653                         "output_required_max_invocations",
654                         "Minimum maximum number of geometry shader invocations",
655                         FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
656                 },
657         };
658
659         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
660                 group->addChild(new GridRenderTestCase(testCtx, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
661
662         return group.release();
663 }
664
665 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.scatter.*
666 tcu::TestCaseGroup* createGeometryGridRenderScatterTests (tcu::TestContext& testCtx)
667 {
668         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "scatter", "Scatter output primitives"));
669
670         static const TestCaseDescription cases[] =
671         {
672                 {
673                         "geometry_scatter_instances",
674                         "Each geometry shader instance outputs its primitives far from other instances of the same execution",
675                         FLAG_GEOMETRY_SCATTER_INSTANCES
676                 },
677                 {
678                         "geometry_scatter_primitives",
679                         "Each geometry shader instance outputs its primitives far from other primitives of the same instance",
680                         FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SEPARATE_PRIMITIVES
681                 },
682                 {
683                         "geometry_scatter_layers",
684                         "Each geometry shader instance outputs its primitives to multiple layers and far from other primitives of the same instance",
685                         FLAG_GEOMETRY_SCATTER_LAYERS | FLAG_GEOMETRY_SEPARATE_PRIMITIVES
686                 },
687         };
688
689         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
690                 group->addChild(new GridRenderTestCase(testCtx, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
691
692         return group.release();
693 }
694
695 } // tessellation
696 } // vkt