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 tcu::Vec4;
52 using tcu::TestStatus;
53 using tcu::TestContext;
54 using tcu::TestCaseGroup;
55 using de::MovePtr;
56 using std::string;
57 using std::vector;
58
59 class GeometryInputTestInstance : public GeometryExpanderRenderTestInstance
60 {
61 public:
62 GeometryInputTestInstance (Context& context,
63 const VkPrimitiveTopology primitiveType,
64 const char* name);
65
66 GeometryInputTestInstance (Context& context,
67 const VkPrimitiveTopology primitiveType,
68 const char* name,
69 const int numDrawVertices);
70
71 void genVertexAttribData (void);
72 };
73
GeometryInputTestInstance(Context& context, const VkPrimitiveTopology primitiveType, const char* name)74 GeometryInputTestInstance::GeometryInputTestInstance (Context& context,
75 const VkPrimitiveTopology primitiveType,
76 const char* name)
77 : GeometryExpanderRenderTestInstance (context, primitiveType, name)
78 {
79 genVertexAttribData();
80 }
81
GeometryInputTestInstance(Context& context, const VkPrimitiveTopology primitiveType, const char* name, const int numDrawVertices)82 GeometryInputTestInstance::GeometryInputTestInstance (Context& context,
83 const VkPrimitiveTopology primitiveType,
84 const char* name,
85 const int numDrawVertices)
86 : GeometryExpanderRenderTestInstance (context, primitiveType, name)
87 {
88 genVertexAttribData();
89 m_numDrawVertices = numDrawVertices;
90 }
91
genVertexAttribData(void)92 void GeometryInputTestInstance::genVertexAttribData (void)
93 {
94 // Create 1 X 2 grid in triangle strip adjacent - order
95 const float scale = 0.3f;
96 const Vec4 offset (-0.5f, -0.2f, 0.0f, 1.0f);
97 m_numDrawVertices = 12;
98
99 m_vertexPosData.resize(m_numDrawVertices);
100 m_vertexPosData[ 0] = Vec4( 0, 0, 0.0f, 0.0f) * scale + offset;
101 m_vertexPosData[ 1] = Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
102 m_vertexPosData[ 2] = Vec4( 0, -1, 0.0f, 0.0f) * scale + offset;
103 m_vertexPosData[ 3] = Vec4( 1, 1, 0.0f, 0.0f) * scale + offset;
104 m_vertexPosData[ 4] = Vec4( 1, 0, 0.0f, 0.0f) * scale + offset;
105 m_vertexPosData[ 5] = Vec4( 0, -2, 0.0f, 0.0f) * scale + offset;
106 m_vertexPosData[ 6] = Vec4( 1, -1, 0.0f, 0.0f) * scale + offset;
107 m_vertexPosData[ 7] = Vec4( 2, 1, 0.0f, 0.0f) * scale + offset;
108 m_vertexPosData[ 8] = Vec4( 2, 0, 0.0f, 0.0f) * scale + offset;
109 m_vertexPosData[ 9] = Vec4( 1, -2, 0.0f, 0.0f) * scale + offset;
110 m_vertexPosData[10] = Vec4( 2, -1, 0.0f, 0.0f) * scale + offset;
111 m_vertexPosData[11] = Vec4( 3, 0, 0.0f, 0.0f) * scale + offset;
112
113 // Red and white
114 m_vertexAttrData.resize(m_numDrawVertices);
115 for (int i = 0; i < m_numDrawVertices; ++i)
116 m_vertexAttrData[i] = (i % 2 == 0) ? Vec4(1, 1, 1, 1) : Vec4(1, 0, 0, 1);
117 }
118
119 class GeometryExpanderRenderTest : public TestCase
120 {
121 public:
122 GeometryExpanderRenderTest (TestContext& testCtx,
123 const PrimitiveTestSpec& inputPrimitives);
124
125 void initPrograms (SourceCollections& sourceCollections) const;
126 virtual TestInstance* createInstance (Context& context) const;
127 virtual void checkSupport (Context& context) const;
128
129 protected:
130 string shaderGeometry (bool pointSize) const;
131 const VkPrimitiveTopology m_primitiveType;
132 const VkPrimitiveTopology m_outputType;
133 };
134
GeometryExpanderRenderTest(TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives)135 GeometryExpanderRenderTest::GeometryExpanderRenderTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives)
136 : TestCase (testCtx, inputPrimitives.name, inputPrimitives.name)
137 , m_primitiveType (inputPrimitives.primitiveType)
138 , m_outputType (inputPrimitives.outputType)
139 {
140
141 }
142
checkSupport(Context& context) const143 void GeometryExpanderRenderTest::checkSupport (Context& context) const
144 {
145 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
146
147 #ifndef CTS_USES_VULKANSC
148 if (m_primitiveType == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
149 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
150 !context.getPortabilitySubsetFeatures().triangleFans)
151 {
152 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
153 }
154 #endif // CTS_USES_VULKANSC
155 }
156
initPrograms(SourceCollections& sourceCollections) const157 void GeometryExpanderRenderTest::initPrograms (SourceCollections& sourceCollections) const
158 {
159 {
160 std::ostringstream src;
161 src << "#version 310 es\n"
162 <<"layout(location = 0) in highp vec4 a_position;\n"
163 <<"layout(location = 1) in highp vec4 a_color;\n"
164 <<"layout(location = 0) out highp vec4 v_geom_FragColor;\n"
165 <<"void main (void)\n"
166 <<"{\n"
167 <<" gl_Position = a_position;\n"
168 <<" v_geom_FragColor = a_color;\n"
169 <<"}\n";
170 sourceCollections.glslSources.add("vertex") << glu::VertexSource(src.str());
171 }
172
173 {
174 sourceCollections.glslSources.add("geometry") << glu::GeometrySource(shaderGeometry(false));
175 if (m_outputType == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
176 sourceCollections.glslSources.add("geometry_pointsize") << glu::GeometrySource(shaderGeometry(true));
177 }
178
179 {
180 std::ostringstream src;
181 src << "#version 310 es\n"
182 <<"layout(location = 0) out highp vec4 fragColor;\n"
183 <<"layout(location = 0) in highp vec4 v_frag_FragColor;\n"
184 <<"void main (void)\n"
185 <<"{\n"
186 <<" fragColor = v_frag_FragColor;\n"
187 <<"}\n";
188 sourceCollections.glslSources.add("fragment") << glu::FragmentSource(src.str());
189 }
190 }
191
createInstance(Context& context) const192 TestInstance* GeometryExpanderRenderTest::createInstance (Context& context) const
193 {
194 return new GeometryInputTestInstance(context, m_primitiveType, getName());
195 }
196
shaderGeometry(bool pointSize) const197 string GeometryExpanderRenderTest::shaderGeometry (bool pointSize) const
198 {
199 std::ostringstream src;
200 src << "#version 310 es\n"
201 << "#extension GL_EXT_geometry_shader : require\n";
202 if (pointSize)
203 src <<"#extension GL_EXT_geometry_point_size : require\n";
204 src << "layout(" << inputTypeToGLString(m_primitiveType) << ") in;\n"
205 << "layout(" << outputTypeToGLString(m_outputType) << ", max_vertices = " << calcOutputVertices(m_primitiveType) << ") out;\n"
206 << "layout(location = 0) in highp vec4 v_geom_FragColor[];\n"
207 << "layout(location = 0) out highp vec4 v_frag_FragColor;\n"
208 << "\n"
209 << "void main (void)\n"
210 << "{\n"
211 << " const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
212 << " const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
213 << " const highp vec4 offset2 = vec4(-0.01, 0.08, 0.0, 0.0);\n"
214 << " highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
215 << "\n"
216 << " for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
217 << " {\n";
218 if (pointSize)
219 src << " gl_PointSize = 1.0;\n";
220 src << " gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
221 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
222 << " EmitVertex();\n"
223 << "\n";
224 if (pointSize)
225 src << " gl_PointSize = 1.0;\n";
226 src << " gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
227 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
228 << " EmitVertex();\n"
229 << "\n";
230 if (pointSize)
231 src << " gl_PointSize = 1.0;\n";
232 src << " gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
233 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
234 << " EmitVertex();\n"
235 << " EndPrimitive();\n"
236 << " }\n"
237 << "}\n";
238 return src.str();
239 }
240
241 class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
242 {
243 public:
244 TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices);
245 virtual TestInstance* createInstance (Context& context) const;
246 private:
247 const int m_numInputVertices;
248 };
249
TriangleStripAdjacencyVertexCountTest(TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices)250 TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices)
251 : GeometryExpanderRenderTest (testCtx, inputPrimitives)
252 , m_numInputVertices (numInputVertices)
253 {
254 }
255
createInstance(Context& context) const256 TestInstance* TriangleStripAdjacencyVertexCountTest::createInstance (Context& context) const
257 {
258 return new GeometryInputTestInstance(context, m_primitiveType, getName(), m_numInputVertices);
259 }
260
261 } // anonymous
262
createInputGeometryShaderTests(TestContext& testCtx)263 TestCaseGroup* createInputGeometryShaderTests (TestContext& testCtx)
264 {
265 MovePtr<TestCaseGroup> inputPrimitiveGroup (new TestCaseGroup(testCtx, "input", "Different input primitives."));
266 MovePtr<TestCaseGroup> basicPrimitiveGroup (new TestCaseGroup(testCtx, "basic_primitive", "Basic Primitive geometry tests"));
267 MovePtr<TestCaseGroup> triStripAdjacencyGroup (new TestCaseGroup(testCtx, "triangle_strip_adjacency", "Different triangle_strip_adjacency vertex counts."));
268 MovePtr<TestCaseGroup> conversionPrimitiveGroup (new TestCaseGroup(testCtx, "conversion", "Different input and output primitives."));
269
270 const PrimitiveTestSpec inputPrimitives[] =
271 {
272 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
273 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
274 { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
275 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
276 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
277 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
278 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, "lines_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
279 { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, "line_strip_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
280 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, "triangles_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }
281 };
282
283 // more basic types
284 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
285 basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, inputPrimitives[ndx]));
286
287 // triangle strip adjacency with different vertex counts
288 for (int vertexCount = 0; vertexCount <= 12; ++vertexCount)
289 {
290 const string name = "vertex_count_" + de::toString(vertexCount);
291 const PrimitiveTestSpec primitives = { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, name.c_str(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP };
292
293 triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(testCtx, primitives, vertexCount));
294 }
295
296 // different type conversions
297 {
298 static const PrimitiveTestSpec conversionPrimitives[] =
299 {
300 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
301 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
302 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
303 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
304 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
305 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}
306 };
307
308 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
309 conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, conversionPrimitives[ndx]));
310 }
311
312 inputPrimitiveGroup->addChild(basicPrimitiveGroup.release());
313 inputPrimitiveGroup->addChild(triStripAdjacencyGroup.release());
314 inputPrimitiveGroup->addChild(conversionPrimitiveGroup.release());
315 return inputPrimitiveGroup.release();
316 }
317
318 } // geometry
319 } // vkt
320