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 if (m_primitiveType == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
148 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
149 !context.getPortabilitySubsetFeatures().triangleFans)
150 {
151 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
152 }
153 }
154
initPrograms(SourceCollections & sourceCollections) const155 void GeometryExpanderRenderTest::initPrograms (SourceCollections& sourceCollections) const
156 {
157 {
158 std::ostringstream src;
159 src << "#version 310 es\n"
160 <<"layout(location = 0) in highp vec4 a_position;\n"
161 <<"layout(location = 1) in highp vec4 a_color;\n"
162 <<"layout(location = 0) out highp vec4 v_geom_FragColor;\n"
163 <<"void main (void)\n"
164 <<"{\n"
165 <<" gl_Position = a_position;\n"
166 <<" v_geom_FragColor = a_color;\n"
167 <<"}\n";
168 sourceCollections.glslSources.add("vertex") << glu::VertexSource(src.str());
169 }
170
171 {
172 sourceCollections.glslSources.add("geometry") << glu::GeometrySource(shaderGeometry(false));
173 if (m_outputType == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
174 sourceCollections.glslSources.add("geometry_pointsize") << glu::GeometrySource(shaderGeometry(true));
175 }
176
177 {
178 std::ostringstream src;
179 src << "#version 310 es\n"
180 <<"layout(location = 0) out highp vec4 fragColor;\n"
181 <<"layout(location = 0) in highp vec4 v_frag_FragColor;\n"
182 <<"void main (void)\n"
183 <<"{\n"
184 <<" fragColor = v_frag_FragColor;\n"
185 <<"}\n";
186 sourceCollections.glslSources.add("fragment") << glu::FragmentSource(src.str());
187 }
188 }
189
createInstance(Context & context) const190 TestInstance* GeometryExpanderRenderTest::createInstance (Context& context) const
191 {
192 return new GeometryInputTestInstance(context, m_primitiveType, getName());
193 }
194
shaderGeometry(bool pointSize) const195 string GeometryExpanderRenderTest::shaderGeometry (bool pointSize) const
196 {
197 std::ostringstream src;
198 src << "#version 310 es\n"
199 << "#extension GL_EXT_geometry_shader : require\n";
200 if (pointSize)
201 src <<"#extension GL_EXT_geometry_point_size : require\n";
202 src << "layout(" << inputTypeToGLString(m_primitiveType) << ") in;\n"
203 << "layout(" << outputTypeToGLString(m_outputType) << ", max_vertices = " << calcOutputVertices(m_primitiveType) << ") out;\n"
204 << "layout(location = 0) in highp vec4 v_geom_FragColor[];\n"
205 << "layout(location = 0) out highp vec4 v_frag_FragColor;\n"
206 << "\n"
207 << "void main (void)\n"
208 << "{\n"
209 << " const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
210 << " const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
211 << " const highp vec4 offset2 = vec4(-0.01, 0.08, 0.0, 0.0);\n"
212 << " highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
213 << "\n"
214 << " for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
215 << " {\n";
216 if (pointSize)
217 src << " gl_PointSize = 1.0;\n";
218 src << " gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
219 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
220 << " EmitVertex();\n"
221 << "\n";
222 if (pointSize)
223 src << " gl_PointSize = 1.0;\n";
224 src << " gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
225 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
226 << " EmitVertex();\n"
227 << "\n";
228 if (pointSize)
229 src << " gl_PointSize = 1.0;\n";
230 src << " gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
231 << " v_frag_FragColor = v_geom_FragColor[ndx];\n"
232 << " EmitVertex();\n"
233 << " EndPrimitive();\n"
234 << " }\n"
235 << "}\n";
236 return src.str();
237 }
238
239 class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
240 {
241 public:
242 TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices);
243 virtual TestInstance* createInstance (Context& context) const;
244 private:
245 const int m_numInputVertices;
246 };
247
TriangleStripAdjacencyVertexCountTest(TestContext & testCtx,const PrimitiveTestSpec & inputPrimitives,const int numInputVertices)248 TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices)
249 : GeometryExpanderRenderTest (testCtx, inputPrimitives)
250 , m_numInputVertices (numInputVertices)
251 {
252 }
253
createInstance(Context & context) const254 TestInstance* TriangleStripAdjacencyVertexCountTest::createInstance (Context& context) const
255 {
256 return new GeometryInputTestInstance(context, m_primitiveType, getName(), m_numInputVertices);
257 }
258
259 } // anonymous
260
createInputGeometryShaderTests(TestContext & testCtx)261 TestCaseGroup* createInputGeometryShaderTests (TestContext& testCtx)
262 {
263 MovePtr<TestCaseGroup> inputPrimitiveGroup (new TestCaseGroup(testCtx, "input", "Different input primitives."));
264 MovePtr<TestCaseGroup> basicPrimitiveGroup (new TestCaseGroup(testCtx, "basic_primitive", "Basic Primitive geometry tests"));
265 MovePtr<TestCaseGroup> triStripAdjacencyGroup (new TestCaseGroup(testCtx, "triangle_strip_adjacency", "Different triangle_strip_adjacency vertex counts."));
266 MovePtr<TestCaseGroup> conversionPrimitiveGroup (new TestCaseGroup(testCtx, "conversion", "Different input and output primitives."));
267
268 const PrimitiveTestSpec inputPrimitives[] =
269 {
270 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
271 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
272 { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
273 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
274 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
275 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
276 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, "lines_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
277 { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, "line_strip_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
278 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, "triangles_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }
279 };
280
281 // more basic types
282 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
283 basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, inputPrimitives[ndx]));
284
285 // triangle strip adjacency with different vertex counts
286 for (int vertexCount = 0; vertexCount <= 12; ++vertexCount)
287 {
288 const string name = "vertex_count_" + de::toString(vertexCount);
289 const PrimitiveTestSpec primitives = { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, name.c_str(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP };
290
291 triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(testCtx, primitives, vertexCount));
292 }
293
294 // different type conversions
295 {
296 static const PrimitiveTestSpec conversionPrimitives[] =
297 {
298 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
299 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
300 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
301 { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
302 { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
303 { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}
304 };
305
306 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
307 conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, conversionPrimitives[ndx]));
308 }
309
310 inputPrimitiveGroup->addChild(basicPrimitiveGroup.release());
311 inputPrimitiveGroup->addChild(triStripAdjacencyGroup.release());
312 inputPrimitiveGroup->addChild(conversionPrimitiveGroup.release());
313 return inputPrimitiveGroup.release();
314 }
315
316 } // geometry
317 } // vkt
318