1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Imagination Technologies Ltd.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Input Assembly Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineInputAssemblyTests.hpp"
28 #include "vktPipelineClearUtil.hpp"
29 #include "vktPipelineImageUtil.hpp"
30 #include "vktPipelineVertexUtil.hpp"
31 #include "vktPipelineReferenceRenderer.hpp"
32 #include "vktAmberTestCase.hpp"
33 #include "vktTestCase.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkRef.hpp"
39 #include "vkRefUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "tcuImageCompare.hpp"
44 #include "deMath.h"
45 #include "deMemory.h"
46 #include "deRandom.hpp"
47 #include "deStringUtil.hpp"
48 #include "deUniquePtr.hpp"
49 
50 #include <algorithm>
51 #include <sstream>
52 #include <vector>
53 
54 namespace vkt
55 {
56 namespace pipeline
57 {
58 
59 using namespace vk;
60 
61 enum class RestartType
62 {
63     NORMAL,
64     NONE,
65     ALL,
66 };
67 
68 namespace
69 {
70 
71 class InputAssemblyTest : public vkt::TestCase
72 {
73 public:
74     const static VkPrimitiveTopology s_primitiveTopologies[];
75     const static uint32_t s_restartIndex32;
76     const static uint16_t s_restartIndex16;
77     const static uint8_t s_restartIndex8;
78 
79     InputAssemblyTest(tcu::TestContext &testContext, const std::string &name,
80                       const PipelineConstructionType pipelineConstructionType, VkPrimitiveTopology primitiveTopology,
81                       int primitiveCount, bool testPrimitiveRestart, VkIndexType indexType);
~InputAssemblyTest(void)82     virtual ~InputAssemblyTest(void)
83     {
84     }
85     virtual void initPrograms(SourceCollections &sourceCollections) const;
86     virtual void checkSupport(Context &context) const;
87     virtual TestInstance *createInstance(Context &context) const;
88     static bool isRestartIndex(VkIndexType indexType, uint32_t indexValue);
89 #ifndef CTS_USES_VULKANSC
90     static uint32_t getRestartIndex(VkIndexType indexType);
91 #endif // CTS_USES_VULKANSC
92 
93 protected:
94     virtual void createBufferData(VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType,
95                                   std::vector<uint32_t> &indexData, std::vector<Vertex4RGBA> &vertexData) const = 0;
96     VkPrimitiveTopology m_primitiveTopology;
97     const int m_primitiveCount;
98 
99 private:
100     const PipelineConstructionType m_pipelineConstructionType;
101     bool m_testPrimitiveRestart;
102     VkIndexType m_indexType;
103 };
104 
105 class PrimitiveTopologyTest : public InputAssemblyTest
106 {
107 public:
108     PrimitiveTopologyTest(tcu::TestContext &testContext, const std::string &name,
109                           PipelineConstructionType pipelineConstructionType, VkPrimitiveTopology primitiveTopology,
110                           VkIndexType indexType);
~PrimitiveTopologyTest(void)111     virtual ~PrimitiveTopologyTest(void)
112     {
113     }
114 
115 protected:
116     virtual void createBufferData(VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType,
117                                   std::vector<uint32_t> &indexData, std::vector<Vertex4RGBA> &vertexData) const;
118 
119 private:
120 };
121 
122 #ifndef CTS_USES_VULKANSC
123 class PrimitiveRestartTest : public InputAssemblyTest
124 {
125 public:
126     PrimitiveRestartTest(tcu::TestContext &testContext, const std::string &name,
127                          const PipelineConstructionType pipelineConstructionType, VkPrimitiveTopology primitiveTopology,
128                          VkIndexType indexType, RestartType restartType);
~PrimitiveRestartTest(void)129     virtual ~PrimitiveRestartTest(void)
130     {
131     }
132     virtual void checkSupport(Context &context) const;
133 
134 protected:
135     virtual void createBufferData(VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType,
136                                   std::vector<uint32_t> &indexData, std::vector<Vertex4RGBA> &vertexData) const;
137 
138 private:
139     bool isRestartPrimitive(int primitiveIndex) const;
140     void createListPrimitives(int primitiveCount, float originX, float originY, float primitiveSizeX,
141                               float primitiveSizeY, int verticesPerPrimitive, VkIndexType indexType,
142                               std::vector<uint32_t> &indexData, std::vector<Vertex4RGBA> &vertexData,
143                               std::vector<uint32_t> adjacencies) const;
144 
145     std::vector<uint32_t> m_restartPrimitives;
146     RestartType m_restartType;
147 };
148 #endif // CTS_USES_VULKANSC
149 
150 class InputAssemblyInstance : public vkt::TestInstance
151 {
152 public:
153     InputAssemblyInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
154                           const VkPrimitiveTopology primitiveTopology, bool testPrimitiveRestart, VkIndexType indexType,
155                           const std::vector<uint32_t> &indexBufferData,
156                           const std::vector<Vertex4RGBA> &vertexBufferData);
157     virtual ~InputAssemblyInstance(void);
158     virtual tcu::TestStatus iterate(void);
159 
160 private:
161     tcu::TestStatus verifyImage(void);
162     void uploadIndexBufferData16(uint16_t *destPtr, const std::vector<uint32_t> &indexBufferData);
163     void uploadIndexBufferData8(uint8_t *destPtr, const std::vector<uint32_t> &indexBufferData);
164 
165     VkPrimitiveTopology m_primitiveTopology;
166     bool m_primitiveRestartEnable;
167     VkIndexType m_indexType;
168 
169     Move<VkBuffer> m_vertexBuffer;
170     std::vector<Vertex4RGBA> m_vertices;
171     de::MovePtr<Allocation> m_vertexBufferAlloc;
172 
173     Move<VkBuffer> m_indexBuffer;
174     std::vector<uint32_t> m_indices;
175     de::MovePtr<Allocation> m_indexBufferAlloc;
176 
177     const tcu::UVec2 m_renderSize;
178 
179     const VkFormat m_colorFormat;
180     VkImageCreateInfo m_colorImageCreateInfo;
181     Move<VkImage> m_colorImage;
182     de::MovePtr<Allocation> m_colorImageAlloc;
183     Move<VkImageView> m_colorAttachmentView;
184     RenderPassWrapper m_renderPass;
185     Move<VkFramebuffer> m_framebuffer;
186 
187     ShaderWrapper m_vertexShaderModule;
188     ShaderWrapper m_fragmentShaderModule;
189     ShaderWrapper m_tcsShaderModule;
190     ShaderWrapper m_tesShaderModule;
191 
192     PipelineLayoutWrapper m_pipelineLayout;
193     GraphicsPipelineWrapper m_graphicsPipeline;
194 
195     Move<VkCommandPool> m_cmdPool;
196     Move<VkCommandBuffer> m_cmdBuffer;
197 };
198 
199 // InputAssemblyTest
200 
201 const VkPrimitiveTopology InputAssemblyTest::s_primitiveTopologies[] = {
202     VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
203     VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
204     VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
205     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
206     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
207     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
208     VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
209     VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
210     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
211     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY};
212 
213 const uint32_t InputAssemblyTest::s_restartIndex32 = ~((uint32_t)0u);
214 const uint16_t InputAssemblyTest::s_restartIndex16 = ~((uint16_t)0u);
215 const uint8_t InputAssemblyTest::s_restartIndex8   = ~((uint8_t)0u);
216 
InputAssemblyTest(tcu::TestContext & testContext,const std::string & name,const PipelineConstructionType pipelineConstructionType,VkPrimitiveTopology primitiveTopology,int primitiveCount,bool testPrimitiveRestart,VkIndexType indexType)217 InputAssemblyTest::InputAssemblyTest(tcu::TestContext &testContext, const std::string &name,
218                                      const PipelineConstructionType pipelineConstructionType,
219                                      VkPrimitiveTopology primitiveTopology, int primitiveCount,
220                                      bool testPrimitiveRestart, VkIndexType indexType)
221     : vkt::TestCase(testContext, name)
222     , m_primitiveTopology(primitiveTopology)
223     , m_primitiveCount(primitiveCount)
224     , m_pipelineConstructionType(pipelineConstructionType)
225     , m_testPrimitiveRestart(testPrimitiveRestart)
226     , m_indexType(indexType)
227 {
228 }
229 
checkSupport(Context & context) const230 void InputAssemblyTest::checkSupport(Context &context) const
231 {
232     if (m_indexType == VK_INDEX_TYPE_UINT8_EXT)
233     {
234         if (!context.isDeviceFunctionalitySupported("VK_KHR_index_type_uint8") &&
235             !context.isDeviceFunctionalitySupported("VK_EXT_index_type_uint8"))
236         {
237             TCU_THROW(NotSupportedError, "VK_KHR_index_type_uint8 and VK_EXT_index_type_uint8 is not supported");
238         }
239     }
240 
241     switch (m_primitiveTopology)
242     {
243     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
244     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
245     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
246     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
247         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
248         break;
249 
250     case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
251         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
252         break;
253 
254     default:
255         break;
256     }
257 
258     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
259                                           m_pipelineConstructionType);
260 
261 #ifndef CTS_USES_VULKANSC
262     if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
263         context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
264         !context.getPortabilitySubsetFeatures().triangleFans)
265     {
266         TCU_THROW(NotSupportedError,
267                   "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
268     }
269 #endif // CTS_USES_VULKANSC
270 }
271 
createInstance(Context & context) const272 TestInstance *InputAssemblyTest::createInstance(Context &context) const
273 {
274     std::vector<uint32_t> indexBufferData;
275     std::vector<Vertex4RGBA> vertexBufferData;
276 
277     createBufferData(m_primitiveTopology, m_primitiveCount, m_indexType, indexBufferData, vertexBufferData);
278 
279     return new InputAssemblyInstance(context, m_pipelineConstructionType, m_primitiveTopology, m_testPrimitiveRestart,
280                                      m_indexType, indexBufferData, vertexBufferData);
281 }
282 
initPrograms(SourceCollections & sourceCollections) const283 void InputAssemblyTest::initPrograms(SourceCollections &sourceCollections) const
284 {
285     std::ostringstream vertexSource;
286 
287     vertexSource << "#version 310 es\n"
288                     "layout(location = 0) in vec4 position;\n"
289                     "layout(location = 1) in vec4 color;\n"
290                     "layout(location = 0) out highp vec4 vtxColor;\n"
291                     "void main (void)\n"
292                     "{\n"
293                     "    gl_Position = position;\n"
294                  << (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? "    gl_PointSize = 3.0;\n" : "")
295                  << "    vtxColor = color;\n"
296                     "}\n";
297 
298     sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
299 
300     sourceCollections.glslSources.add("color_frag")
301         << glu::FragmentSource("#version 310 es\n"
302                                "layout(location = 0) in highp vec4 vtxColor;\n"
303                                "layout(location = 0) out highp vec4 fragColor;\n"
304                                "void main (void)\n"
305                                "{\n"
306                                "    fragColor = vtxColor;\n"
307                                "}\n");
308 
309     sourceCollections.glslSources.add("color_tcs")
310         << glu::TessellationControlSource("#version 310 es\n"
311                                           "#extension GL_EXT_tessellation_shader : require\n"
312                                           "layout(vertices = 3) out;\n"
313                                           "layout(location = 0) in highp vec4 vtxColorIn[];\n"
314                                           "layout(location = 0) out highp vec4 vtxColorOut[];\n"
315                                           "#define ID gl_InvocationID\n"
316                                           "void main (void)\n"
317                                           "{\n"
318                                           "    vtxColorOut[ID] = vtxColorIn[ID];\n"
319                                           "    gl_out[ID].gl_Position = gl_in[ID].gl_Position;\n"
320                                           "    if (ID == 0)\n"
321                                           "    {\n"
322                                           "        gl_TessLevelInner[0] = 5.0;\n"
323                                           "        gl_TessLevelOuter[0] = 4.0;\n"
324                                           "        gl_TessLevelOuter[1] = 5.0;\n"
325                                           "        gl_TessLevelOuter[2] = 6.0;\n"
326                                           "    }\n"
327                                           "}\n");
328 
329     sourceCollections.glslSources.add("color_tes")
330         << glu::TessellationEvaluationSource("#version 310 es\n"
331                                              "#extension GL_EXT_tessellation_shader : require\n"
332                                              "layout(triangles) in;\n"
333                                              "layout(location = 0) in vec4 vtxColorIn[];\n"
334                                              "layout(location = 0) out vec4 vtxColorOut;\n"
335                                              "void main (void)\n"
336                                              "{\n"
337                                              "    vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position;\n"
338                                              "    vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position;\n"
339                                              "    vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position;\n"
340                                              "    gl_Position = p0 + p1 + p2;\n"
341                                              "    vec4 q0 = gl_TessCoord.x * vtxColorIn[0];\n"
342                                              "    vec4 q1 = gl_TessCoord.y * vtxColorIn[1];\n"
343                                              "    vec4 q2 = gl_TessCoord.z * vtxColorIn[2];\n"
344                                              "    vtxColorOut = q0 + q1 + q2;\n"
345                                              "}\n");
346 }
347 
isRestartIndex(VkIndexType indexType,uint32_t indexValue)348 bool InputAssemblyTest::isRestartIndex(VkIndexType indexType, uint32_t indexValue)
349 {
350     if (indexType == VK_INDEX_TYPE_UINT16)
351         return indexValue == s_restartIndex16;
352     else if (indexType == VK_INDEX_TYPE_UINT8_EXT)
353         return indexValue == s_restartIndex8;
354     else
355         return indexValue == s_restartIndex32;
356 }
357 
358 #ifndef CTS_USES_VULKANSC
getRestartIndex(VkIndexType indexType)359 uint32_t InputAssemblyTest::getRestartIndex(VkIndexType indexType)
360 {
361     if (indexType == VK_INDEX_TYPE_UINT16)
362         return InputAssemblyTest::s_restartIndex16;
363     else if (indexType == VK_INDEX_TYPE_UINT8_EXT)
364         return InputAssemblyTest::s_restartIndex8;
365     else
366         return InputAssemblyTest::s_restartIndex32;
367 }
368 #endif // CTS_USES_VULKANSC
369 
370 // PrimitiveTopologyTest
371 
PrimitiveTopologyTest(tcu::TestContext & testContext,const std::string & name,PipelineConstructionType pipelineConstructionType,VkPrimitiveTopology primitiveTopology,VkIndexType indexType)372 PrimitiveTopologyTest::PrimitiveTopologyTest(tcu::TestContext &testContext, const std::string &name,
373                                              PipelineConstructionType pipelineConstructionType,
374                                              VkPrimitiveTopology primitiveTopology, VkIndexType indexType)
375     : InputAssemblyTest(testContext, name, pipelineConstructionType, primitiveTopology, 10, false, indexType)
376 {
377 }
378 
createBufferData(VkPrimitiveTopology topology,int primitiveCount,VkIndexType indexType,std::vector<uint32_t> & indexData,std::vector<Vertex4RGBA> & vertexData) const379 void PrimitiveTopologyTest::createBufferData(VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType,
380                                              std::vector<uint32_t> &indexData,
381                                              std::vector<Vertex4RGBA> &vertexData) const
382 {
383     DE_ASSERT(primitiveCount > 0);
384     DE_UNREF(indexType);
385 
386     const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
387     const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
388     const float border              = 0.2f;
389     const float originX             = -1.0f + border;
390     const float originY             = -1.0f + border;
391     const Vertex4RGBA defaultVertex = {tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green};
392     float primitiveSizeY            = (2.0f - 2.0f * border);
393     float primitiveSizeX;
394     std::vector<uint32_t> indices;
395     std::vector<Vertex4RGBA> vertices;
396 
397     // Calculate primitive size
398     switch (topology)
399     {
400     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
401         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
402         break;
403 
404     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
405     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
406         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount - 1);
407         break;
408 
409     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
410     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
411         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
412         break;
413 
414     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
415     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
416         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount + primitiveCount / 2 + primitiveCount % 2 - 1);
417         break;
418 
419     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
420     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
421         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
422         break;
423 
424     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
425         primitiveSizeX = 1.0f - border;
426         primitiveSizeY = 1.0f - border;
427         break;
428 
429     default:
430         primitiveSizeX = 0.0f; // Garbage
431         DE_ASSERT(false);
432     }
433 
434     switch (topology)
435     {
436     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
437         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
438         {
439             const Vertex4RGBA vertex = {tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX,
440                                                   originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
441                                         red};
442 
443             vertices.push_back(vertex);
444             indices.push_back(primitiveNdx);
445         }
446         break;
447 
448     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
449         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
450         {
451             for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
452             {
453                 const Vertex4RGBA vertex = {
454                     tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX,
455                               originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
456                     red};
457 
458                 vertices.push_back(vertex);
459                 indices.push_back((primitiveNdx * 2 + vertexNdx));
460             }
461         }
462         break;
463 
464     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
465         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
466         {
467             if (primitiveNdx == 0)
468             {
469                 Vertex4RGBA vertex = {tcu::Vec4(originX, originY, 0.0f, 1.0f), red};
470 
471                 vertices.push_back(vertex);
472                 indices.push_back(0);
473 
474                 vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
475                 vertices.push_back(vertex);
476                 indices.push_back(1);
477             }
478             else
479             {
480                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX,
481                                                       originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f,
482                                                       1.0f),
483                                             red};
484 
485                 vertices.push_back(vertex);
486                 indices.push_back(primitiveNdx + 1);
487             }
488         }
489         break;
490 
491     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
492         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
493         {
494             for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
495             {
496                 const Vertex4RGBA vertex = {
497                     tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX,
498                               originY + float((primitiveNdx * 3 + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
499                     red};
500 
501                 vertices.push_back(vertex);
502                 indices.push_back(primitiveNdx * 3 + vertexNdx);
503             }
504         }
505         break;
506 
507     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
508         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
509         {
510             if (primitiveNdx == 0)
511             {
512                 for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
513                 {
514                     const Vertex4RGBA vertex = {tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX,
515                                                           originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
516                                                 red};
517 
518                     vertices.push_back(vertex);
519                     indices.push_back(vertexNdx);
520                 }
521             }
522             else
523             {
524                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX,
525                                                       originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f,
526                                                       1.0f),
527                                             red};
528 
529                 vertices.push_back(vertex);
530                 indices.push_back(primitiveNdx + 2);
531             }
532         }
533         break;
534 
535     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
536     {
537         const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
538 
539         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
540         {
541             if (primitiveNdx == 0)
542             {
543                 Vertex4RGBA vertex = {tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), red};
544 
545                 vertices.push_back(vertex);
546                 indices.push_back(0);
547 
548                 vertex.position = tcu::Vec4(primitiveSizeX, 0.0f, 0.0f, 1.0f);
549                 vertices.push_back(vertex);
550                 indices.push_back(1);
551 
552                 vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle),
553                                             primitiveSizeY * deFloatSin(stepAngle), 0.0f, 1.0f);
554                 vertices.push_back(vertex);
555                 indices.push_back(2);
556             }
557             else
558             {
559                 const Vertex4RGBA vertex = {tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)),
560                                                       primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)),
561                                                       0.0f, 1.0f),
562                                             red};
563 
564                 vertices.push_back(vertex);
565                 indices.push_back(primitiveNdx + 2);
566             }
567         }
568         break;
569     }
570 
571     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
572         vertices.push_back(defaultVertex);
573 
574         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
575         {
576             indices.push_back(0);
577 
578             for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
579             {
580                 const Vertex4RGBA vertex = {
581                     tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX,
582                               originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
583                     red};
584 
585                 vertices.push_back(vertex);
586                 indices.push_back(primitiveNdx * 2 + vertexNdx + 1);
587             }
588 
589             indices.push_back(0);
590         }
591         break;
592 
593     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
594         vertices.push_back(defaultVertex);
595         indices.push_back(0);
596 
597         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
598         {
599             if (primitiveNdx == 0)
600             {
601                 Vertex4RGBA vertex = {tcu::Vec4(originX, originY, 0.0f, 1.0f), red};
602 
603                 vertices.push_back(vertex);
604                 indices.push_back(1);
605 
606                 vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
607                 vertices.push_back(vertex);
608                 indices.push_back(2);
609             }
610             else
611             {
612                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX,
613                                                       originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f,
614                                                       1.0f),
615                                             red};
616 
617                 vertices.push_back(vertex);
618                 indices.push_back(primitiveNdx + 2);
619             }
620         }
621 
622         indices.push_back(0);
623         break;
624 
625     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
626         vertices.push_back(defaultVertex);
627 
628         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
629         {
630             for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
631             {
632                 const Vertex4RGBA vertex = {
633                     tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX,
634                               originY + float((primitiveNdx * 3 + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
635                     red};
636 
637                 vertices.push_back(vertex);
638                 indices.push_back(primitiveNdx * 3 + vertexNdx + 1);
639                 indices.push_back(0);
640             }
641         }
642         break;
643 
644     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
645         vertices.push_back(defaultVertex);
646 
647         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
648         {
649             if (primitiveNdx == 0)
650             {
651                 for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
652                 {
653                     const Vertex4RGBA vertex = {tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX,
654                                                           originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
655                                                 red};
656 
657                     vertices.push_back(vertex);
658                     indices.push_back(vertexNdx + 1);
659                     indices.push_back(0);
660                 }
661             }
662             else
663             {
664                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX,
665                                                       originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f,
666                                                       1.0f),
667                                             red};
668 
669                 vertices.push_back(vertex);
670                 indices.push_back(primitiveNdx + 2 + 1);
671                 indices.push_back(0);
672             }
673         }
674         break;
675 
676     default:
677         DE_ASSERT(false);
678         break;
679     }
680 
681     vertexData = vertices;
682     indexData  = indices;
683 }
684 
685 #ifndef CTS_USES_VULKANSC
686 // PrimitiveRestartTest
687 
PrimitiveRestartTest(tcu::TestContext & testContext,const std::string & name,PipelineConstructionType pipelineConstructionType,VkPrimitiveTopology primitiveTopology,VkIndexType indexType,RestartType restartType)688 PrimitiveRestartTest::PrimitiveRestartTest(tcu::TestContext &testContext, const std::string &name,
689                                            PipelineConstructionType pipelineConstructionType,
690                                            VkPrimitiveTopology primitiveTopology, VkIndexType indexType,
691                                            RestartType restartType)
692 
693     : InputAssemblyTest(testContext, name, pipelineConstructionType, primitiveTopology, 10, true, indexType)
694     , m_restartType(restartType)
695 {
696     uint32_t restartPrimitives[] = {1, 5};
697 
698     if (restartType == RestartType::NORMAL)
699     {
700         m_restartPrimitives =
701             std::vector<uint32_t>(restartPrimitives, restartPrimitives + sizeof(restartPrimitives) / sizeof(uint32_t));
702     }
703     else if (restartType == RestartType::NONE)
704     {
705         m_restartPrimitives = std::vector<uint32_t>{};
706     }
707     else
708     {
709         uint32_t count = 1;
710         switch (primitiveTopology)
711         {
712         case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
713         case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
714         case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
715         case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
716             count = 2;
717             break;
718         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
719         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
720         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
721         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
722         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
723             count = 3;
724             break;
725         default:
726             break;
727         }
728         for (uint32_t i = 0; i < (uint32_t)m_primitiveCount; ++i)
729         {
730             if (i % count == count - 1)
731             {
732                 m_restartPrimitives.push_back(i);
733             }
734         }
735     }
736 }
737 
checkSupport(Context & context) const738 void PrimitiveRestartTest::checkSupport(Context &context) const
739 {
740     switch (m_primitiveTopology)
741     {
742     case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
743     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
744     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
745     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
746     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
747     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
748     {
749         context.requireDeviceFunctionality("VK_EXT_primitive_topology_list_restart");
750 
751         const auto &features = context.getPrimitiveTopologyListRestartFeaturesEXT();
752         if (!features.primitiveTopologyListRestart)
753             TCU_THROW(NotSupportedError, "Primitive topology list restart feature not supported");
754         if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && !features.primitiveTopologyPatchListRestart)
755             TCU_THROW(NotSupportedError, "Primitive topology patch list restart feature not supported");
756     }
757     break;
758 
759     default:
760         break;
761     }
762 
763     InputAssemblyTest::checkSupport(context);
764 }
765 
createBufferData(VkPrimitiveTopology topology,int primitiveCount,VkIndexType indexType,std::vector<uint32_t> & indexData,std::vector<Vertex4RGBA> & vertexData) const766 void PrimitiveRestartTest::createBufferData(VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType,
767                                             std::vector<uint32_t> &indexData,
768                                             std::vector<Vertex4RGBA> &vertexData) const
769 {
770     DE_ASSERT(primitiveCount > 0);
771     DE_UNREF(indexType);
772 
773     const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
774     const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
775     const float border              = 0.2f;
776     const float originX             = -1.0f + border;
777     const float originY             = -1.0f + border;
778     const Vertex4RGBA defaultVertex = {tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green};
779     float primitiveSizeY            = (2.0f - 2.0f * border);
780     float primitiveSizeX;
781     bool primitiveStart = true;
782     std::vector<uint32_t> indices;
783     std::vector<Vertex4RGBA> vertices;
784 
785     // Calculate primitive size
786     switch (topology)
787     {
788     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
789         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
790         break;
791 
792     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
793     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
794     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
795     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
796         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
797         break;
798 
799     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
800     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
801     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
802     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
803     case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
804         primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
805         break;
806 
807     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
808         primitiveSizeX = 1.0f - border;
809         primitiveSizeY = 1.0f - border;
810         break;
811 
812     default:
813         primitiveSizeX = 0.0f; // Garbage
814         DE_ASSERT(false);
815     }
816 
817     switch (topology)
818     {
819     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
820         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
821         {
822             if (isRestartPrimitive(primitiveNdx))
823             {
824                 indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
825                 primitiveStart = true;
826             }
827             else
828             {
829                 if (primitiveStart && m_restartType != RestartType::ALL)
830                 {
831                     const Vertex4RGBA vertex = {tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX,
832                                                           originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f,
833                                                           1.0f),
834                                                 red};
835 
836                     vertices.push_back(vertex);
837                     indices.push_back((uint32_t)vertices.size() - 1);
838 
839                     primitiveStart = false;
840                 }
841 
842                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX,
843                                                       originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f,
844                                                       1.0f),
845                                             red};
846 
847                 vertices.push_back(vertex);
848                 indices.push_back((uint32_t)vertices.size() - 1);
849             }
850         }
851         break;
852 
853     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
854     {
855         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
856         {
857             if (isRestartPrimitive(primitiveNdx))
858             {
859                 indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
860                 primitiveStart = true;
861             }
862             else
863             {
864                 if (primitiveStart && m_restartType != RestartType::ALL)
865                 {
866                     for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
867                     {
868                         const Vertex4RGBA vertex = {
869                             tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX,
870                                       originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
871                             red};
872 
873                         vertices.push_back(vertex);
874                         indices.push_back((uint32_t)vertices.size() - 1);
875                     }
876 
877                     primitiveStart = false;
878                 }
879                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX,
880                                                       originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f,
881                                                       1.0f),
882                                             red};
883 
884                 vertices.push_back(vertex);
885                 indices.push_back((uint32_t)vertices.size() - 1);
886             }
887         }
888         break;
889     }
890 
891     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
892     {
893         const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
894 
895         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
896         {
897             if (isRestartPrimitive(primitiveNdx))
898             {
899                 indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
900                 primitiveStart = true;
901             }
902             else
903             {
904                 if (primitiveStart && m_restartType != RestartType::ALL)
905                 {
906                     Vertex4RGBA vertex = {tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), red};
907 
908                     vertices.push_back(vertex);
909                     indices.push_back((uint32_t)vertices.size() - 1);
910 
911                     vertex.position =
912                         tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx)),
913                                   primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx)), 0.0f, 1.0f);
914                     vertices.push_back(vertex);
915                     indices.push_back((uint32_t)vertices.size() - 1);
916 
917                     primitiveStart = false;
918                 }
919 
920                 const Vertex4RGBA vertex = {tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)),
921                                                       primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)),
922                                                       0.0f, 1.0f),
923                                             red};
924 
925                 vertices.push_back(vertex);
926                 indices.push_back((uint32_t)vertices.size() - 1);
927             }
928         }
929         break;
930     }
931 
932     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
933         vertices.push_back(defaultVertex);
934 
935         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
936         {
937             if (isRestartPrimitive(primitiveNdx))
938             {
939                 indices.push_back(0);
940                 indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
941                 primitiveStart = true;
942             }
943             else
944             {
945                 if (primitiveStart && m_restartType != RestartType::ALL)
946                 {
947                     indices.push_back(0);
948 
949                     const Vertex4RGBA vertex = {tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX,
950                                                           originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f,
951                                                           1.0f),
952                                                 red};
953 
954                     vertices.push_back(vertex);
955                     indices.push_back((uint32_t)vertices.size() - 1);
956 
957                     primitiveStart = false;
958                 }
959 
960                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX,
961                                                       originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f,
962                                                       1.0f),
963                                             red};
964 
965                 vertices.push_back(vertex);
966                 indices.push_back((uint32_t)vertices.size() - 1);
967             }
968         }
969 
970         indices.push_back(0);
971         break;
972 
973     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
974         vertices.push_back(defaultVertex);
975 
976         for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
977         {
978             if (isRestartPrimitive(primitiveNdx))
979             {
980                 indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
981                 primitiveStart = true;
982             }
983             else
984             {
985                 if (primitiveStart && m_restartType != RestartType::ALL)
986                 {
987                     for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
988                     {
989                         const Vertex4RGBA vertex = {
990                             tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX,
991                                       originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
992                             red};
993 
994                         vertices.push_back(vertex);
995                         indices.push_back((uint32_t)vertices.size() - 1);
996                         indices.push_back(0);
997                     }
998 
999                     primitiveStart = false;
1000                 }
1001 
1002                 const Vertex4RGBA vertex = {tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX,
1003                                                       originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f,
1004                                                       1.0f),
1005                                             red};
1006 
1007                 vertices.push_back(vertex);
1008                 indices.push_back((uint32_t)vertices.size() - 1);
1009                 indices.push_back(0);
1010             }
1011         }
1012         break;
1013 
1014     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1015         createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 1, indexType, indices,
1016                              vertices, std::vector<uint32_t>());
1017         break;
1018 
1019     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1020         createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 2, indexType, indices,
1021                              vertices, std::vector<uint32_t>());
1022         break;
1023 
1024     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1025     {
1026         std::vector<uint32_t> adjacencies = {0, 3};
1027 
1028         createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 4, indexType, indices,
1029                              vertices, adjacencies);
1030     }
1031     break;
1032 
1033     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1034     case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1035         createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 3, indexType, indices,
1036                              vertices, std::vector<uint32_t>());
1037         break;
1038 
1039     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1040     {
1041         std::vector<uint32_t> adjacencies = {1, 3, 5};
1042 
1043         createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 6, indexType, indices,
1044                              vertices, adjacencies);
1045     }
1046     break;
1047 
1048     default:
1049         DE_ASSERT(false);
1050         break;
1051     }
1052 
1053     vertexData = vertices;
1054     indexData  = indices;
1055 }
1056 
createListPrimitives(int primitiveCount,float originX,float originY,float primitiveSizeX,float primitiveSizeY,int verticesPerPrimitive,VkIndexType indexType,std::vector<uint32_t> & indexData,std::vector<Vertex4RGBA> & vertexData,std::vector<uint32_t> adjacencies) const1057 void PrimitiveRestartTest::createListPrimitives(int primitiveCount, float originX, float originY, float primitiveSizeX,
1058                                                 float primitiveSizeY, int verticesPerPrimitive, VkIndexType indexType,
1059                                                 std::vector<uint32_t> &indexData, std::vector<Vertex4RGBA> &vertexData,
1060                                                 std::vector<uint32_t> adjacencies) const
1061 {
1062     const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
1063     const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
1064     // Tells which vertex of a primitive is used as a restart index.
1065     // This is decreased each time a restart primitive is used.
1066     int restartVertexIndex = verticesPerPrimitive - 1;
1067 
1068     for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
1069     {
1070         uint32_t nonAdjacentVertexNdx = 0;
1071 
1072         for (int vertexNdx = 0; vertexNdx < verticesPerPrimitive; vertexNdx++)
1073         {
1074             if (isRestartPrimitive(primitiveNdx) && vertexNdx == restartVertexIndex)
1075             {
1076                 indexData.push_back(InputAssemblyTest::getRestartIndex(indexType));
1077 
1078                 restartVertexIndex--;
1079                 if (restartVertexIndex < 0)
1080                     restartVertexIndex = verticesPerPrimitive - 1;
1081 
1082                 break;
1083             }
1084 
1085             if (std::find(adjacencies.begin(), adjacencies.end(), vertexNdx) != adjacencies.end())
1086             {
1087                 // This is an adjacency vertex index. Add a green vertex that should never end up to the framebuffer.
1088                 const Vertex4RGBA vertex = {tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), green};
1089                 vertexData.push_back(vertex);
1090                 indexData.push_back((uint32_t)vertexData.size() - 1);
1091                 continue;
1092             }
1093 
1094             const Vertex4RGBA vertex = {
1095                 tcu::Vec4(originX + float((primitiveNdx + nonAdjacentVertexNdx) / 2) * primitiveSizeX,
1096                           originY + float((primitiveNdx + nonAdjacentVertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
1097                 red};
1098 
1099             vertexData.push_back(vertex);
1100             indexData.push_back((uint32_t)vertexData.size() - 1);
1101             nonAdjacentVertexNdx++;
1102         }
1103     }
1104 }
1105 
isRestartPrimitive(int primitiveIndex) const1106 bool PrimitiveRestartTest::isRestartPrimitive(int primitiveIndex) const
1107 {
1108     return std::find(m_restartPrimitives.begin(), m_restartPrimitives.end(), primitiveIndex) !=
1109            m_restartPrimitives.end();
1110 }
1111 #endif // CTS_USES_VULKANSC
1112 
1113 // InputAssemblyInstance
1114 
InputAssemblyInstance(Context & context,PipelineConstructionType pipelineConstructionType,VkPrimitiveTopology primitiveTopology,bool testPrimitiveRestart,VkIndexType indexType,const std::vector<uint32_t> & indexBufferData,const std::vector<Vertex4RGBA> & vertexBufferData)1115 InputAssemblyInstance::InputAssemblyInstance(Context &context, PipelineConstructionType pipelineConstructionType,
1116                                              VkPrimitiveTopology primitiveTopology, bool testPrimitiveRestart,
1117                                              VkIndexType indexType, const std::vector<uint32_t> &indexBufferData,
1118                                              const std::vector<Vertex4RGBA> &vertexBufferData)
1119 
1120     : vkt::TestInstance(context)
1121     , m_primitiveTopology(primitiveTopology)
1122     , m_primitiveRestartEnable(testPrimitiveRestart)
1123     , m_indexType(indexType)
1124     , m_vertices(vertexBufferData)
1125     , m_indices(indexBufferData)
1126     , m_renderSize((primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) ? tcu::UVec2(32, 32) : tcu::UVec2(64, 16))
1127     , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
1128     , m_graphicsPipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(),
1129                          context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
1130 {
1131     const DeviceInterface &vk       = context.getDeviceInterface();
1132     const VkDevice vkDevice         = context.getDevice();
1133     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1134     SimpleAllocator memAlloc(
1135         vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
1136     const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1137                                                      VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
1138     const bool patchList                          = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
1139 
1140     // Create color image
1141     {
1142         const VkImageCreateInfo colorImageParams = {
1143             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                   // VkStructureType sType;
1144             DE_NULL,                                                               // const void* pNext;
1145             0u,                                                                    // VkImageCreateFlags flags;
1146             VK_IMAGE_TYPE_2D,                                                      // VkImageType imageType;
1147             m_colorFormat,                                                         // VkFormat format;
1148             {m_renderSize.x(), m_renderSize.y(), 1u},                              // VkExtent3D extent;
1149             1u,                                                                    // uint32_t mipLevels;
1150             1u,                                                                    // uint32_t arrayLayers;
1151             VK_SAMPLE_COUNT_1_BIT,                                                 // VkSampleCountFlagBits samples;
1152             VK_IMAGE_TILING_OPTIMAL,                                               // VkImageTiling tiling;
1153             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
1154             VK_SHARING_MODE_EXCLUSIVE,                                             // VkSharingMode sharingMode;
1155             1u,                                                                    // uint32_t queueFamilyIndexCount;
1156             &queueFamilyIndex,        // const uint32_t* pQueueFamilyIndices;
1157             VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
1158         };
1159 
1160         m_colorImageCreateInfo = colorImageParams;
1161         m_colorImage           = createImage(vk, vkDevice, &m_colorImageCreateInfo);
1162 
1163         // Allocate and bind color image memory
1164         m_colorImageAlloc =
1165             memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
1166         VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(),
1167                                     m_colorImageAlloc->getOffset()));
1168     }
1169 
1170     // Create color attachment view
1171     {
1172         const VkImageViewCreateInfo colorAttachmentViewParams = {
1173             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,    // VkStructureType sType;
1174             DE_NULL,                                     // const void* pNext;
1175             0u,                                          // VkImageViewCreateFlags flags;
1176             *m_colorImage,                               // VkImage image;
1177             VK_IMAGE_VIEW_TYPE_2D,                       // VkImageViewType viewType;
1178             m_colorFormat,                               // VkFormat format;
1179             componentMappingRGBA,                        // VkComponentMapping components;
1180             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1181         };
1182 
1183         m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
1184     }
1185 
1186     // Create render pass
1187     m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, vkDevice, m_colorFormat);
1188 
1189     // Create framebuffer
1190     {
1191         const VkFramebufferCreateInfo framebufferParams = {
1192             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1193             DE_NULL,                                   // const void* pNext;
1194             0u,                                        // VkFramebufferCreateFlags flags;
1195             *m_renderPass,                             // VkRenderPass renderPass;
1196             1u,                                        // uint32_t attachmentCount;
1197             &m_colorAttachmentView.get(),              // const VkImageView* pAttachments;
1198             (uint32_t)m_renderSize.x(),                // uint32_t width;
1199             (uint32_t)m_renderSize.y(),                // uint32_t height;
1200             1u                                         // uint32_t layers;
1201         };
1202 
1203         m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
1204     }
1205 
1206     // Create pipeline layout
1207     {
1208         const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
1209             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1210             DE_NULL,                                       // const void* pNext;
1211             0u,                                            // VkPipelineLayoutCreateFlags flags;
1212             0u,                                            // uint32_t setLayoutCount;
1213             DE_NULL,                                       // const VkDescriptorSetLayout* pSetLayouts;
1214             0u,                                            // uint32_t pushConstantRangeCount;
1215             DE_NULL                                        // const VkPushConstantRange* pPushConstantRanges;
1216         };
1217 
1218         m_pipelineLayout = PipelineLayoutWrapper(pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
1219     }
1220 
1221     m_vertexShaderModule   = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
1222     m_fragmentShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
1223 
1224     if (patchList)
1225     {
1226         m_tcsShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_tcs"), 0);
1227         m_tesShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_tes"), 0);
1228     }
1229 
1230     // Create pipeline
1231     {
1232         const VkVertexInputBindingDescription vertexInputBindingDescription = {
1233             0u,                         // uint32_t binding;
1234             sizeof(Vertex4RGBA),        // uint32_t stride;
1235             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
1236         };
1237 
1238         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
1239             {
1240                 0u,                            // uint32_t location;
1241                 0u,                            // uint32_t binding;
1242                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1243                 0u                             // uint32_t offset;
1244             },
1245             {
1246                 1u,                            // uint32_t location;
1247                 0u,                            // uint32_t binding;
1248                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1249                 offsetof(Vertex4RGBA, color),  // uint32_t offset;
1250             }};
1251 
1252         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
1253             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1254             DE_NULL,                                                   // const void* pNext;
1255             0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
1256             1u,                                                        // uint32_t vertexBindingDescriptionCount;
1257             &vertexInputBindingDescription,  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1258             2u,                              // uint32_t vertexAttributeDescriptionCount;
1259             vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1260         };
1261 
1262         const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = {
1263             VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
1264             DE_NULL,                                                     // const void* pNext;
1265             0u,                      // VkPipelineInputAssemblyStateCreateFlags flags;
1266             m_primitiveTopology,     // VkPrimitiveTopology topology;
1267             m_primitiveRestartEnable // VkBool32 primitiveRestartEnable;
1268         };
1269 
1270         const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
1271         const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
1272 
1273         const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1274             false,                                                // VkBool32 blendEnable;
1275             VK_BLEND_FACTOR_ONE,                                  // VkBlendFactor srcColorBlendFactor;
1276             VK_BLEND_FACTOR_ZERO,                                 // VkBlendFactor dstColorBlendFactor;
1277             VK_BLEND_OP_ADD,                                      // VkBlendOp colorBlendOp;
1278             VK_BLEND_FACTOR_ONE,                                  // VkBlendFactor srcAlphaBlendFactor;
1279             VK_BLEND_FACTOR_ZERO,                                 // VkBlendFactor dstAlphaBlendFactor;
1280             VK_BLEND_OP_ADD,                                      // VkBlendOp alphaBlendOp;
1281             VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
1282                 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
1283 
1284         const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
1285             VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1286             DE_NULL,                                                  // const void* pNext;
1287             0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
1288             false,                                                    // VkBool32 logicOpEnable;
1289             VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1290             1u,                                                       // uint32_t attachmentCount;
1291             &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1292             {0.0f, 0.0f, 0.0f, 0.0f}    // float blendConstants[4];
1293         };
1294 
1295         VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = {
1296             VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1297             DE_NULL,                                                    // const void* pNext;
1298             0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
1299             false,                                                      // VkBool32 depthTestEnable;
1300             false,                                                      // VkBool32 depthWriteEnable;
1301             VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
1302             false,                                                      // VkBool32 depthBoundsTestEnable;
1303             false,                                                      // VkBool32 stencilTestEnable;
1304             // VkStencilOpState front;
1305             {
1306                 VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1307                 VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1308                 VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1309                 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1310                 0u,                  // uint32_t compareMask;
1311                 0u,                  // uint32_t writeMask;
1312                 0u,                  // uint32_t reference;
1313             },
1314             // VkStencilOpState back;
1315             {
1316                 VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1317                 VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1318                 VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1319                 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1320                 0u,                  // uint32_t compareMask;
1321                 0u,                  // uint32_t writeMask;
1322                 0u,                  // uint32_t reference;
1323             },
1324             0.0f, // float minDepthBounds;
1325             1.0f  // float maxDepthBounds;
1326         };
1327 
1328         m_graphicsPipeline.setDefaultRasterizationState()
1329             .setDefaultMultisampleState()
1330             .setupVertexInputState(&vertexInputStateParams, &inputAssemblyStateParams)
1331             .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, *m_renderPass, 0u,
1332                                               m_vertexShaderModule, DE_NULL, m_tcsShaderModule, m_tesShaderModule)
1333             .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, m_fragmentShaderModule,
1334                                       &depthStencilStateParams)
1335             .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1336             .setMonolithicPipelineLayout(m_pipelineLayout)
1337             .buildPipeline();
1338     }
1339 
1340     // Create vertex and index buffer
1341     {
1342         const VkBufferCreateInfo indexBufferParams = {
1343             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1344             DE_NULL,                              // const void* pNext;
1345             0u,                                   // VkBufferCreateFlags flags;
1346             m_indices.size() * sizeof(uint32_t),  // VkDeviceSize size;
1347             VK_BUFFER_USAGE_INDEX_BUFFER_BIT,     // VkBufferUsageFlags usage;
1348             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1349             1u,                                   // uint32_t queueFamilyIndexCount;
1350             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
1351         };
1352 
1353         const VkBufferCreateInfo vertexBufferParams = {
1354             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,    // VkStructureType sType;
1355             DE_NULL,                                 // const void* pNext;
1356             0u,                                      // VkBufferCreateFlags flags;
1357             m_vertices.size() * sizeof(Vertex4RGBA), // VkDeviceSize size;
1358             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,       // VkBufferUsageFlags usage;
1359             VK_SHARING_MODE_EXCLUSIVE,               // VkSharingMode sharingMode;
1360             1u,                                      // uint32_t queueFamilyIndexCount;
1361             &queueFamilyIndex                        // const uint32_t* pQueueFamilyIndices;
1362         };
1363 
1364         m_indexBuffer      = createBuffer(vk, vkDevice, &indexBufferParams);
1365         m_indexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_indexBuffer),
1366                                                MemoryRequirement::HostVisible);
1367 
1368         VK_CHECK(vk.bindBufferMemory(vkDevice, *m_indexBuffer, m_indexBufferAlloc->getMemory(),
1369                                      m_indexBufferAlloc->getOffset()));
1370 
1371         m_vertexBuffer      = createBuffer(vk, vkDevice, &vertexBufferParams);
1372         m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer),
1373                                                 MemoryRequirement::HostVisible);
1374 
1375         VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(),
1376                                      m_vertexBufferAlloc->getOffset()));
1377 
1378         // Load vertices into index buffer
1379         if (m_indexType == VK_INDEX_TYPE_UINT32)
1380         {
1381             deMemcpy(m_indexBufferAlloc->getHostPtr(), m_indices.data(), m_indices.size() * sizeof(uint32_t));
1382         }
1383         else if (m_indexType == VK_INDEX_TYPE_UINT8_EXT)
1384         {
1385             uploadIndexBufferData8((uint8_t *)m_indexBufferAlloc->getHostPtr(), m_indices);
1386         }
1387         else // m_indexType == VK_INDEX_TYPE_UINT16
1388         {
1389             uploadIndexBufferData16((uint16_t *)m_indexBufferAlloc->getHostPtr(), m_indices);
1390         }
1391 
1392         // Load vertices into vertex buffer
1393         deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
1394 
1395         flushAlloc(vk, vkDevice, *m_indexBufferAlloc);
1396         flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
1397     }
1398 
1399     // Create command pool
1400     m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1401 
1402     // Create command buffer
1403     {
1404         const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
1405 
1406         const VkImageMemoryBarrier attachmentLayoutBarrier = {
1407             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,      // VkStructureType sType;
1408             DE_NULL,                                     // const void* pNext;
1409             0u,                                          // VkAccessFlags srcAccessMask;
1410             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,        // VkAccessFlags dstAccessMask;
1411             VK_IMAGE_LAYOUT_UNDEFINED,                   // VkImageLayout oldLayout;
1412             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,    // VkImageLayout newLayout;
1413             VK_QUEUE_FAMILY_IGNORED,                     // uint32_t srcQueueFamilyIndex;
1414             VK_QUEUE_FAMILY_IGNORED,                     // uint32_t dstQueueFamilyIndex;
1415             *m_colorImage,                               // VkImage image;
1416             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1417         };
1418 
1419         m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1420 
1421         beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1422 
1423         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1424                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u,
1425                               DE_NULL, 1u, &attachmentLayoutBarrier);
1426 
1427         m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()),
1428                            attachmentClearValue);
1429 
1430         const VkDeviceSize vertexBufferOffset = 0;
1431 
1432         m_graphicsPipeline.bind(*m_cmdBuffer);
1433         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
1434         vk.cmdBindIndexBuffer(*m_cmdBuffer, *m_indexBuffer, 0, m_indexType);
1435         vk.cmdDrawIndexed(*m_cmdBuffer, (uint32_t)m_indices.size(), 1, 0, 0, 0);
1436 
1437         m_renderPass.end(vk, *m_cmdBuffer);
1438         endCommandBuffer(vk, *m_cmdBuffer);
1439     }
1440 }
1441 
~InputAssemblyInstance(void)1442 InputAssemblyInstance::~InputAssemblyInstance(void)
1443 {
1444 }
1445 
iterate(void)1446 tcu::TestStatus InputAssemblyInstance::iterate(void)
1447 {
1448     const DeviceInterface &vk = m_context.getDeviceInterface();
1449     const VkDevice vkDevice   = m_context.getDevice();
1450     const VkQueue queue       = m_context.getUniversalQueue();
1451 
1452     submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1453 
1454     return verifyImage();
1455 }
1456 
verifyImage(void)1457 tcu::TestStatus InputAssemblyInstance::verifyImage(void)
1458 {
1459     const tcu::TextureFormat tcuColorFormat   = mapVkFormat(m_colorFormat);
1460     const tcu::TextureFormat tcuStencilFormat = tcu::TextureFormat();
1461     const ColorVertexShader vertexShader;
1462     const ColorFragmentShader fragmentShader(tcuColorFormat, tcuStencilFormat);
1463     const rr::Program program(&vertexShader, &fragmentShader);
1464     ReferenceRenderer refRenderer(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
1465     bool compareOk = false;
1466 
1467     // Render reference image
1468     {
1469         // The reference for tessellated patches are drawn using ordinary triangles.
1470         const rr::PrimitiveType topology = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ?
1471                                                rr::PrimitiveType::PRIMITIVETYPE_TRIANGLES :
1472                                                mapVkPrimitiveTopology(m_primitiveTopology);
1473         rr::RenderState renderState(refRenderer.getViewportState(),
1474                                     m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1475 
1476         if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1477             renderState.point.pointSize = 3.0f;
1478 
1479         if (m_primitiveRestartEnable)
1480         {
1481             std::vector<uint32_t> indicesRange;
1482 
1483             for (size_t indexNdx = 0; indexNdx < m_indices.size(); indexNdx++)
1484             {
1485                 const bool isRestart = InputAssemblyTest::isRestartIndex(m_indexType, m_indices[indexNdx]);
1486 
1487                 if (!isRestart)
1488                     indicesRange.push_back(m_indices[indexNdx]);
1489 
1490                 if (isRestart || indexNdx == (m_indices.size() - 1))
1491                 {
1492                     // Draw the range of indices found so far
1493 
1494                     std::vector<Vertex4RGBA> nonIndexedVertices;
1495                     for (size_t i = 0; i < indicesRange.size(); i++)
1496                         nonIndexedVertices.push_back(m_vertices[indicesRange[i]]);
1497 
1498                     refRenderer.draw(renderState, topology, nonIndexedVertices);
1499                     indicesRange.clear();
1500                 }
1501             }
1502         }
1503         else
1504         {
1505             std::vector<Vertex4RGBA> nonIndexedVertices;
1506             for (size_t i = 0; i < m_indices.size(); i++)
1507                 nonIndexedVertices.push_back(m_vertices[m_indices[i]]);
1508 
1509             refRenderer.draw(renderState, topology, nonIndexedVertices);
1510         }
1511     }
1512 
1513     // Compare result with reference image
1514     {
1515         const DeviceInterface &vk       = m_context.getDeviceInterface();
1516         const VkDevice vkDevice         = m_context.getDevice();
1517         const VkQueue queue             = m_context.getUniversalQueue();
1518         const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1519         SimpleAllocator allocator(
1520             vk, vkDevice,
1521             getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
1522         de::UniquePtr<tcu::TextureLevel> result(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator,
1523                                                                     *m_colorImage, m_colorFormat, m_renderSize)
1524                                                     .release());
1525 
1526         compareOk = tcu::intThresholdPositionDeviationCompare(
1527             m_context.getTestContext().getLog(), "IntImageCompare", "Image comparison", refRenderer.getAccess(),
1528             result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT);
1529     }
1530 
1531     if (compareOk)
1532         return tcu::TestStatus::pass("Result image matches reference");
1533     else
1534         return tcu::TestStatus::fail("Image mismatch");
1535 }
1536 
uploadIndexBufferData16(uint16_t * destPtr,const std::vector<uint32_t> & indexBufferData)1537 void InputAssemblyInstance::uploadIndexBufferData16(uint16_t *destPtr, const std::vector<uint32_t> &indexBufferData)
1538 {
1539     for (size_t i = 0; i < indexBufferData.size(); i++)
1540     {
1541         DE_ASSERT(indexBufferData[i] <= 0xFFFF);
1542         destPtr[i] = (uint16_t)indexBufferData[i];
1543     }
1544 }
1545 
uploadIndexBufferData8(uint8_t * destPtr,const std::vector<uint32_t> & indexBufferData)1546 void InputAssemblyInstance::uploadIndexBufferData8(uint8_t *destPtr, const std::vector<uint32_t> &indexBufferData)
1547 {
1548     for (size_t i = 0; i < indexBufferData.size(); i++)
1549     {
1550         DE_ASSERT(indexBufferData[i] <= 0xFF);
1551         destPtr[i] = (uint8_t)indexBufferData[i];
1552     }
1553 }
1554 
1555 // Utilities for test names
1556 
getPrimitiveTopologyCaseName(VkPrimitiveTopology topology)1557 std::string getPrimitiveTopologyCaseName(VkPrimitiveTopology topology)
1558 {
1559     const std::string fullName = getPrimitiveTopologyName(topology);
1560 
1561     DE_ASSERT(de::beginsWith(fullName, "VK_PRIMITIVE_TOPOLOGY_"));
1562 
1563     return de::toLower(fullName.substr(22));
1564 }
1565 
createPrimitiveTopologyTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1566 de::MovePtr<tcu::TestCaseGroup> createPrimitiveTopologyTests(tcu::TestContext &testCtx,
1567                                                              PipelineConstructionType pipelineConstructionType)
1568 {
1569     de::MovePtr<tcu::TestCaseGroup> primitiveTopologyTests(new tcu::TestCaseGroup(testCtx, "primitive_topology"));
1570 
1571     de::MovePtr<tcu::TestCaseGroup> indexUint16Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint16"));
1572     de::MovePtr<tcu::TestCaseGroup> indexUint32Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint32"));
1573     de::MovePtr<tcu::TestCaseGroup> indexUint8Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint8"));
1574 
1575     for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(InputAssemblyTest::s_primitiveTopologies); topologyNdx++)
1576     {
1577         const VkPrimitiveTopology topology = InputAssemblyTest::s_primitiveTopologies[topologyNdx];
1578 
1579         indexUint16Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology),
1580                                                              pipelineConstructionType, topology, VK_INDEX_TYPE_UINT16));
1581 
1582         indexUint32Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology),
1583                                                              pipelineConstructionType, topology, VK_INDEX_TYPE_UINT32));
1584 
1585         indexUint8Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology),
1586                                                             pipelineConstructionType, topology,
1587                                                             VK_INDEX_TYPE_UINT8_EXT));
1588     }
1589 
1590     primitiveTopologyTests->addChild(indexUint16Tests.release());
1591     primitiveTopologyTests->addChild(indexUint32Tests.release());
1592     primitiveTopologyTests->addChild(indexUint8Tests.release());
1593 
1594     return primitiveTopologyTests;
1595 }
1596 
1597 #ifndef CTS_USES_VULKANSC
createPrimitiveRestartTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1598 de::MovePtr<tcu::TestCaseGroup> createPrimitiveRestartTests(tcu::TestContext &testCtx,
1599                                                             PipelineConstructionType pipelineConstructionType)
1600 {
1601     const VkPrimitiveTopology primitiveRestartTopologies[] = {
1602         VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
1603         VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
1604 
1605         // Supported with VK_EXT_primitive_topology_list_restart
1606         VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
1607         VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1608         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST};
1609 
1610     de::MovePtr<tcu::TestCaseGroup> primitiveRestartTests(new tcu::TestCaseGroup(testCtx, "primitive_restart"));
1611 
1612     de::MovePtr<tcu::TestCaseGroup> indexUint16Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint16"));
1613     de::MovePtr<tcu::TestCaseGroup> indexUint32Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint32"));
1614     de::MovePtr<tcu::TestCaseGroup> indexUint8Tests(new tcu::TestCaseGroup(testCtx, "index_type_uint8"));
1615 
1616     constexpr struct RestartTest
1617     {
1618         RestartType type;
1619         const char *name;
1620     } restartTypes[] = {
1621         {
1622             RestartType::NORMAL,
1623             "",
1624         },
1625         {
1626             RestartType::NONE,
1627             "no_restart_",
1628         },
1629         {RestartType::ALL, "restart_all_"},
1630     };
1631 
1632     for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(primitiveRestartTopologies); topologyNdx++)
1633     {
1634         const VkPrimitiveTopology topology = primitiveRestartTopologies[topologyNdx];
1635 
1636         for (int useRestartNdx = 0; useRestartNdx < DE_LENGTH_OF_ARRAY(restartTypes); useRestartNdx++)
1637         {
1638             if (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST && restartTypes[useRestartNdx].type == RestartType::ALL)
1639             {
1640                 continue;
1641             }
1642             indexUint16Tests->addChild(new PrimitiveRestartTest(
1643                 testCtx, restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1644                 pipelineConstructionType, topology, VK_INDEX_TYPE_UINT16, restartTypes[useRestartNdx].type));
1645 
1646             indexUint32Tests->addChild(new PrimitiveRestartTest(
1647                 testCtx, restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1648                 pipelineConstructionType, topology, VK_INDEX_TYPE_UINT32, restartTypes[useRestartNdx].type));
1649 
1650             indexUint8Tests->addChild(new PrimitiveRestartTest(
1651                 testCtx, restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1652                 pipelineConstructionType, topology, VK_INDEX_TYPE_UINT8_EXT, restartTypes[useRestartNdx].type));
1653         }
1654     }
1655 
1656     // Tests that have primitive restart disabled, but have indices with restart index value.
1657     if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1658     {
1659         struct
1660         {
1661             std::string name;
1662             std::vector<std::string> requirements;
1663         } tests[] = {
1664             {"line_list", {"VK_EXT_primitive_topology_list_restart"}},
1665             {"line_list_with_adjacency", {"Features.geometryShader", "VK_EXT_primitive_topology_list_restart"}},
1666             {"line_strip", {}},
1667             {"line_strip_with_adjacency", {"Features.geometryShader"}},
1668             {"patch_list", {"VK_EXT_primitive_topology_list_restart", "Features.tessellationShader"}},
1669             {"point_list", {"VK_EXT_primitive_topology_list_restart"}},
1670             {"triangle_fan", {}},
1671             {"triangle_list", {"VK_EXT_primitive_topology_list_restart"}},
1672             {"triangle_list_with_adjacency", {"Features.geometryShader", "VK_EXT_primitive_topology_list_restart"}},
1673             {"triangle_strip", {}},
1674             {"triangle_strip_with_adjacency", {"Features.geometryShader"}}};
1675 
1676         const std::string dataDir = "pipeline/input_assembly/primitive_restart";
1677 
1678         for (auto &test : tests)
1679         {
1680             std::string testName = "restart_disabled_" + test.name;
1681             indexUint16Tests->addChild(cts_amber::createAmberTestCase(testCtx, testName.c_str(), dataDir.c_str(),
1682                                                                       testName + "_uint16.amber", test.requirements));
1683             test.requirements.push_back("IndexTypeUint8Features.indexTypeUint8");
1684             indexUint8Tests->addChild(cts_amber::createAmberTestCase(testCtx, testName.c_str(), dataDir.c_str(),
1685                                                                      testName + "_uint8.amber", test.requirements));
1686         }
1687     }
1688 
1689     primitiveRestartTests->addChild(indexUint16Tests.release());
1690     primitiveRestartTests->addChild(indexUint32Tests.release());
1691     primitiveRestartTests->addChild(indexUint8Tests.release());
1692 
1693     return primitiveRestartTests;
1694 }
1695 #endif // CTS_USES_VULKANSC
1696 
1697 } // namespace
1698 
createInputAssemblyTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1699 tcu::TestCaseGroup *createInputAssemblyTests(tcu::TestContext &testCtx,
1700                                              PipelineConstructionType pipelineConstructionType)
1701 {
1702     de::MovePtr<tcu::TestCaseGroup> inputAssemblyTests(new tcu::TestCaseGroup(testCtx, "input_assembly"));
1703 
1704     inputAssemblyTests->addChild(createPrimitiveTopologyTests(testCtx, pipelineConstructionType).release());
1705 #ifndef CTS_USES_VULKANSC
1706     inputAssemblyTests->addChild(createPrimitiveRestartTests(testCtx, pipelineConstructionType).release());
1707 #endif // CTS_USES_VULKANSC
1708 
1709     return inputAssemblyTests.release();
1710 }
1711 
1712 } // namespace pipeline
1713 } // namespace vkt
1714