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