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