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 Emit Geometry Shader Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktGeometryEmitGeometryShaderTests.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 tcu::TestCaseGroup;
54 using tcu::TestContext;
55 using tcu::TestStatus;
56 using tcu::Vec4;
57 
58 typedef enum VertexOutputs
59 {
60     VERTEXT_NO_OP = -1,
61     VERTEXT_ZERO,
62     VERTEXT_ONE
63 } VertexOut;
64 typedef enum GeometryOutputs
65 {
66     GEOMETRY_ZERO,
67     GEOMETRY_ONE,
68     GEOMETRY_TWO
69 } GeometryOut;
70 
71 struct EmitTestSpec
72 {
73     VkPrimitiveTopology primitiveTopology;
74     int emitCountA; //!< primitive A emit count
75     int endCountA;  //!< primitive A end count
76     int emitCountB; //!<
77     int endCountB;  //!<
78     string name;
79     string desc;
80 };
81 
82 class GeometryEmitTestInstance : public GeometryExpanderRenderTestInstance
83 {
84 public:
85     GeometryEmitTestInstance(Context &context, const char *name);
86     void genVertexAttribData(void);
87 };
88 
GeometryEmitTestInstance(Context & context,const char * name)89 GeometryEmitTestInstance::GeometryEmitTestInstance(Context &context, const char *name)
90     : GeometryExpanderRenderTestInstance(context, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, name)
91 {
92     genVertexAttribData();
93 }
94 
genVertexAttribData(void)95 void GeometryEmitTestInstance::genVertexAttribData(void)
96 {
97     m_numDrawVertices = 1;
98     m_vertexPosData.resize(m_numDrawVertices);
99     m_vertexPosData[0] = Vec4(0, 0, 0, 1);
100 
101     m_vertexAttrData.resize(m_numDrawVertices);
102     m_vertexAttrData[0] = Vec4(1, 1, 1, 1);
103 }
104 
105 class EmitTest : public TestCase
106 {
107 public:
108     EmitTest(TestContext &testCtx, const EmitTestSpec &emitTestSpec);
109 
110     void initPrograms(SourceCollections &sourceCollections) const;
111     virtual TestInstance *createInstance(Context &context) const;
112     virtual void checkSupport(Context &context) const;
113 
114 protected:
115     string shaderGeometry(bool pointSize) const;
116     const EmitTestSpec m_emitTestSpec;
117 };
118 
EmitTest(TestContext & testCtx,const EmitTestSpec & emitTestSpec)119 EmitTest::EmitTest(TestContext &testCtx, const EmitTestSpec &emitTestSpec)
120     : TestCase(testCtx, emitTestSpec.name)
121     , m_emitTestSpec(emitTestSpec)
122 
123 {
124 }
125 
checkSupport(Context & context) const126 void EmitTest::checkSupport(Context &context) const
127 {
128     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
129 }
130 
initPrograms(SourceCollections & sourceCollections) const131 void EmitTest::initPrograms(SourceCollections &sourceCollections) const
132 {
133     {
134         std::ostringstream src;
135         src << "#version 310 es\n"
136             << "layout(location = 0) in highp vec4 a_position;\n"
137             << "layout(location = 1) in highp vec4 a_color;\n"
138             << "layout(location = 0) out highp vec4 v_geom_FragColor;\n"
139             << "void main (void)\n"
140             << "{\n"
141             << "    gl_Position = a_position;\n"
142             << "    v_geom_FragColor = a_color;\n"
143             << "}\n";
144         sourceCollections.glslSources.add("vertex") << glu::VertexSource(src.str());
145     }
146 
147     {
148         sourceCollections.glslSources.add("geometry") << glu::GeometrySource(shaderGeometry(false));
149         if (m_emitTestSpec.primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
150             sourceCollections.glslSources.add("geometry_pointsize") << glu::GeometrySource(shaderGeometry(true));
151     }
152 
153     {
154         std::ostringstream src;
155         src << "#version 310 es\n"
156             << "layout(location = 0) out mediump vec4 fragColor;\n"
157             << "layout(location = 0) in highp vec4 v_frag_FragColor;\n"
158             << "void main (void)\n"
159             << "{\n"
160             << "    fragColor = v_frag_FragColor;\n"
161             << "}\n";
162         sourceCollections.glslSources.add("fragment") << glu::FragmentSource(src.str());
163     }
164 }
165 
createInstance(Context & context) const166 TestInstance *EmitTest::createInstance(Context &context) const
167 {
168     return new GeometryEmitTestInstance(context, getName());
169 }
170 
shaderGeometry(bool pointSize) const171 string EmitTest::shaderGeometry(bool pointSize) const
172 {
173     std::ostringstream src;
174     src << "#version 310 es\n"
175         << "#extension GL_EXT_geometry_shader : require\n";
176     if (pointSize)
177         src << "#extension GL_EXT_geometry_point_size : require\n";
178     src << "layout(points) in;\n"
179         << "layout(" << outputTypeToGLString(m_emitTestSpec.primitiveTopology)
180         << ", max_vertices = " << (m_emitTestSpec.emitCountA + m_emitTestSpec.emitCountB + 1) << ") out;\n"
181         << "layout(location = 0) in highp vec4 v_geom_FragColor[];\n"
182         << "layout(location = 0) out highp vec4 v_frag_FragColor;\n"
183         << "void main (void)\n"
184         << "{\n"
185         << "    const highp vec4 position0 = vec4(-0.5,  0.5, 0.0, 0.0);\n"
186         << "    const highp vec4 position1 = vec4( 0.0,  0.1, 0.0, 0.0);\n"
187         << "    const highp vec4 position2 = vec4( 0.5,  0.5, 0.0, 0.0);\n"
188         << "    const highp vec4 position3 = vec4( 0.7, -0.2, 0.0, 0.0);\n"
189         << "    const highp vec4 position4 = vec4( 0.2,  0.2, 0.0, 0.0);\n"
190         << "    const highp vec4 position5 = vec4( 0.4, -0.3, 0.0, 0.0);\n";
191     for (int i = 0; i < m_emitTestSpec.emitCountA; ++i)
192     {
193         if (pointSize)
194             src << "    gl_PointSize = 1.0;\n";
195         src << "    gl_Position = gl_in[0].gl_Position + position" << i
196             << ";\n"
197                "    gl_PrimitiveID = gl_PrimitiveIDIn;\n"
198                "    v_frag_FragColor = v_geom_FragColor[0];\n"
199                "    EmitVertex();\n"
200                "\n";
201     }
202 
203     for (int i = 0; i < m_emitTestSpec.endCountA; ++i)
204         src << "    EndPrimitive();\n";
205 
206     for (int i = 0; i < m_emitTestSpec.emitCountB; ++i)
207     {
208         if (pointSize)
209             src << "    gl_PointSize = 1.0;\n";
210         src << "    gl_Position = gl_in[0].gl_Position + position" << (m_emitTestSpec.emitCountA + i)
211             << ";\n"
212                "    gl_PrimitiveID = gl_PrimitiveIDIn;\n"
213                "    v_frag_FragColor = v_geom_FragColor[0];\n"
214                "    EmitVertex();\n"
215                "\n";
216     }
217 
218     for (int i = 0; i < m_emitTestSpec.endCountB; ++i)
219         src << "    EndPrimitive();\n";
220     src << "}\n";
221     return src.str();
222 }
223 
224 } // namespace
225 
createEmitGeometryShaderTests(TestContext & testCtx)226 TestCaseGroup *createEmitGeometryShaderTests(TestContext &testCtx)
227 {
228     MovePtr<TestCaseGroup> emitGroup(new TestCaseGroup(testCtx, "emit"));
229 
230     // emit different amounts
231     {
232         EmitTestSpec emitTests[] = {
233             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, 0, 0, 0, "points", ""},
234             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, 1, 0, 0, "points", ""},
235             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 1, 1, 0, 0, "points", ""},
236             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, 2, 0, 0, "points", ""},
237             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 1, 2, 0, 0, "points", ""},
238             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0, 0, 0, 0, "line_strip", ""},
239             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0, 1, 0, 0, "line_strip", ""},
240             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 1, 1, 0, 0, "line_strip", ""},
241             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 2, 1, 0, 0, "line_strip", ""},
242             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0, 2, 0, 0, "line_strip", ""},
243             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 1, 2, 0, 0, "line_strip", ""},
244             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 2, 2, 0, 0, "line_strip", ""},
245             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 2, 2, 2, 0, "line_strip", ""},
246             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, 0, 0, 0, "triangle_strip", ""},
247             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, 1, 0, 0, "triangle_strip", ""},
248             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 1, 1, 0, 0, "triangle_strip", ""},
249             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 2, 1, 0, 0, "triangle_strip", ""},
250             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 3, 1, 0, 0, "triangle_strip", ""},
251             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, 2, 0, 0, "triangle_strip", ""},
252             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 1, 2, 0, 0, "triangle_strip", ""},
253             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 2, 2, 0, 0, "triangle_strip", ""},
254             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 3, 2, 0, 0, "triangle_strip", ""},
255             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 3, 2, 3, 0, "triangle_strip", ""},
256         };
257 
258         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(emitTests); ++ndx)
259         {
260             emitTests[ndx].name = std::string(emitTests[ndx].name) + "_emit_" +
261                                   de::toString(emitTests[ndx].emitCountA) + "_end_" +
262                                   de::toString(emitTests[ndx].endCountA);
263             emitTests[ndx].desc = std::string(emitTests[ndx].name) + " output, emit " +
264                                   de::toString(emitTests[ndx].emitCountA) + " vertices, call EndPrimitive " +
265                                   de::toString(emitTests[ndx].endCountA) + " times";
266 
267             if (emitTests[ndx].emitCountB)
268             {
269                 emitTests[ndx].name += "_emit_" + de::toString(emitTests[ndx].emitCountB) + "_end_" +
270                                        de::toString(emitTests[ndx].endCountB);
271                 emitTests[ndx].desc += ", emit " + de::toString(emitTests[ndx].emitCountB) +
272                                        " vertices, call EndPrimitive " + de::toString(emitTests[ndx].endCountB) +
273                                        " times";
274             }
275 
276             emitGroup->addChild(new EmitTest(testCtx, emitTests[ndx]));
277         }
278     }
279 
280     return emitGroup.release();
281 }
282 
283 } // namespace geometry
284 } // namespace vkt
285