1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Input Geometry Shader Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktGeometryInputGeometryShaderTests.hpp"
26 #include "vktGeometryBasicClass.hpp"
27 #include "vktGeometryTestsUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vktTestCase.hpp"
31 #include "vktTestCaseUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkBuilderUtil.hpp"
36 
37 #include "vkRefUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkMemUtil.hpp"
40 
41 #include <string>
42 
43 using namespace vk;
44 
45 namespace vkt
46 {
47 namespace geometry
48 {
49 namespace
50 {
51 using de::MovePtr;
52 using std::string;
53 using std::vector;
54 using tcu::TestCaseGroup;
55 using tcu::TestContext;
56 using tcu::TestStatus;
57 using tcu::Vec4;
58 
59 class GeometryInputTestInstance : public GeometryExpanderRenderTestInstance
60 {
61 public:
62     GeometryInputTestInstance(Context &context, const VkPrimitiveTopology primitiveType, const char *name);
63 
64     GeometryInputTestInstance(Context &context, const VkPrimitiveTopology primitiveType, const char *name,
65                               const int numDrawVertices);
66 
67     void genVertexAttribData(void);
68 };
69 
GeometryInputTestInstance(Context & context,const VkPrimitiveTopology primitiveType,const char * name)70 GeometryInputTestInstance::GeometryInputTestInstance(Context &context, const VkPrimitiveTopology primitiveType,
71                                                      const char *name)
72     : GeometryExpanderRenderTestInstance(context, primitiveType, name)
73 {
74     genVertexAttribData();
75 }
76 
GeometryInputTestInstance(Context & context,const VkPrimitiveTopology primitiveType,const char * name,const int numDrawVertices)77 GeometryInputTestInstance::GeometryInputTestInstance(Context &context, const VkPrimitiveTopology primitiveType,
78                                                      const char *name, const int numDrawVertices)
79     : GeometryExpanderRenderTestInstance(context, primitiveType, name)
80 {
81     genVertexAttribData();
82     m_numDrawVertices = numDrawVertices;
83 }
84 
genVertexAttribData(void)85 void GeometryInputTestInstance::genVertexAttribData(void)
86 {
87     // Create 1 X 2 grid in triangle strip adjacent - order
88     const float scale = 0.3f;
89     const Vec4 offset(-0.5f, -0.2f, 0.0f, 1.0f);
90     m_numDrawVertices = 12;
91 
92     m_vertexPosData.resize(m_numDrawVertices);
93     m_vertexPosData[0]  = Vec4(0, 0, 0.0f, 0.0f) * scale + offset;
94     m_vertexPosData[1]  = Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
95     m_vertexPosData[2]  = Vec4(0, -1, 0.0f, 0.0f) * scale + offset;
96     m_vertexPosData[3]  = Vec4(1, 1, 0.0f, 0.0f) * scale + offset;
97     m_vertexPosData[4]  = Vec4(1, 0, 0.0f, 0.0f) * scale + offset;
98     m_vertexPosData[5]  = Vec4(0, -2, 0.0f, 0.0f) * scale + offset;
99     m_vertexPosData[6]  = Vec4(1, -1, 0.0f, 0.0f) * scale + offset;
100     m_vertexPosData[7]  = Vec4(2, 1, 0.0f, 0.0f) * scale + offset;
101     m_vertexPosData[8]  = Vec4(2, 0, 0.0f, 0.0f) * scale + offset;
102     m_vertexPosData[9]  = Vec4(1, -2, 0.0f, 0.0f) * scale + offset;
103     m_vertexPosData[10] = Vec4(2, -1, 0.0f, 0.0f) * scale + offset;
104     m_vertexPosData[11] = Vec4(3, 0, 0.0f, 0.0f) * scale + offset;
105 
106     // Red and white
107     m_vertexAttrData.resize(m_numDrawVertices);
108     for (int i = 0; i < m_numDrawVertices; ++i)
109         m_vertexAttrData[i] = (i % 2 == 0) ? Vec4(1, 1, 1, 1) : Vec4(1, 0, 0, 1);
110 }
111 
112 class GeometryExpanderRenderTest : public TestCase
113 {
114 public:
115     GeometryExpanderRenderTest(TestContext &testCtx, const PrimitiveTestSpec &inputPrimitives);
116 
117     void initPrograms(SourceCollections &sourceCollections) const;
118     virtual TestInstance *createInstance(Context &context) const;
119     virtual void checkSupport(Context &context) const;
120 
121 protected:
122     string shaderGeometry(bool pointSize) const;
123     const VkPrimitiveTopology m_primitiveType;
124     const VkPrimitiveTopology m_outputType;
125 };
126 
GeometryExpanderRenderTest(TestContext & testCtx,const PrimitiveTestSpec & inputPrimitives)127 GeometryExpanderRenderTest::GeometryExpanderRenderTest(TestContext &testCtx, const PrimitiveTestSpec &inputPrimitives)
128     : TestCase(testCtx, inputPrimitives.name)
129     , m_primitiveType(inputPrimitives.primitiveType)
130     , m_outputType(inputPrimitives.outputType)
131 {
132 }
133 
checkSupport(Context & context) const134 void GeometryExpanderRenderTest::checkSupport(Context &context) const
135 {
136     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
137 
138 #ifndef CTS_USES_VULKANSC
139     if (m_primitiveType == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
140         context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
141         !context.getPortabilitySubsetFeatures().triangleFans)
142     {
143         TCU_THROW(NotSupportedError,
144                   "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
145     }
146 #endif // CTS_USES_VULKANSC
147 }
148 
initPrograms(SourceCollections & sourceCollections) const149 void GeometryExpanderRenderTest::initPrograms(SourceCollections &sourceCollections) const
150 {
151     {
152         std::ostringstream src;
153         src << "#version 310 es\n"
154             << "layout(location = 0) in highp vec4 a_position;\n"
155             << "layout(location = 1) in highp vec4 a_color;\n"
156             << "layout(location = 0) out highp vec4 v_geom_FragColor;\n"
157             << "void main (void)\n"
158             << "{\n"
159             << "    gl_Position = a_position;\n"
160             << "    v_geom_FragColor = a_color;\n"
161             << "}\n";
162         sourceCollections.glslSources.add("vertex") << glu::VertexSource(src.str());
163     }
164 
165     {
166         sourceCollections.glslSources.add("geometry") << glu::GeometrySource(shaderGeometry(false));
167         if (m_outputType == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
168             sourceCollections.glslSources.add("geometry_pointsize") << glu::GeometrySource(shaderGeometry(true));
169     }
170 
171     {
172         std::ostringstream src;
173         src << "#version 310 es\n"
174             << "layout(location = 0) out highp vec4 fragColor;\n"
175             << "layout(location = 0) in highp vec4 v_frag_FragColor;\n"
176             << "void main (void)\n"
177             << "{\n"
178             << "    fragColor = v_frag_FragColor;\n"
179             << "}\n";
180         sourceCollections.glslSources.add("fragment") << glu::FragmentSource(src.str());
181     }
182 }
183 
createInstance(Context & context) const184 TestInstance *GeometryExpanderRenderTest::createInstance(Context &context) const
185 {
186     return new GeometryInputTestInstance(context, m_primitiveType, getName());
187 }
188 
shaderGeometry(bool pointSize) const189 string GeometryExpanderRenderTest::shaderGeometry(bool pointSize) const
190 {
191     std::ostringstream src;
192     src << "#version 310 es\n"
193         << "#extension GL_EXT_geometry_shader : require\n";
194     if (pointSize)
195         src << "#extension GL_EXT_geometry_point_size : require\n";
196     src << "layout(" << inputTypeToGLString(m_primitiveType) << ") in;\n"
197         << "layout(" << outputTypeToGLString(m_outputType) << ", max_vertices = " << calcOutputVertices(m_primitiveType)
198         << ") out;\n"
199         << "layout(location = 0) in highp vec4 v_geom_FragColor[];\n"
200         << "layout(location = 0) out highp vec4 v_frag_FragColor;\n"
201         << "\n"
202         << "void main (void)\n"
203         << "{\n"
204         << "    const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
205         << "    const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
206         << "    const highp vec4 offset2 = vec4(-0.01,  0.08, 0.0, 0.0);\n"
207         << "    highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
208         << "\n"
209         << "    for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
210         << "    {\n";
211     if (pointSize)
212         src << "        gl_PointSize = 1.0;\n";
213     src << "        gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
214         << "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
215         << "        EmitVertex();\n"
216         << "\n";
217     if (pointSize)
218         src << "        gl_PointSize = 1.0;\n";
219     src << "        gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
220         << "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
221         << "        EmitVertex();\n"
222         << "\n";
223     if (pointSize)
224         src << "        gl_PointSize = 1.0;\n";
225     src << "        gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
226         << "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
227         << "        EmitVertex();\n"
228         << "        EndPrimitive();\n"
229         << "    }\n"
230         << "}\n";
231     return src.str();
232 }
233 
234 class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
235 {
236 public:
237     TriangleStripAdjacencyVertexCountTest(TestContext &testCtx, const PrimitiveTestSpec &inputPrimitives,
238                                           const int numInputVertices);
239     virtual TestInstance *createInstance(Context &context) const;
240 
241 private:
242     const int m_numInputVertices;
243 };
244 
TriangleStripAdjacencyVertexCountTest(TestContext & testCtx,const PrimitiveTestSpec & inputPrimitives,const int numInputVertices)245 TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest(TestContext &testCtx,
246                                                                              const PrimitiveTestSpec &inputPrimitives,
247                                                                              const int numInputVertices)
248     : GeometryExpanderRenderTest(testCtx, inputPrimitives)
249     , m_numInputVertices(numInputVertices)
250 {
251 }
252 
createInstance(Context & context) const253 TestInstance *TriangleStripAdjacencyVertexCountTest::createInstance(Context &context) const
254 {
255     return new GeometryInputTestInstance(context, m_primitiveType, getName(), m_numInputVertices);
256 }
257 
258 } // namespace
259 
createInputGeometryShaderTests(TestContext & testCtx)260 TestCaseGroup *createInputGeometryShaderTests(TestContext &testCtx)
261 {
262     MovePtr<TestCaseGroup> inputPrimitiveGroup(new TestCaseGroup(testCtx, "input"));
263     MovePtr<TestCaseGroup> basicPrimitiveGroup(new TestCaseGroup(testCtx, "basic_primitive"));
264     MovePtr<TestCaseGroup> triStripAdjacencyGroup(new TestCaseGroup(testCtx, "triangle_strip_adjacency"));
265     MovePtr<TestCaseGroup> conversionPrimitiveGroup(new TestCaseGroup(testCtx, "conversion"));
266 
267     const PrimitiveTestSpec inputPrimitives[] = {
268         {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST},
269         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
270         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
271         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
272         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
273         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
274         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, "lines_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
275         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, "line_strip_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
276         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, "triangles_adjacency",
277          VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}};
278 
279     // more basic types
280     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
281         basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, inputPrimitives[ndx]));
282 
283     // triangle strip adjacency with different vertex counts
284     for (int vertexCount = 0; vertexCount <= 12; ++vertexCount)
285     {
286         const string name                  = "vertex_count_" + de::toString(vertexCount);
287         const PrimitiveTestSpec primitives = {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, name.c_str(),
288                                               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP};
289 
290         triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(testCtx, primitives, vertexCount));
291     }
292 
293     // different type conversions
294     {
295         static const PrimitiveTestSpec conversionPrimitives[] = {
296             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST},
297             {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST},
298             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
299             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
300             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
301             {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}};
302 
303         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
304             conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, conversionPrimitives[ndx]));
305     }
306 
307     inputPrimitiveGroup->addChild(basicPrimitiveGroup.release());
308     inputPrimitiveGroup->addChild(triStripAdjacencyGroup.release());
309     inputPrimitiveGroup->addChild(conversionPrimitiveGroup.release());
310     return inputPrimitiveGroup.release();
311 }
312 
313 } // namespace geometry
314 } // namespace vkt
315