Geometry interaction tessellation tests
authorMaciej Jesionowski <maciej.jesionowski@mobica.com>
Wed, 6 Apr 2016 09:45:46 +0000 (11:45 +0200)
committerMaciej Jesionowski <maciej.jesionowski@mobica.com>
Mon, 16 May 2016 10:26:48 +0000 (12:26 +0200)
Ported from GLES 3.1

Some features were excluded:
- Transform Feedback related tests
- tests that required true runtime shader generation
  (because we need to support precompiled shaders)

external/vulkancts/modules/vulkan/tessellation/CMakeLists.txt
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/tessellation/vktTessellationTests.cpp
external/vulkancts/mustpass/1.0.0/vk-default.txt

index 78b7f0e..b204339 100644 (file)
@@ -25,6 +25,12 @@ set(DEQP_VK_TESSELLATION_SRCS
        vktTessellationInvarianceTests.cpp
        vktTessellationUserDefinedIO.hpp
        vktTessellationUserDefinedIO.cpp
+       vktTessellationGeometryPassthroughTests.hpp
+       vktTessellationGeometryPassthroughTests.cpp
+       vktTessellationGeometryPointSizeTests.hpp
+       vktTessellationGeometryPointSizeTests.cpp
+       vktTessellationGeometryGridRenderTests.hpp
+       vktTessellationGeometryGridRenderTests.cpp
        )
 
 set(DEQP_VK_TESSELLATION_LIBS
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.cpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.cpp
new file mode 100644 (file)
index 0000000..d7bd3a1
--- /dev/null
@@ -0,0 +1,715 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tessellation Geometry Interaction - Grid render (limits, scatter)
+*//*--------------------------------------------------------------------*/
+
+#include "vktTessellationGeometryGridRenderTests.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vktTessellationUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuSurface.hpp"
+#include "tcuRGBA.hpp"
+
+#include "vkDefs.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkImageUtil.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include <string>
+#include <vector>
+
+namespace vkt
+{
+namespace tessellation
+{
+
+using namespace vk;
+
+namespace
+{
+
+enum Constants
+{
+       RENDER_SIZE = 256,
+};
+
+enum FlagBits
+{
+       FLAG_TESSELLATION_MAX_SPEC                      = 1u << 0,
+       FLAG_GEOMETRY_MAX_SPEC                          = 1u << 1,
+       FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC      = 1u << 2,
+
+       FLAG_GEOMETRY_SCATTER_INSTANCES         = 1u << 3,
+       FLAG_GEOMETRY_SCATTER_PRIMITIVES        = 1u << 4,
+       FLAG_GEOMETRY_SEPARATE_PRIMITIVES       = 1u << 5, //!< if set, geometry shader outputs separate grid cells and not continuous slices
+       FLAG_GEOMETRY_SCATTER_LAYERS            = 1u << 6,
+};
+typedef deUint32 Flags;
+
+class GridRenderTestCase : public TestCase
+{
+public:
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const;
+       TestInstance*   createInstance                  (Context& context) const;
+
+                                       GridRenderTestCase              (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Flags flags);
+
+private:
+       const Flags             m_flags;
+       const int               m_tessGenLevel;
+       const int               m_numGeometryInvocations;
+       const int               m_numLayers;
+       int                             m_numGeometryPrimitivesPerInvocation;
+};
+
+GridRenderTestCase::GridRenderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Flags flags)
+       : TestCase                                      (testCtx, name, description)
+       , m_flags                                       (flags)
+       , m_tessGenLevel                        ((m_flags & FLAG_TESSELLATION_MAX_SPEC)                 ? 64 : 5)
+       , m_numGeometryInvocations      ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) ? 32 : 4)
+       , m_numLayers                           ((m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)               ? 8  : 1)
+{
+       DE_ASSERT(((flags & (FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS)) != 0) == ((flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0));
+
+       testCtx.getLog()
+               << tcu::TestLog::Message
+               << "Testing tessellation and geometry shaders that output a large number of primitives.\n"
+               << getDescription()
+               << tcu::TestLog::EndMessage;
+
+       if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
+               m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to 2d texture array, numLayers = " << m_numLayers << tcu::TestLog::EndMessage;
+
+       m_testCtx.getLog()
+               << tcu::TestLog::Message
+               << "Tessellation level: " << m_tessGenLevel << ", mode = quad.\n"
+               << "\tEach input patch produces " << (m_tessGenLevel*m_tessGenLevel) << " (" << (m_tessGenLevel*m_tessGenLevel*2) << " triangles)\n"
+               << tcu::TestLog::EndMessage;
+
+       int geometryOutputComponents      = 0;
+       int geometryOutputVertices                = 0;
+       int geometryTotalOutputComponents = 0;
+
+       if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
+       {
+               m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader minimum maximum output limits." << tcu::TestLog::EndMessage;
+
+               geometryOutputComponents          = 64;
+               geometryOutputVertices            = 256;
+               geometryTotalOutputComponents = 1024;
+       }
+       else
+       {
+               geometryOutputComponents          = 64;
+               geometryOutputVertices            = 16;
+               geometryTotalOutputComponents = 1024;
+       }
+
+       if ((m_flags & FLAG_GEOMETRY_MAX_SPEC) || (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC))
+       {
+               tcu::MessageBuilder msg(&m_testCtx.getLog());
+
+               msg << "Geometry shader, targeting following limits:\n";
+
+               if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
+                       msg     << "\tmaxGeometryOutputComponents = "      << geometryOutputComponents << "\n"
+                               << "\tmaxGeometryOutputVertices = "                << geometryOutputVertices << "\n"
+                               << "\tmaxGeometryTotalOutputComponents = " << geometryTotalOutputComponents << "\n";
+
+               if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
+                       msg << "\tmaxGeometryShaderInvocations = "         << m_numGeometryInvocations;
+
+               msg << tcu::TestLog::EndMessage;
+       }
+
+       const bool      separatePrimitives                                = (m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0;
+       const int       numComponentsPerVertex                    = 8; // vec4 pos, vec4 color
+       int                     numVerticesPerInvocation                  = 0;
+       int                     geometryVerticesPerPrimitive      = 0;
+       int                     geometryPrimitivesOutPerPrimitive = 0;
+
+       if (separatePrimitives)
+       {
+               const int       numComponentLimit                = geometryTotalOutputComponents / (4 * numComponentsPerVertex);
+               const int       numOutputLimit                   = geometryOutputVertices / 4;
+
+               m_numGeometryPrimitivesPerInvocation = de::min(numComponentLimit, numOutputLimit);
+               numVerticesPerInvocation                         = m_numGeometryPrimitivesPerInvocation * 4;
+       }
+       else
+       {
+               // If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
+               // Each slice is a triangle strip and is generated by a single shader invocation.
+               // One slice with 4 segment ends (nodes) and 3 segments:
+               //    .__.__.__.
+               //    |\ |\ |\ |
+               //    |_\|_\|_\|
+
+               const int       numSliceNodesComponentLimit     = geometryTotalOutputComponents / (2 * numComponentsPerVertex);                 // each node 2 vertices
+               const int       numSliceNodesOutputLimit        = geometryOutputVertices / 2;                                                                                   // each node 2 vertices
+               const int       numSliceNodes                           = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
+
+               numVerticesPerInvocation                                = numSliceNodes * 2;
+               m_numGeometryPrimitivesPerInvocation    = (numSliceNodes - 1) * 2;
+       }
+
+       geometryVerticesPerPrimitive      = numVerticesPerInvocation * m_numGeometryInvocations;
+       geometryPrimitivesOutPerPrimitive = m_numGeometryPrimitivesPerInvocation * m_numGeometryInvocations;
+
+       m_testCtx.getLog()
+               << tcu::TestLog::Message
+               << "Geometry shader:\n"
+               << "\tTotal output vertex count per invocation: "                 << numVerticesPerInvocation << "\n"
+               << "\tTotal output primitive count per invocation: "      << m_numGeometryPrimitivesPerInvocation << "\n"
+               << "\tNumber of invocations per primitive: "                      << m_numGeometryInvocations << "\n"
+               << "\tTotal output vertex count per input primitive: "    << geometryVerticesPerPrimitive << "\n"
+               << "\tTotal output primitive count per input primitive: " << geometryPrimitivesOutPerPrimitive << "\n"
+               << tcu::TestLog::EndMessage;
+
+       m_testCtx.getLog()
+               << tcu::TestLog::Message
+               << "Program:\n"
+               << "\tTotal program output vertices count per input patch: "  << (m_tessGenLevel*m_tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
+               << "\tTotal program output primitive count per input patch: " << (m_tessGenLevel*m_tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
+               << tcu::TestLog::EndMessage;
+}
+
+void GridRenderTestCase::initPrograms (SourceCollections& programCollection) const
+{
+       // Vertex shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "layout(location = 0) flat in mediump vec4 v_color;\n"
+                       << "layout(location = 0) out     mediump vec4 fragColor;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    fragColor = v_color;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+
+       // Tessellation control
+       {
+               std::ostringstream src;
+               src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                               "#extension GL_EXT_tessellation_shader : require\n"
+                               "layout(vertices = 1) out;\n"
+                               "\n"
+                               "void main (void)\n"
+                               "{\n"
+                               "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+                               "    gl_TessLevelInner[0] = float(" << m_tessGenLevel << ");\n"
+                               "    gl_TessLevelInner[1] = float(" << m_tessGenLevel << ");\n"
+                               "    gl_TessLevelOuter[0] = float(" << m_tessGenLevel << ");\n"
+                               "    gl_TessLevelOuter[1] = float(" << m_tessGenLevel << ");\n"
+                               "    gl_TessLevelOuter[2] = float(" << m_tessGenLevel << ");\n"
+                               "    gl_TessLevelOuter[3] = float(" << m_tessGenLevel << ");\n"
+                               "}\n";
+
+               programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
+       }
+
+       // Tessellation evaluation
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_tessellation_shader : require\n"
+                       << "layout(quads) in;\n"
+                       << "\n"
+                       << "layout(location = 0) out mediump ivec2 v_tessellationGridPosition;\n"
+                       << "\n"
+                       << "// note: No need to use precise gl_Position since position does not depend on order\n"
+                       << "void main (void)\n"
+                       << "{\n";
+
+               if (m_flags & (FLAG_GEOMETRY_SCATTER_INSTANCES | FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS))
+                       src << "    // Cover only a small area in a corner. The area will be expanded in geometry shader to cover whole viewport\n"
+                               << "    gl_Position = vec4(gl_TessCoord.x * 0.3 - 1.0, gl_TessCoord.y * 0.3 - 1.0, 0.0, 1.0);\n";
+               else
+                       src << "    // Fill the whole viewport\n"
+                               << "    gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n";
+
+               src << "    // Calculate position in tessellation grid\n"
+                       << "    v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << m_tessGenLevel << ")));\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
+       }
+
+       // Geometry shader
+       {
+               const int numInvocations = m_numGeometryInvocations;
+               const int numPrimitives  = m_numGeometryPrimitivesPerInvocation;
+
+               std::ostringstream src;
+
+               src     << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_geometry_shader : require\n"
+                       << "layout(triangles, invocations = " << numInvocations << ") in;\n"
+                       << "layout(triangle_strip, max_vertices = " << ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) ? (4 * numPrimitives) : (numPrimitives + 2)) << ") out;\n"
+                       << "\n"
+                       << "layout(location = 0) in       mediump ivec2 v_tessellationGridPosition[];\n"
+                       << "layout(location = 0) flat out highp   vec4  v_color;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    const float equalThreshold = 0.001;\n"
+                       << "    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"
+                       << "\n"
+                       << "    // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
+                       << "    // Original rectangle can be found by finding the bounding AABB of the triangle\n"
+                       << "    vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
+                       << "                     min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
+                       << "                     max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
+                       << "                     max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
+                       << "\n"
+                       << "    // Location in tessellation grid\n"
+                       << "    ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
+                       << "\n"
+                       << "    // Which triangle of the two that split the grid cell\n"
+                       << "    int numVerticesOnBottomEdge = 0;\n"
+                       << "    for (int ndx = 0; ndx < 3; ++ndx)\n"
+                       << "        if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
+                       << "            ++numVerticesOnBottomEdge;\n"
+                       << "    bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
+                       << "\n";
+
+               if (m_flags & FLAG_GEOMETRY_SCATTER_PRIMITIVES)
+               {
+                       // scatter primitives
+                       src << "    // Draw grid cells\n"
+                               << "    int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
+                               << "    for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
+                               << "    {\n"
+                               << "        ivec2 dstGridSize = ivec2(" << m_tessGenLevel << " * " << numPrimitives << ", 2 * " << m_tessGenLevel << " * " << numInvocations << ");\n"
+                               << "        ivec2 dstGridNdx = ivec2(" << m_tessGenLevel << " * ndx + gridPosition.x, " << m_tessGenLevel << " * inputTriangleNdx + 2 * gridPosition.y + ndx * 127) % dstGridSize;\n"
+                               << "        vec4 dstArea;\n"
+                               << "        dstArea.x = float(dstGridNdx.x)   / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
+                               << "        dstArea.y = float(dstGridNdx.y)   / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
+                               << "        dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
+                               << "        dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
+                               << "\n"
+                               << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "        EndPrimitive();\n"
+                               << "    }\n";
+               }
+               else if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
+               {
+                       // Number of subrectangle instances = num layers
+                       DE_ASSERT(m_numLayers == numInvocations * 2);
+
+                       src << "    // Draw grid cells, send each primitive to a separate layer\n"
+                               << "    int baseLayer = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
+                               << "    for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
+                               << "    {\n"
+                               << "        ivec2 dstGridSize = ivec2(" << m_tessGenLevel << " * " << numPrimitives << ", " << m_tessGenLevel << ");\n"
+                               << "        ivec2 dstGridNdx = ivec2((gridPosition.x * " << numPrimitives << " * 7 + ndx)*13, (gridPosition.y * 127 + ndx) * 19) % dstGridSize;\n"
+                               << "        vec4 dstArea;\n"
+                               << "        dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
+                               << "        dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
+                               << "        dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
+                               << "        dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
+                               << "\n"
+                               << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
+                               << "        EmitVertex();\n"
+                               << "        EndPrimitive();\n"
+                               << "    }\n";
+               }
+               else
+               {
+                       if (m_flags & FLAG_GEOMETRY_SCATTER_INSTANCES)
+                       {
+                               src << "    // Scatter slices\n"
+                                       << "    int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
+                                       << "    ivec2 srcSliceNdx = ivec2(gridPosition.x, gridPosition.y * " << (numInvocations*2) << " + inputTriangleNdx);\n"
+                                       << "    ivec2 dstSliceNdx = ivec2(7 * srcSliceNdx.x, 127 * srcSliceNdx.y) % ivec2(" << m_tessGenLevel << ", " << m_tessGenLevel << " * " << (numInvocations*2) << ");\n"
+                                       << "\n"
+                                       << "    // Draw slice to the dstSlice slot\n"
+                                       << "    vec4 outputSliceArea;\n"
+                                       << "    outputSliceArea.x = float(dstSliceNdx.x)   / float(" << m_tessGenLevel << ") * 2.0 - 1.0 - gapOffset;\n"
+                                       << "    outputSliceArea.y = float(dstSliceNdx.y)   / float(" << (m_tessGenLevel * numInvocations * 2) << ") * 2.0 - 1.0 - gapOffset;\n"
+                                       << "    outputSliceArea.z = float(dstSliceNdx.x+1) / float(" << m_tessGenLevel << ") * 2.0 - 1.0 + gapOffset;\n"
+                                       << "    outputSliceArea.w = float(dstSliceNdx.y+1) / float(" << (m_tessGenLevel * numInvocations * 2) << ") * 2.0 - 1.0 + gapOffset;\n";
+                       }
+                       else
+                       {
+                               src << "    // Fill the input area with slices\n"
+                                       << "    // Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
+                                       << "    float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
+                                       << "    // Each slice is a invocation\n"
+                                       << "    float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInvocations << ");\n"
+                                       << "    float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
+                                       << "\n"
+                                       << "    vec4 outputSliceArea;\n"
+                                       << "    outputSliceArea.x = aabb.x - gapOffset;\n"
+                                       << "    outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
+                                       << "    outputSliceArea.z = aabb.z + gapOffset;\n"
+                                       << "    outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n";
+                       }
+
+                       src << "\n"
+                               << "    // Draw slice\n"
+                               << "    for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
+                               << "    {\n"
+                               << "        vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                               << "        vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
+                               << "        float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
+                               << "\n"
+                               << "        gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "\n"
+                               << "        gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
+                               << "        v_color = outputColor;\n"
+                               << "        EmitVertex();\n"
+                               << "    }\n";
+               }
+
+               src <<  "}\n";
+
+               programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
+       }
+}
+
+class GridRenderTestInstance : public TestInstance
+{
+public:
+       struct Params
+       {
+               Flags   flags;
+               int             numLayers;
+
+               Params (void) : flags(), numLayers() {}
+       };
+                                               GridRenderTestInstance  (Context& context, const Params& params) : TestInstance(context), m_params(params) {}
+       tcu::TestStatus         iterate                                 (void);
+
+private:
+       Params                          m_params;
+};
+
+TestInstance* GridRenderTestCase::createInstance (Context& context) const
+{
+       GridRenderTestInstance::Params params;
+
+       params.flags     = m_flags;
+       params.numLayers = m_numLayers;
+
+       return new GridRenderTestInstance(context, params);
+}
+
+bool verifyResultLayer (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& image, const int layerNdx)
+{
+       tcu::Surface errorMask  (image.getWidth(), image.getHeight());
+       bool             foundError     = false;
+
+       tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
+
+       log << tcu::TestLog::Message << "Verifying output layer " << layerNdx  << tcu::TestLog::EndMessage;
+
+       for (int y = 0; y < image.getHeight(); ++y)
+       for (int x = 0; x < image.getWidth(); ++x)
+       {
+               const int               threshold       = 8;
+               const tcu::RGBA color           (image.getPixel(x, y));
+
+               // Color must be a linear combination of green and yellow
+               if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
+               {
+                       errorMask.setPixel(x, y, tcu::RGBA::red());
+                       foundError = true;
+               }
+       }
+
+       if (!foundError)
+       {
+               log << tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
+                       << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
+                       << tcu::TestLog::Image("Result", "Rendered result", image)
+                       << tcu::TestLog::EndImageSet;
+               return true;
+       }
+       else
+       {
+               log     << tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
+                       << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
+                       << tcu::TestLog::Image("Result", "Rendered result", image)
+                       << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
+                       << tcu::TestLog::EndImageSet;
+               return false;
+       }
+}
+
+tcu::TestStatus GridRenderTestInstance::iterate (void)
+{
+       requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER);
+
+       m_context.getTestContext().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;
+
+       const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
+       const VkDevice                  device                          = m_context.getDevice();
+       const VkQueue                   queue                           = m_context.getUniversalQueue();
+       const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       Allocator&                              allocator                       = m_context.getDefaultAllocator();
+
+       // Color attachment
+
+       const tcu::IVec2                          renderSize                       = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
+       const VkFormat                            colorFormat                      = VK_FORMAT_R8G8B8A8_UNORM;
+       const VkImageSubresourceRange colorImageAllLayersRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.numLayers);
+       const VkImageCreateInfo           colorImageCreateInfo     = makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, m_params.numLayers);
+       const VkImageViewType             colorAttachmentViewType  = (m_params.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
+       const Image                                       colorAttachmentImage     (vk, device, allocator, colorImageCreateInfo, MemoryRequirement::Any);
+
+       // Color output buffer: image will be copied here for verification (big enough for all layers).
+
+       const VkDeviceSize      colorBufferSizeBytes    = renderSize.x()*renderSize.y() * m_params.numLayers * tcu::getPixelSize(mapVkFormat(colorFormat));
+       const Buffer            colorBuffer                             (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
+
+       // Pipeline: no vertex input attributes nor descriptors.
+
+       const Unique<VkImageView>               colorAttachmentView(makeImageView                                               (vk, device, *colorAttachmentImage, colorAttachmentViewType, colorFormat, colorImageAllLayersRange));
+       const Unique<VkRenderPass>              renderPass                 (makeRenderPass                                              (vk, device, colorFormat));
+       const Unique<VkFramebuffer>             framebuffer                (makeFramebuffer                                             (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), m_params.numLayers));
+       const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayoutWithoutDescriptors(vk, device));
+       const Unique<VkCommandPool>             cmdPool                    (makeCommandPool                                             (vk, device, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer                  (makeCommandBuffer                                   (vk, device, *cmdPool));
+
+       const Unique<VkPipeline> pipeline (GraphicsPipelineBuilder()
+               .setRenderSize  (renderSize)
+               .setShader              (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                  m_context.getBinaryCollection().get("vert"), DE_NULL)
+               .setShader              (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                m_context.getBinaryCollection().get("frag"), DE_NULL)
+               .setShader              (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), DE_NULL)
+               .setShader              (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
+               .setShader              (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                                m_context.getBinaryCollection().get("geom"), DE_NULL)
+               .build                  (vk, device, *pipelineLayout, *renderPass));
+
+       beginCommandBuffer(vk, *cmdBuffer);
+
+       // Change color attachment image layout
+       {
+               const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
+                       (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                       *colorAttachmentImage, colorImageAllLayersRange);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
+                       0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
+       }
+
+       // Begin render pass
+       {
+               const VkRect2D renderArea = {
+                       makeOffset2D(0, 0),
+                       makeExtent2D(renderSize.x(), renderSize.y()),
+               };
+               const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+               beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
+       }
+
+       vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+
+       vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
+       endRenderPass(vk, *cmdBuffer);
+
+       // Copy render result to a host-visible buffer
+       {
+               const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                       *colorAttachmentImage, colorImageAllLayersRange);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
+                       0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
+       }
+       {
+               const VkImageSubresourceLayers subresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, m_params.numLayers);
+               const VkBufferImageCopy            copyRegion            = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 0), subresourceLayers);
+               vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
+       }
+       {
+               const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
+                       VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
+                       0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
+       }
+
+       endCommandBuffer(vk, *cmdBuffer);
+       submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+
+       // Verify results
+       {
+               const Allocation& alloc = colorBuffer.getAllocation();
+               invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
+
+               const tcu::ConstPixelBufferAccess imageAllLayers(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), m_params.numLayers, alloc.getHostPtr());
+
+               bool allOk = true;
+               for (int ndx = 0; ndx < m_params.numLayers; ++ndx)
+                       allOk = allOk && verifyResultLayer(m_context.getTestContext().getLog(),
+                                                                                          tcu::getSubregion(imageAllLayers, 0, 0, ndx, renderSize.x(), renderSize.y(), 1),
+                                                                                          ndx);
+
+               return (allOk ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed"));
+       }
+}
+
+struct TestCaseDescription
+{
+       const char*     name;
+       const char*     desc;
+       Flags           flags;
+};
+
+} // anonymous
+
+//! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.limits.*
+//! \note Tests that check implementation defined limits were omitted, because they rely on runtime shader source generation
+//!       (e.g. changing the number of vertices output from geometry shader). CTS currently doesn't support that,
+//!       because some platforms require precompiled shaders.
+tcu::TestCaseGroup* createGeometryGridRenderLimitsTests  (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "limits", "Render with properties near their limits"));
+
+       static const TestCaseDescription cases[] =
+       {
+               {
+                       "output_required_max_tessellation",
+                       "Minimum maximum tessellation level",
+                       FLAG_TESSELLATION_MAX_SPEC
+               },
+               {
+                       "output_required_max_geometry",
+                       "Output minimum maximum number of vertices the geometry shader",
+                       FLAG_GEOMETRY_MAX_SPEC
+               },
+               {
+                       "output_required_max_invocations",
+                       "Minimum maximum number of geometry shader invocations",
+                       FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
+               },
+       };
+
+       for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
+               group->addChild(new GridRenderTestCase(testCtx, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
+
+       return group.release();
+}
+
+//! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.scatter.*
+tcu::TestCaseGroup* createGeometryGridRenderScatterTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "scatter", "Scatter output primitives"));
+
+       static const TestCaseDescription cases[] =
+       {
+               {
+                       "geometry_scatter_instances",
+                       "Each geometry shader instance outputs its primitives far from other instances of the same execution",
+                       FLAG_GEOMETRY_SCATTER_INSTANCES
+               },
+               {
+                       "geometry_scatter_primitives",
+                       "Each geometry shader instance outputs its primitives far from other primitives of the same instance",
+                       FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SEPARATE_PRIMITIVES
+               },
+               {
+                       "geometry_scatter_layers",
+                       "Each geometry shader instance outputs its primitives to multiple layers and far from other primitives of the same instance",
+                       FLAG_GEOMETRY_SCATTER_LAYERS | FLAG_GEOMETRY_SEPARATE_PRIMITIVES
+               },
+       };
+
+       for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
+               group->addChild(new GridRenderTestCase(testCtx, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
+
+       return group.release();
+}
+
+} // tessellation
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.hpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryGridRenderTests.hpp
new file mode 100644 (file)
index 0000000..3d01d58
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _VKTTESSELLATIONGEOMETRYGRIDRENDERTESTS_HPP
+#define _VKTTESSELLATIONGEOMETRYGRIDRENDERTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tessellation Geometry Interaction - Grid render (limits, scatter)
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace tessellation
+{
+
+tcu::TestCaseGroup* createGeometryGridRenderLimitsTests  (tcu::TestContext& testCtx);
+tcu::TestCaseGroup* createGeometryGridRenderScatterTests (tcu::TestContext& testCtx);
+
+} // tessellation
+} // vkt
+
+#endif // _VKTTESSELLATIONGEOMETRYGRIDRENDERTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.cpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.cpp
new file mode 100644 (file)
index 0000000..37bc882
--- /dev/null
@@ -0,0 +1,730 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+* \brief Tessellation Geometry Interaction - Passthrough
+*//*--------------------------------------------------------------------*/
+
+#include "vktTessellationGeometryPassthroughTests.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vktTessellationUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuImageCompare.hpp"
+
+#include "vkDefs.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkImageUtil.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include <string>
+#include <vector>
+
+namespace vkt
+{
+namespace tessellation
+{
+
+using namespace vk;
+
+namespace
+{
+
+void addVertexAndFragmentShaders (vk::SourceCollections&  programCollection)
+{
+       // Vertex shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "\n"
+                       << "layout(location = 0) in  highp vec4 a_position;\n"
+                       << "layout(location = 0) out highp vec4 v_vertex_color;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_Position = a_position;\n"
+                       << "    v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "\n"
+                       << "layout(location = 0) in  mediump vec4 v_fragment_color;\n"
+                       << "layout(location = 0) out mediump vec4 fragColor;\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    fragColor = v_fragment_color;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+}
+
+//! Tessellation evaluation shader used in passthrough geometry shader case.
+std::string generateTessellationEvaluationShader (const TessPrimitiveType primitiveType, const std::string& colorOutputName)
+{
+       std::ostringstream      src;
+       src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+               << "#extension GL_EXT_tessellation_shader : require\n"
+               << "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ") in;\n"
+               << "\n"
+               << "layout(location = 0) in  highp vec4 v_patch_color[];\n"
+               << "layout(location = 0) out highp vec4 " << colorOutputName << ";\n"
+               << "\n"
+               << "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
+               << "void main (void)\n"
+               << "{\n";
+
+       if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
+               src << "    vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
+                       << "    vec3 cweights = gl_TessCoord;\n"
+                       << "    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"
+                       << "    " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
+       else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
+               src << "    vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
+                       << "    vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
+                       << "    vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
+                       << "    vec2 cweights = gl_TessCoord.xy;\n"
+                       << "    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"
+                       << "    " << 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";
+       else
+               DE_ASSERT(false);
+
+       src <<  "}\n";
+
+       return src.str();
+}
+
+class IdentityGeometryShaderTestCase : public TestCase
+{
+public:
+       void                    initPrograms    (vk::SourceCollections& programCollection) const;
+       TestInstance*   createInstance  (Context& context) const;
+
+       IdentityGeometryShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
+               : TestCase                      (testCtx, name, description)
+               , m_primitiveType       (primitiveType)
+       {
+       }
+
+private:
+       const TessPrimitiveType m_primitiveType;
+};
+
+void IdentityGeometryShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       addVertexAndFragmentShaders(programCollection);
+
+       // Tessellation control
+       {
+               std::ostringstream src;
+               src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_tessellation_shader : require\n"
+                       << "layout(vertices = 4) out;\n"
+                       << "\n"
+                       << "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
+                       << "    float inner0;\n"
+                       << "    float inner1;\n"
+                       << "    float outer0;\n"
+                       << "    float outer1;\n"
+                       << "    float outer2;\n"
+                       << "    float outer3;\n"
+                       << "} sb_levels;\n"
+                       << "\n"
+                       << "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
+                       << "layout(location = 0) out highp vec4 v_patch_color[];\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+                       << "    v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
+                       << "\n"
+                       << "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
+                       << "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
+                       << "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
+                       << "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
+                       << "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
+                       << "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
+                       <<      "}\n";
+
+               programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
+       }
+
+       // Tessellation evaluation shader
+       {
+               programCollection.glslSources.add("tese_to_frag")
+                       << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_fragment_color"));
+               programCollection.glslSources.add("tese_to_geom")
+                       << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_evaluated_color"));
+       }
+
+       // Geometry shader
+       {
+               std::ostringstream      src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_geometry_shader : require\n"
+                       << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(m_primitiveType, false) << ") in;\n"
+                       << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(m_primitiveType, false)
+                                                << ", max_vertices=" << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
+                       << "\n"
+                       << "layout(location = 0) in  highp vec4 v_evaluated_color[];\n"
+                       << "layout(location = 0) out highp vec4 v_fragment_color;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
+                       << "    {\n"
+                       << "        gl_Position = gl_in[ndx].gl_Position;\n"
+                       << "        v_fragment_color = v_evaluated_color[ndx];\n"
+                       << "        EmitVertex();\n"
+                       << "    }\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
+       }
+}
+
+class IdentityTessellationShaderTestCase : public TestCase
+{
+public:
+       void                    initPrograms    (vk::SourceCollections& programCollection) const;
+       TestInstance*   createInstance  (Context& context) const;
+
+       IdentityTessellationShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
+               : TestCase                      (testCtx, name, description)
+               , m_primitiveType       (primitiveType)
+       {
+       }
+
+private:
+       const TessPrimitiveType m_primitiveType;
+};
+
+//! Geometry shader used in passthrough tessellation shader case.
+std::string generateGeometryShader (const TessPrimitiveType primitiveType, const std::string& colorSourceName)
+{
+       const int numEmitVertices = (primitiveType == TESSPRIMITIVETYPE_ISOLINES ? 11 : 8);
+
+       std::ostringstream src;
+       src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+               << "#extension GL_EXT_geometry_shader : require\n"
+               << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, false) << ") in;\n"
+               << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, false)
+                                         << ", max_vertices=" << numEmitVertices << ") out;\n"
+               << "\n"
+               << "layout(location = 0) in  highp vec4 " << colorSourceName << "[];\n"
+               << "layout(location = 0) out highp vec4 v_fragment_color;\n"
+               << "\n"
+               << "void main (void)\n"
+               << "{\n";
+
+       if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
+       {
+               src << "        vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
+                       << "\n"
+                       << "    for (int ndx = 0; ndx < 4; ++ndx)\n"
+                       << "    {\n"
+                       << "            gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
+                       << "            v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
+                       << "            EmitVertex();\n"
+                       << "\n"
+                       << "            gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
+                       << "            v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
+                       << "            EmitVertex();\n"
+                       << "    }\n";
+       }
+       else if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
+       {
+               src << "        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"
+                       << "    for (int i = 0; i <= 10; ++i)\n"
+                       << "    {\n"
+                       << "            float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
+                       << "            float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
+                       << "            gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
+                       << "            v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
+                       << "            EmitVertex();\n"
+                       << "    }\n";
+       }
+       else
+               DE_ASSERT(false);
+
+       src << "}\n";
+
+       return src.str();
+}
+
+void IdentityTessellationShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       addVertexAndFragmentShaders(programCollection);
+
+       // Tessellation control
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_tessellation_shader : require\n"
+                       << "layout(vertices = " << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
+                       << "\n"
+                       << "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
+                       << "layout(location = 0) out highp vec4 v_control_color[];\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+                       << "    v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
+                       << "\n"
+                       << "    gl_TessLevelInner[0] = 1.0;\n"
+                       << "    gl_TessLevelInner[1] = 1.0;\n"
+                       << "    gl_TessLevelOuter[0] = 1.0;\n"
+                       << "    gl_TessLevelOuter[1] = 1.0;\n"
+                       << "    gl_TessLevelOuter[2] = 1.0;\n"
+                       << "    gl_TessLevelOuter[3] = 1.0;\n"
+                       <<      "}\n";
+
+               programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
+       }
+
+       // Tessellation evaluation shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_tessellation_shader : require\n"
+                       << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ") in;\n"
+                       << "\n"
+                       << "layout(location = 0) in  highp vec4 v_control_color[];\n"
+                       << "layout(location = 0) out highp vec4 v_evaluated_color;\n"
+                       << "\n"
+                       << "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
+                       << "void main (void)\n"
+                       << "{\n";
+
+               if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
+                       src << "    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"
+                               << "    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";
+               else if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
+                       src << "    gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
+                               << "    v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
+               else
+                       DE_ASSERT(false);
+
+               src << "}\n";
+
+               programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
+       }
+
+       // Geometry shader
+       {
+               programCollection.glslSources.add("geom_from_tese") << glu::GeometrySource(
+                       generateGeometryShader(m_primitiveType, "v_evaluated_color"));
+               programCollection.glslSources.add("geom_from_vert") << glu::GeometrySource(
+                       generateGeometryShader(m_primitiveType, "v_vertex_color"));
+       }
+}
+
+inline tcu::ConstPixelBufferAccess getPixelBufferAccess (const DeviceInterface& vk,
+                                                                                                                const VkDevice                 device,
+                                                                                                                const Buffer&                  colorBuffer,
+                                                                                                                const VkFormat                 colorFormat,
+                                                                                                                const VkDeviceSize             colorBufferSizeBytes,
+                                                                                                                const tcu::IVec2&              renderSize)
+{
+       const Allocation& alloc = colorBuffer.getAllocation();
+       invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
+       return tcu::ConstPixelBufferAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
+}
+
+//! When a test case disables tessellation stage and we need to derive a primitive type.
+VkPrimitiveTopology getPrimitiveTopology (const TessPrimitiveType primitiveType)
+{
+       switch (primitiveType)
+       {
+               case TESSPRIMITIVETYPE_TRIANGLES:
+               case TESSPRIMITIVETYPE_QUADS:
+                       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+               case TESSPRIMITIVETYPE_ISOLINES:
+                       return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+
+               default:
+                       DE_ASSERT(false);
+                       return VK_PRIMITIVE_TOPOLOGY_LAST;
+       }
+}
+
+enum Constants
+{
+       PIPELINE_CASES  = 2,
+       RENDER_SIZE             = 256,
+};
+
+class PassthroughTestInstance : public TestInstance
+{
+public:
+       struct PipelineDescription
+       {
+               bool            useTessellation;
+               bool            useGeometry;
+               std::string     tessEvalShaderName;
+               std::string     geomShaderName;
+               std::string description;
+
+               PipelineDescription (void) : useTessellation(), useGeometry() {}
+       };
+
+       struct Params
+       {
+               bool                                    useTessLevels;
+               TessLevels                              tessLevels;
+               TessPrimitiveType               primitiveType;
+               int                                             inputPatchVertices;
+               std::vector<tcu::Vec4>  vertices;
+               PipelineDescription             pipelineCases[PIPELINE_CASES];  //!< Each test case renders with two pipelines and compares results
+               std::string                             message;
+
+               Params (void) : useTessLevels(), tessLevels(), primitiveType(), inputPatchVertices() {}
+       };
+
+                                                               PassthroughTestInstance (Context& context, const Params& params) : TestInstance(context), m_params(params) {}
+       tcu::TestStatus                         iterate                                 (void);
+
+private:
+       const Params                            m_params;
+};
+
+tcu::TestStatus PassthroughTestInstance::iterate (void)
+{
+       requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER);
+       DE_STATIC_ASSERT(PIPELINE_CASES == 2);
+
+       const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
+       const VkDevice                  device                          = m_context.getDevice();
+       const VkQueue                   queue                           = m_context.getUniversalQueue();
+       const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       Allocator&                              allocator                       = m_context.getDefaultAllocator();
+
+       // Tessellation levels
+       const Buffer tessLevelsBuffer (vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
+
+       if (m_params.useTessLevels)
+       {
+               const Allocation& alloc = tessLevelsBuffer.getAllocation();
+               TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
+               *bufferTessLevels = m_params.tessLevels;
+               flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
+       }
+
+       // Vertex attributes
+
+       const VkDeviceSize      vertexDataSizeBytes = sizeInBytes(m_params.vertices);
+       const VkFormat          vertexFormat            = VK_FORMAT_R32G32B32A32_SFLOAT;
+       const Buffer            vertexBuffer            (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
+
+       {
+               const Allocation& alloc = vertexBuffer.getAllocation();
+               deMemcpy(alloc.getHostPtr(), &m_params.vertices[0], static_cast<std::size_t>(vertexDataSizeBytes));
+               flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
+       }
+
+       // Descriptors - make descriptor for tessellation levels, even if we don't use them, to simplify code
+
+       const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
+               .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+               .build(vk, device));
+
+       const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
+               .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+               .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
+
+       const Unique<VkDescriptorSet> descriptorSet                (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
+       const VkDescriptorBufferInfo  tessLevelsBufferInfo = makeDescriptorBufferInfo(*tessLevelsBuffer, 0ull, sizeof(TessLevels));
+
+       DescriptorSetUpdateBuilder()
+               .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
+               .update(vk, device);
+
+       // Color attachment
+
+       const tcu::IVec2                          renderSize                             = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
+       const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
+       const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const Image                                       colorAttachmentImage           (vk, device, allocator,
+                                                                                                                        makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
+                                                                                                                        MemoryRequirement::Any);
+
+       // Color output buffer: image will be copied here for verification.
+       //                      We use two buffers, one for each case.
+
+       const VkDeviceSize      colorBufferSizeBytes            = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
+       const Buffer            colorBuffer1                            (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
+       const Buffer            colorBuffer2                            (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
+       const Buffer* const colorBuffer[PIPELINE_CASES] = { &colorBuffer1, &colorBuffer2 };
+
+       // Pipeline
+
+       const Unique<VkImageView>               colorAttachmentView(makeImageView               (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
+       const Unique<VkRenderPass>              renderPass                 (makeRenderPass              (vk, device, colorFormat));
+       const Unique<VkFramebuffer>             framebuffer                (makeFramebuffer             (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
+       const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayout  (vk, device, *descriptorSetLayout));
+       const Unique<VkCommandPool>             cmdPool                    (makeCommandPool             (vk, device, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer                  (makeCommandBuffer   (vk, device, *cmdPool));
+
+       // Message explaining the test
+       {
+               tcu::TestLog& log = m_context.getTestContext().getLog();
+               log << tcu::TestLog::Message << m_params.message << tcu::TestLog::EndMessage;
+
+               if (m_params.useTessLevels)
+                       log << tcu::TestLog::Message << "Tessellation levels: " << getTessellationLevelsString(m_params.tessLevels, m_params.primitiveType) << tcu::TestLog::EndMessage;
+       }
+
+       for (int pipelineNdx = 0; pipelineNdx < PIPELINE_CASES; ++pipelineNdx)
+       {
+               const PipelineDescription& pipelineDescription = m_params.pipelineCases[pipelineNdx];
+               GraphicsPipelineBuilder    pipelineBuilder;
+
+               pipelineBuilder
+                       .setPrimitiveTopology             (getPrimitiveTopology(m_params.primitiveType))
+                       .setRenderSize                            (renderSize)
+                       .setBlend                                         (true)
+                       .setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
+                       .setPatchControlPoints            (m_params.inputPatchVertices)
+                       .setShader                                        (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                      m_context.getBinaryCollection().get("vert"), DE_NULL)
+                       .setShader                                        (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                            m_context.getBinaryCollection().get("frag"), DE_NULL);
+
+               if (pipelineDescription.useTessellation)
+                       pipelineBuilder
+                               .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,        m_context.getBinaryCollection().get("tesc"), DE_NULL)
+                               .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(pipelineDescription.tessEvalShaderName), DE_NULL);
+
+               if (pipelineDescription.useGeometry)
+                       pipelineBuilder
+                               .setShader                                (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                            m_context.getBinaryCollection().get(pipelineDescription.geomShaderName), DE_NULL);
+
+               const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
+
+               // Draw commands
+
+               beginCommandBuffer(vk, *cmdBuffer);
+
+               // Change color attachment image layout
+               {
+                       // State is slightly different on the first iteration.
+                       const VkImageLayout currentLayout = (pipelineNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+                       const VkAccessFlags srcFlags      = (pipelineNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
+
+                       const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
+                               srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                               currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                               *colorAttachmentImage, colorImageSubresourceRange);
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
+               }
+
+               // Begin render pass
+               {
+                       const VkRect2D renderArea = {
+                               makeOffset2D(0, 0),
+                               makeExtent2D(renderSize.x(), renderSize.y()),
+                       };
+                       const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+                       beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
+               }
+
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+               {
+                       const VkDeviceSize vertexBufferOffset = 0ull;
+                       vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
+               }
+
+               if (m_params.useTessLevels)
+                       vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
+
+               vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(m_params.vertices.size()), 1u, 0u, 0u);
+               endRenderPass(vk, *cmdBuffer);
+
+               // Copy render result to a host-visible buffer
+               {
+                       const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
+                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                               *colorAttachmentImage, colorImageSubresourceRange);
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
+               }
+               {
+                       const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 0), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
+                       vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer[pipelineNdx]->get(), 1u, &copyRegion);
+               }
+               {
+                       const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
+                               VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, colorBuffer[pipelineNdx]->get(), 0ull, colorBufferSizeBytes);
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
+                               0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
+               }
+
+               endCommandBuffer(vk, *cmdBuffer);
+               submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+       }
+
+       // Verify results
+
+       tcu::ConstPixelBufferAccess image0 = getPixelBufferAccess(vk, device, *colorBuffer[0], colorFormat, colorBufferSizeBytes, renderSize);
+       tcu::ConstPixelBufferAccess image1 = getPixelBufferAccess(vk, device, *colorBuffer[1], colorFormat, colorBufferSizeBytes, renderSize);
+
+       const tcu::UVec4 colorThreshold    (8, 8, 8, 255);
+       const tcu::IVec3 positionDeviation (1, 1, 0);           // 3x3 search kernel
+       const bool               ignoreOutOfBounds = true;
+
+       tcu::TestLog& log = m_context.getTestContext().getLog();
+       log << tcu::TestLog::Message
+               << "In image comparison:\n"
+               << "  Reference - " << m_params.pipelineCases[0].description << "\n"
+               << "  Result    - " << m_params.pipelineCases[1].description << "\n"
+               << tcu::TestLog::EndMessage;
+
+       const bool ok = tcu::intThresholdPositionDeviationCompare(
+               log, "ImageCompare", "Image comparison", image0, image1, colorThreshold, positionDeviation, ignoreOutOfBounds, tcu::COMPARE_LOG_RESULT);
+
+       return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed"));
+}
+
+TestInstance* IdentityGeometryShaderTestCase::createInstance (Context& context) const
+{
+       PassthroughTestInstance::Params params;
+
+       const float level                  = 14.0;
+       params.useTessLevels       = true;
+       params.tessLevels.inner[0] = level;
+       params.tessLevels.inner[1] = level;
+       params.tessLevels.outer[0] = level;
+       params.tessLevels.outer[1] = level;
+       params.tessLevels.outer[2] = level;
+       params.tessLevels.outer[3] = level;
+
+       params.primitiveType       = m_primitiveType;
+       params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
+
+       params.vertices.push_back(tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ));
+       params.vertices.push_back(tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ));
+       params.vertices.push_back(tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ));
+       params.vertices.push_back(tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ));
+
+       params.pipelineCases[0].useTessellation         = true;
+       params.pipelineCases[0].useGeometry                     = true;
+       params.pipelineCases[0].tessEvalShaderName      = "tese_to_geom";
+       params.pipelineCases[0].geomShaderName          = "geom";
+       params.pipelineCases[0].description                     = "passthrough geometry shader";
+
+       params.pipelineCases[1].useTessellation         = true;
+       params.pipelineCases[1].useGeometry                     = false;
+       params.pipelineCases[1].tessEvalShaderName      = "tese_to_frag";
+       params.pipelineCases[1].geomShaderName          = "geom";
+       params.pipelineCases[1].description                     = "no geometry shader in the pipeline";
+
+       params.message = "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
+                                        "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
+                                        "Using additive blending to detect overlap.\n";
+
+       return new PassthroughTestInstance(context, params);
+};
+
+TestInstance* IdentityTessellationShaderTestCase::createInstance (Context& context) const
+{
+       PassthroughTestInstance::Params params;
+
+       params.useTessLevels       = false;
+       params.primitiveType       = m_primitiveType;
+       params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
+
+       params.vertices.push_back(        tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f ));
+       params.vertices.push_back(        tcu::Vec4(  0.0f, -0.5f, 0.0f, 1.0f ));
+       if (params.inputPatchVertices == 3)
+               params.vertices.push_back(tcu::Vec4(  0.4f,  0.4f, 0.0f, 1.0f ));
+
+       params.pipelineCases[0].useTessellation         = true;
+       params.pipelineCases[0].useGeometry                     = true;
+       params.pipelineCases[0].tessEvalShaderName      = "tese";
+       params.pipelineCases[0].geomShaderName          = "geom_from_tese";
+       params.pipelineCases[0].description                     = "passthrough tessellation shaders";
+
+       params.pipelineCases[1].useTessellation         = false;
+       params.pipelineCases[1].useGeometry                     = true;
+       params.pipelineCases[1].tessEvalShaderName      = "tese";
+       params.pipelineCases[1].geomShaderName          = "geom_from_vert";
+       params.pipelineCases[1].description                     = "no tessellation shaders in the pipeline";
+
+       params.message = "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
+                                        "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
+                                        "Using additive blending to detect overlap.\n";
+
+       return new PassthroughTestInstance(context, params);
+};
+
+inline TestCase* makeIdentityGeometryShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
+{
+       return new IdentityGeometryShaderTestCase(
+               testCtx,
+               "tessellate_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_passthrough_geometry_no_change",
+               "Passthrough geometry shader has no effect",
+               primitiveType);
+}
+
+inline TestCase* makeIdentityTessellationShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
+{
+       return new IdentityTessellationShaderTestCase(
+               testCtx,
+               "passthrough_tessellation_geometry_shade_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_no_change",
+               "Passthrough tessellation shader has no effect",
+               primitiveType);
+}
+
+} // anonymous
+
+
+//! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.passthrough.*
+tcu::TestCaseGroup* createGeometryPassthroughTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "passthrough", "Render various types with either passthrough geometry or tessellation shader"));
+
+       // Passthrough geometry shader
+       group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
+       group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_QUADS));
+       group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
+
+       // Passthrough tessellation shader
+       group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
+       group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
+
+       return group.release();
+}
+
+} // tessellation
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.hpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPassthroughTests.hpp
new file mode 100644 (file)
index 0000000..71e0416
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _VKTTESSELLATIONGEOMETRYPASSTHROUGHTESTS_HPP
+#define _VKTTESSELLATIONGEOMETRYPASSTHROUGHTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tessellation Geometry Interaction - Passthrough
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace tessellation
+{
+
+tcu::TestCaseGroup* createGeometryPassthroughTests (tcu::TestContext& testCtx);
+
+} // tessellation
+} // vkt
+
+#endif // _VKTTESSELLATIONGEOMETRYPASSTHROUGHTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.cpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.cpp
new file mode 100644 (file)
index 0000000..c055391
--- /dev/null
@@ -0,0 +1,516 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+* \brief Tessellation Geometry Interaction - Point Size
+*//*--------------------------------------------------------------------*/
+
+#include "vktTessellationGeometryPassthroughTests.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vktTessellationUtil.hpp"
+
+#include "tcuTestLog.hpp"
+
+#include "vkDefs.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkImageUtil.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include <string>
+#include <vector>
+
+namespace vkt
+{
+namespace tessellation
+{
+
+using namespace vk;
+
+namespace
+{
+
+enum Constants
+{
+       RENDER_SIZE = 32,
+};
+
+enum FlagBits
+{
+       FLAG_VERTEX_SET                                         = 1u << 0,              // !< set gl_PointSize in vertex shader
+       FLAG_TESSELLATION_CONTROL_SET           = 1u << 1,              // !< set gl_PointSize in tessellation evaluation shader
+       FLAG_TESSELLATION_EVALUATION_SET        = 1u << 2,              // !< set gl_PointSize in tessellation control shader
+       FLAG_TESSELLATION_ADD                           = 1u << 3,              // !< read and add to gl_PointSize in tessellation shader pair
+       FLAG_TESSELLATION_DONT_SET                      = 1u << 4,              // !< don't set gl_PointSize in tessellation shader
+       FLAG_GEOMETRY_SET                                       = 1u << 5,              // !< set gl_PointSize in geometry shader
+       FLAG_GEOMETRY_ADD                                       = 1u << 6,              // !< read and add to gl_PointSize in geometry shader
+       FLAG_GEOMETRY_DONT_SET                          = 1u << 7,              // !< don't set gl_PointSize in geometry shader
+};
+typedef deUint32 Flags;
+
+void checkPointSizeRequirements (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const int maxPointSize)
+{
+       const VkPhysicalDeviceProperties properties = getPhysicalDeviceProperties(vki, physDevice);
+       if (maxPointSize > static_cast<int>(properties.limits.pointSizeRange[1]))
+               throw tcu::NotSupportedError("Test requires point size " + de::toString(maxPointSize));
+       // Point size granularity must be 1.0 at most, so no need to check it for this test.
+}
+
+int getExpectedPointSize (const Flags flags)
+{
+       int addition = 0;
+
+       // geometry
+       if (flags & FLAG_GEOMETRY_DONT_SET)
+               return 1;
+       else if (flags & FLAG_GEOMETRY_SET)
+               return 6;
+       else if (flags & FLAG_GEOMETRY_ADD)
+               addition += 2;
+
+       // tessellation
+       if (flags & FLAG_TESSELLATION_EVALUATION_SET)
+               return 4 + addition;
+       else if (flags & FLAG_TESSELLATION_ADD)
+               addition += 2;
+       else if (flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_DONT_SET))
+       {
+               DE_ASSERT((flags & FLAG_GEOMETRY_ADD) == 0); // reading pointSize undefined
+               return 1;
+       }
+
+       // vertex
+       if (flags & FLAG_VERTEX_SET)
+               return 2 + addition;
+
+       // undefined
+       DE_ASSERT(false);
+       return -1;
+}
+
+inline bool isTessellationStage (const Flags flags)
+{
+       return (flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET)) != 0;
+}
+
+inline bool isGeometryStage (const Flags flags)
+{
+       return (flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET)) != 0;
+}
+
+bool verifyImage (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image, const int expectedSize)
+{
+       log << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
+
+       bool                    resultAreaFound = false;
+       tcu::IVec4              resultArea;
+       const tcu::Vec4 black(0.0, 0.0, 0.0, 1.0);
+
+       // Find rasterization output area
+
+       for (int y = 0; y < image.getHeight(); ++y)
+       for (int x = 0; x < image.getWidth();  ++x)
+               if (image.getPixel(x, y) != black)
+               {
+                       if (!resultAreaFound)
+                       {
+                               // first fragment
+                               resultArea = tcu::IVec4(x, y, x + 1, y + 1);
+                               resultAreaFound = true;
+                       }
+                       else
+                       {
+                               // union area
+                               resultArea.x() = de::min(resultArea.x(), x);
+                               resultArea.y() = de::min(resultArea.y(), y);
+                               resultArea.z() = de::max(resultArea.z(), x+1);
+                               resultArea.w() = de::max(resultArea.w(), y+1);
+                       }
+               }
+
+       if (!resultAreaFound)
+       {
+               log << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
+               return false;
+       }
+
+       const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
+
+       if (pointSize.x() != pointSize.y())
+       {
+               log << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
+               return false;
+       }
+
+       if (pointSize.x() != expectedSize)
+       {
+               log << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
+               return false;
+       }
+
+       return true;
+}
+
+void initPrograms (vk::SourceCollections& programCollection, const Flags flags)
+{
+       // Vertex shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n";
+
+               if (flags & FLAG_VERTEX_SET)
+                       src << "    gl_PointSize = 2.0;\n";
+
+               src << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "layout(location = 0) out mediump vec4 fragColor;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    fragColor = vec4(1.0);\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+
+       if (isTessellationStage(flags))
+       {
+               // Tessellation control shader
+               {
+                       std::ostringstream src;
+                       src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                               << "#extension GL_EXT_tessellation_shader : require\n"
+                               << ((flags & FLAG_TESSELLATION_DONT_SET) ? "" : "#extension GL_EXT_tessellation_point_size : require\n")
+                               << "layout(vertices = 1) out;\n"
+                               << "\n"
+                               << "void main (void)\n"
+                               << "{\n"
+                               << "    gl_TessLevelOuter[0] = 3.0;\n"
+                               << "    gl_TessLevelOuter[1] = 3.0;\n"
+                               << "    gl_TessLevelOuter[2] = 3.0;\n"
+                               << "    gl_TessLevelInner[0] = 3.0;\n"
+                               << "\n"
+                               << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
+
+                       if (flags & FLAG_TESSELLATION_ADD)
+                               src << "    // pass as is to eval\n"
+                                       << "    gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
+                       else if (flags & FLAG_TESSELLATION_CONTROL_SET)
+                               src << "    // thrown away\n"
+                                       << "    gl_out[gl_InvocationID].gl_PointSize = 4.0;\n";
+
+                       src << "}\n";
+
+                       programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
+               }
+
+               // Tessellation evaluation shader
+               {
+                       std::ostringstream src;
+                       src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                               << "#extension GL_EXT_tessellation_shader : require\n"
+                               << (flags & FLAG_TESSELLATION_DONT_SET ? "" : "#extension GL_EXT_tessellation_point_size : require\n")
+                               << "layout(triangles, point_mode) in;\n"
+                               << "\n"
+                               << "void main (void)\n"
+                               << "{\n"
+                               << "    // hide all but one vertex\n"
+                               << "    if (gl_TessCoord.x < 0.99)\n"
+                               << "        gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
+                               << "    else\n"
+                               << "        gl_Position = gl_in[0].gl_Position;\n";
+
+                       if (flags & FLAG_TESSELLATION_ADD)
+                               src << "\n"
+                                       << "    // add to point size\n"
+                                       << "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
+                       else if (flags & FLAG_TESSELLATION_EVALUATION_SET)
+                               src << "\n"
+                                       << "    // set point size\n"
+                                       << "    gl_PointSize = 4.0;\n";
+
+                       src << "}\n";
+
+                       programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
+               }
+       }
+
+       if (isGeometryStage(flags))
+       {
+               // Geometry shader
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
+                       << "#extension GL_EXT_geometry_shader : require\n"
+                       << (flags & FLAG_GEOMETRY_DONT_SET ? "" : "#extension GL_EXT_geometry_point_size : require\n")
+                       << "layout(points) in;\n"
+                       << "layout(points, max_vertices = 1) out;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n";
+
+               if (flags & FLAG_GEOMETRY_SET)
+                       src << "    gl_Position  = gl_in[0].gl_Position;\n"
+                               << "    gl_PointSize = 6.0;\n";
+               else if (flags & FLAG_GEOMETRY_ADD)
+                       src << "    gl_Position  = gl_in[0].gl_Position;\n"
+                               << "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
+               else if (flags & FLAG_GEOMETRY_DONT_SET)
+                       src << "    gl_Position = gl_in[0].gl_Position;\n";
+
+               src << "\n"
+                       << "    EmitVertex();\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
+       }
+}
+
+tcu::TestStatus test (Context& context, const Flags flags)
+{
+       const int expectedPointSize = getExpectedPointSize(flags);
+       {
+               const InstanceInterface& vki        = context.getInstanceInterface();
+               const VkPhysicalDevice   physDevice = context.getPhysicalDevice();
+
+               requireFeatures           (vki, physDevice, FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
+               checkPointSizeRequirements(vki, physDevice, expectedPointSize);
+       }
+       {
+               tcu::TestLog& log = context.getTestContext().getLog();
+
+               if (flags & FLAG_VERTEX_SET)
+                       log << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_TESSELLATION_CONTROL_SET)
+                       log << tcu::TestLog::Message << "Setting point size in tessellation control shader to 4.0. (And ignoring it in evaluation)." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_TESSELLATION_EVALUATION_SET)
+                       log << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_TESSELLATION_ADD)
+                       log << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_TESSELLATION_DONT_SET)
+                       log << tcu::TestLog::Message << "Not setting point size in tessellation evaluation shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_GEOMETRY_SET)
+                       log << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_GEOMETRY_ADD)
+                       log << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
+               if (flags & FLAG_GEOMETRY_DONT_SET)
+                       log << tcu::TestLog::Message << "Not setting point size in geometry shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
+       }
+
+       const DeviceInterface&  vk                                      = context.getDeviceInterface();
+       const VkDevice                  device                          = context.getDevice();
+       const VkQueue                   queue                           = context.getUniversalQueue();
+       const deUint32                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+       Allocator&                              allocator                       = context.getDefaultAllocator();
+
+       // Color attachment
+
+       const tcu::IVec2                          renderSize                             = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
+       const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
+       const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const Image                                       colorAttachmentImage           (vk, device, allocator,
+                                                                                                                        makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
+                                                                                                                        MemoryRequirement::Any);
+
+       // Color output buffer
+
+       const VkDeviceSize      colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
+       const Buffer            colorBuffer          (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
+
+       // Pipeline
+
+       const Unique<VkImageView>               colorAttachmentView(makeImageView                                               (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
+       const Unique<VkRenderPass>              renderPass                 (makeRenderPass                                              (vk, device, colorFormat));
+       const Unique<VkFramebuffer>             framebuffer                (makeFramebuffer                                             (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
+       const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayoutWithoutDescriptors(vk, device));
+       const Unique<VkCommandPool>             cmdPool                    (makeCommandPool                                             (vk, device, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer                  (makeCommandBuffer                                   (vk, device, *cmdPool));
+
+       GraphicsPipelineBuilder                 pipelineBuilder;
+
+       pipelineBuilder
+               .setPrimitiveTopology             (VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
+               .setRenderSize                            (renderSize)
+               .setPatchControlPoints            (1)
+               .setShader                                        (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                      context.getBinaryCollection().get("vert"), DE_NULL)
+               .setShader                                        (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                            context.getBinaryCollection().get("frag"), DE_NULL);
+
+       if (isTessellationStage(flags))
+               pipelineBuilder
+                       .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,        context.getBinaryCollection().get("tesc"), DE_NULL)
+                       .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL);
+
+       if (isGeometryStage(flags))
+               pipelineBuilder
+                       .setShader                                (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                            context.getBinaryCollection().get("geom"), DE_NULL);
+
+       const Unique<VkPipeline> pipeline(pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
+
+       // Draw commands
+
+       beginCommandBuffer(vk, *cmdBuffer);
+
+       {
+               const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
+                       (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                       *colorAttachmentImage, colorImageSubresourceRange);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
+                       0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
+       }
+
+       // Begin render pass
+       {
+               const VkRect2D renderArea = {
+                       makeOffset2D(0, 0),
+                       makeExtent2D(renderSize.x(), renderSize.y()),
+               };
+               const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+               beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
+       }
+
+       vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+
+       vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
+       endRenderPass(vk, *cmdBuffer);
+
+       // Copy render result to a host-visible buffer
+       {
+               const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                       *colorAttachmentImage, colorImageSubresourceRange);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
+                       0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
+       }
+       {
+               const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 0), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
+               vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
+       }
+       {
+               const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
+                       VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
+                       0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
+       }
+
+       endCommandBuffer(vk, *cmdBuffer);
+       submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+
+       // Verify results
+       {
+               const Allocation& alloc = colorBuffer.getAllocation();
+               invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
+               tcu::ConstPixelBufferAccess image(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
+
+               tcu::TestLog& log = context.getTestContext().getLog();
+               log << tcu::LogImage("color0", "", image);
+
+               if (verifyImage(log, image, expectedPointSize))
+                       return tcu::TestStatus::pass("OK");
+               else
+                       return tcu::TestStatus::fail("Didn't render expected point");
+       }
+}
+
+std::string getTestCaseName (const Flags flags)
+{
+       std::ostringstream buf;
+
+       // join per-bit descriptions into a single string with '_' separator
+       if (flags & FLAG_VERTEX_SET)                                    buf                                                                                                                                             << "vertex_set";
+       if (flags & FLAG_TESSELLATION_CONTROL_SET)              buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))             ? ("_") : ("")) << "control_set";
+       if (flags & FLAG_TESSELLATION_EVALUATION_SET)   buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))  ? ("_") : ("")) << "evaluation_set";
+       if (flags & FLAG_TESSELLATION_ADD)                              buf << ((flags & (FLAG_TESSELLATION_ADD-1))                             ? ("_") : ("")) << "control_pass_eval_add";
+       if (flags & FLAG_TESSELLATION_DONT_SET)                 buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))                ? ("_") : ("")) << "eval_default";
+       if (flags & FLAG_GEOMETRY_SET)                                  buf << ((flags & (FLAG_GEOMETRY_SET-1))                                 ? ("_") : ("")) << "geometry_set";
+       if (flags & FLAG_GEOMETRY_ADD)                                  buf << ((flags & (FLAG_GEOMETRY_ADD-1))                                 ? ("_") : ("")) << "geometry_add";
+       if (flags & FLAG_GEOMETRY_DONT_SET)                             buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))                    ? ("_") : ("")) << "geometry_default";
+
+       return buf.str();
+}
+
+std::string getTestCaseDescription (const Flags flags)
+{
+       std::ostringstream buf;
+
+       // join per-bit descriptions into a single string with ", " separator
+       if (flags & FLAG_VERTEX_SET)                                    buf                                                                                                                                                     << "set point size in vertex shader";
+       if (flags & FLAG_TESSELLATION_CONTROL_SET)              buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))             ? (", ") : (""))        << "set point size in tessellation control shader";
+       if (flags & FLAG_TESSELLATION_EVALUATION_SET)   buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))  ? (", ") : (""))        << "set point size in tessellation evaluation shader";
+       if (flags & FLAG_TESSELLATION_ADD)                              buf << ((flags & (FLAG_TESSELLATION_ADD-1))                             ? (", ") : (""))        << "add to point size in tessellation shader";
+       if (flags & FLAG_TESSELLATION_DONT_SET)                 buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))                ? (", ") : (""))        << "don't set point size in tessellation evaluation shader";
+       if (flags & FLAG_GEOMETRY_SET)                                  buf << ((flags & (FLAG_GEOMETRY_SET-1))                                 ? (", ") : (""))        << "set point size in geometry shader";
+       if (flags & FLAG_GEOMETRY_ADD)                                  buf << ((flags & (FLAG_GEOMETRY_ADD-1))                                 ? (", ") : (""))        << "add to point size in geometry shader";
+       if (flags & FLAG_GEOMETRY_DONT_SET)                             buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))                    ? (", ") : (""))        << "don't set point size in geometry shader";
+
+       return buf.str();
+}
+
+} // anonymous
+
+//! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.point_size.*
+tcu::TestCaseGroup* createGeometryPointSizeTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "point_size", "Test point size"));
+
+       static const Flags caseFlags[] =
+       {
+               FLAG_VERTEX_SET,
+                                                       FLAG_TESSELLATION_EVALUATION_SET,
+                                                                                                                                       FLAG_GEOMETRY_SET,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_CONTROL_SET,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_EVALUATION_SET,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_DONT_SET,
+               FLAG_VERTEX_SET |                                                                                       FLAG_GEOMETRY_SET,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_EVALUATION_SET        |       FLAG_GEOMETRY_SET,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_ADD                           |       FLAG_GEOMETRY_ADD,
+               FLAG_VERTEX_SET |       FLAG_TESSELLATION_EVALUATION_SET        |       FLAG_GEOMETRY_DONT_SET,
+       };
+
+       for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
+       {
+               const std::string name = getTestCaseName       (caseFlags[ndx]);
+               const std::string desc = getTestCaseDescription(caseFlags[ndx]);
+
+               addFunctionCaseWithPrograms(group.get(), name, desc, initPrograms, test, caseFlags[ndx]);
+       }
+
+       return group.release();
+}
+
+} // tessellation
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.hpp b/external/vulkancts/modules/vulkan/tessellation/vktTessellationGeometryPointSizeTests.hpp
new file mode 100644 (file)
index 0000000..c76c721
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _VKTTESSELLATIONGEOMETRYPOINTSIZETESTS_HPP
+#define _VKTTESSELLATIONGEOMETRYPOINTSIZETESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tessellation Geometry Interaction - Point Size
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace tessellation
+{
+
+tcu::TestCaseGroup* createGeometryPointSizeTests (tcu::TestContext& testCtx);
+
+} // tessellation
+} // vkt
+
+#endif // _VKTTESSELLATIONGEOMETRYPOINTSIZETESTS_HPP
index c71f468..c062d5f 100644 (file)
 #include "vktTessellationPrimitiveDiscardTests.hpp"
 #include "vktTessellationInvarianceTests.hpp"
 #include "vktTessellationUserDefinedIO.hpp"
+#include "vktTessellationGeometryPassthroughTests.hpp"
+#include "vktTessellationGeometryPointSizeTests.hpp"
+#include "vktTessellationGeometryGridRenderTests.hpp"
+
+#include "deUniquePtr.hpp"
 
 namespace vkt
 {
@@ -42,20 +47,33 @@ namespace tessellation
 namespace
 {
 
+tcu::TestCaseGroup* createGeometryInteractionTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "geometry_interaction", "Tessellation and geometry shader interaction tests"));
+
+       group->addChild(createGeometryPassthroughTests          (testCtx));
+       group->addChild(createGeometryGridRenderLimitsTests     (testCtx));
+       group->addChild(createGeometryGridRenderScatterTests(testCtx));
+       group->addChild(createGeometryPointSizeTests            (testCtx));
+
+       return group.release();
+}
+
 void createChildren (tcu::TestCaseGroup* tessellationTests)
 {
        tcu::TestContext& testCtx = tessellationTests->getTestContext();
 
-       tessellationTests->addChild(createLimitsTests                   (testCtx));
-       tessellationTests->addChild(createCoordinatesTests              (testCtx));
-       tessellationTests->addChild(createWindingTests                  (testCtx));
-       tessellationTests->addChild(createShaderInputOutputTests(testCtx));
-       tessellationTests->addChild(createMiscDrawTests                 (testCtx));
-       tessellationTests->addChild(createCommonEdgeTests               (testCtx));
-       tessellationTests->addChild(createFractionalSpacingTests(testCtx));
-       tessellationTests->addChild(createPrimitiveDiscardTests (testCtx));
-       tessellationTests->addChild(createInvarianceTests               (testCtx));
-       tessellationTests->addChild(createUserDefinedIOTests    (testCtx));
+       tessellationTests->addChild(createLimitsTests                           (testCtx));
+       tessellationTests->addChild(createCoordinatesTests                      (testCtx));
+       tessellationTests->addChild(createWindingTests                          (testCtx));
+       tessellationTests->addChild(createShaderInputOutputTests        (testCtx));
+       tessellationTests->addChild(createMiscDrawTests                         (testCtx));
+       tessellationTests->addChild(createCommonEdgeTests                       (testCtx));
+       tessellationTests->addChild(createFractionalSpacingTests        (testCtx));
+       tessellationTests->addChild(createPrimitiveDiscardTests         (testCtx));
+       tessellationTests->addChild(createInvarianceTests                       (testCtx));
+       tessellationTests->addChild(createUserDefinedIOTests            (testCtx));
+       tessellationTests->addChild(createGeometryInteractionTests      (testCtx));
 }
 
 } // anonymous
index f12740d..dc42d2c 100644 (file)
@@ -82848,3 +82848,24 @@ dEQP-VK.tessellation.invariance.one_minus_tess_coord_component.isolines_fraction
 dEQP-VK.tessellation.invariance.one_minus_tess_coord_component.isolines_fractional_even_spacing_ccw_point_mode
 dEQP-VK.tessellation.invariance.one_minus_tess_coord_component.isolines_fractional_even_spacing_cw
 dEQP-VK.tessellation.invariance.one_minus_tess_coord_component.isolines_fractional_even_spacing_cw_point_mode
+dEQP-VK.tessellation.geometry_interaction.passthrough.tessellate_triangles_passthrough_geometry_no_change
+dEQP-VK.tessellation.geometry_interaction.passthrough.tessellate_quads_passthrough_geometry_no_change
+dEQP-VK.tessellation.geometry_interaction.passthrough.tessellate_isolines_passthrough_geometry_no_change
+dEQP-VK.tessellation.geometry_interaction.passthrough.passthrough_tessellation_geometry_shade_triangles_no_change
+dEQP-VK.tessellation.geometry_interaction.passthrough.passthrough_tessellation_geometry_shade_isolines_no_change
+dEQP-VK.tessellation.geometry_interaction.limits.output_required_max_tessellation
+dEQP-VK.tessellation.geometry_interaction.limits.output_required_max_geometry
+dEQP-VK.tessellation.geometry_interaction.limits.output_required_max_invocations
+dEQP-VK.tessellation.geometry_interaction.scatter.geometry_scatter_instances
+dEQP-VK.tessellation.geometry_interaction.scatter.geometry_scatter_primitives
+dEQP-VK.tessellation.geometry_interaction.scatter.geometry_scatter_layers
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set
+dEQP-VK.tessellation.geometry_interaction.point_size.evaluation_set
+dEQP-VK.tessellation.geometry_interaction.point_size.geometry_set
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_control_set
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_evaluation_set
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_eval_default
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_geometry_set
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_evaluation_set_geometry_set
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_control_pass_eval_add_geometry_add
+dEQP-VK.tessellation.geometry_interaction.point_size.vertex_set_evaluation_set_geometry_default