1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Vulkan Transform Feedback Simple Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktTransformFeedbackSimpleTests.hpp"
25 #include "vktTestGroupUtil.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 
29 #include "vkCmdUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 
36 #include "deUniquePtr.hpp"
37 #include "deRandom.hpp"
38 
39 #include "tcuTextureUtil.hpp"
40 #include "tcuVectorUtil.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuRGBA.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuCommandLine.hpp"
45 
46 #include <iostream>
47 #include <functional>
48 #include <set>
49 #include <algorithm>
50 #include <limits>
51 #include <memory>
52 #include <map>
53 
54 namespace vkt
55 {
56 namespace TransformFeedback
57 {
58 namespace
59 {
60 using namespace vk;
61 using de::MovePtr;
62 using de::SharedPtr;
63 using de::UniquePtr;
64 
65 #define VALIDATE_MINIMUM(A, B) \
66     if ((A) < (B))             \
67     TCU_FAIL(#A "==" + de::toString(A) + " which is less than required by specification (" + de::toString(B) + ")")
68 #define VALIDATE_BOOL(A)                      \
69     if (!((A) == VK_TRUE || (A) == VK_FALSE)) \
70     TCU_FAIL(#A " expected to be VK_TRUE or VK_FALSE. Received " + de::toString((uint64_t)(A)))
71 
72 const uint32_t INVOCATION_COUNT = 8u;
73 const std::vector<uint32_t> LINES_LIST{2, 6, 3};
74 const std::vector<uint32_t> TRIANGLES_LIST{3, 8, 6, 5, 4};
75 constexpr auto kVec4Components = 4u;
76 
77 enum TestType
78 {
79     TEST_TYPE_BASIC,
80     TEST_TYPE_RESUME,
81     TEST_TYPE_STREAMS,
82     TEST_TYPE_XFB_POINTSIZE,
83     TEST_TYPE_XFB_CLIPDISTANCE,
84     TEST_TYPE_XFB_CULLDISTANCE,
85     TEST_TYPE_XFB_CLIP_AND_CULL,
86     TEST_TYPE_WINDING,
87     TEST_TYPE_STREAMS_POINTSIZE,
88     TEST_TYPE_STREAMS_CLIPDISTANCE,
89     TEST_TYPE_STREAMS_CULLDISTANCE,
90     TEST_TYPE_MULTISTREAMS,
91     TEST_TYPE_MULTISTREAMS_SAME_LOCATION,
92     TEST_TYPE_DRAW_INDIRECT,
93     TEST_TYPE_DRAW_INDIRECT_MULTIVIEW,
94     TEST_TYPE_BACKWARD_DEPENDENCY,
95     TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT,
96     TEST_TYPE_QUERY_GET,
97     TEST_TYPE_QUERY_COPY,
98     TEST_TYPE_QUERY_COPY_STRIDE_ZERO,
99     TEST_TYPE_QUERY_RESET,
100     TEST_TYPE_MULTIQUERY,
101     TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX,
102     TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY,
103     TEST_TYPE_DEPTH_CLIP_CONTROL_TESE,
104     TEST_TYPE_LINES_TRIANGLES,
105     TEST_TYPE_DRAW_OUTSIDE,
106     TEST_TYPE_HOLES_VERTEX,
107     TEST_TYPE_HOLES_GEOMETRY,
108     TEST_TYPE_MAX_OUTPUT_COMPONENTS,
109     TEST_TYPE_LAST
110 };
111 
112 enum StreamId0Mode
113 {
114     STREAM_ID_0_NORMAL              = 0,
115     STREAM_ID_0_BEGIN_QUERY_INDEXED = 1,
116     STREAM_ID_0_END_QUERY_INDEXED   = 2,
117 };
118 
119 struct TestParameters
120 {
121     const PipelineConstructionType pipelineConstructionType;
122 
123     TestType testType;
124     uint32_t bufferSize;
125     uint32_t partCount;
126     uint32_t streamId;
127     uint32_t pointSize;
128     uint32_t vertexStride;
129     StreamId0Mode streamId0Mode;
130     bool query64bits;
131     bool noOffsetArray;
132     bool requireRastStreamSelect;
133     bool omitShaderWrite;
134     bool useMaintenance5;
135     VkPrimitiveTopology primTopology;
136     bool queryResultWithAvailability;
137 
isPointsvkt::TransformFeedback::__anonb6d10ff70111::TestParameters138     bool isPoints(void) const
139     {
140         return (primTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
141     }
142 
usingTessvkt::TransformFeedback::__anonb6d10ff70111::TestParameters143     bool usingTess(void) const
144     {
145         return (primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
146     }
147 
requiresFullPipelinevkt::TransformFeedback::__anonb6d10ff70111::TestParameters148     bool requiresFullPipeline(void) const
149     {
150         return (testType == TEST_TYPE_STREAMS || testType == TEST_TYPE_STREAMS_POINTSIZE ||
151                 testType == TEST_TYPE_STREAMS_CULLDISTANCE || testType == TEST_TYPE_STREAMS_CLIPDISTANCE ||
152                 (testType == TEST_TYPE_WINDING && primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST));
153     }
154 
usingGeomvkt::TransformFeedback::__anonb6d10ff70111::TestParameters155     bool usingGeom(void) const
156     {
157         static const std::set<TestType> nonFullPipelineTestTypesWithGeomShaders{
158             TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY,
159             TEST_TYPE_MULTISTREAMS,
160             TEST_TYPE_MULTISTREAMS_SAME_LOCATION,
161             TEST_TYPE_QUERY_GET,
162             TEST_TYPE_QUERY_COPY,
163             TEST_TYPE_QUERY_COPY_STRIDE_ZERO,
164             TEST_TYPE_QUERY_RESET,
165             TEST_TYPE_MULTIQUERY,
166             TEST_TYPE_LINES_TRIANGLES,
167         };
168 
169         const auto itr = nonFullPipelineTestTypesWithGeomShaders.find(testType);
170         return (itr != nonFullPipelineTestTypesWithGeomShaders.end() || requiresFullPipeline());
171     }
172 
usingTessGeomvkt::TransformFeedback::__anonb6d10ff70111::TestParameters173     bool usingTessGeom(void) const
174     {
175         return (usingTess() || usingGeom());
176     }
177 
178     // Returns true if we want to set PointSize in some shaders. Note some test types always need/want PointSize, independently of
179     // this value, as it's in the nature of the test.
pointSizeWantedvkt::TransformFeedback::__anonb6d10ff70111::TestParameters180     bool pointSizeWanted(void) const
181     {
182         return (pointSize > 0u);
183     }
184 };
185 
186 // Device helper: this is needed in some tests when we create custom devices.
187 class DeviceHelper
188 {
189 public:
~DeviceHelper()190     virtual ~DeviceHelper()
191     {
192     }
193     virtual const DeviceInterface &getDeviceInterface(void) const = 0;
194     virtual VkDevice getDevice(void) const                        = 0;
195     virtual uint32_t getQueueFamilyIndex(void) const              = 0;
196     virtual VkQueue getQueue(void) const                          = 0;
197     virtual Allocator &getAllocator(void) const                   = 0;
198 };
199 
200 // This one just reuses the default device from the context.
201 class ContextDeviceHelper : public DeviceHelper
202 {
203 public:
ContextDeviceHelper(Context & context)204     ContextDeviceHelper(Context &context)
205         : m_deviceInterface(context.getDeviceInterface())
206         , m_device(context.getDevice())
207         , m_queueFamilyIndex(context.getUniversalQueueFamilyIndex())
208         , m_queue(context.getUniversalQueue())
209         , m_allocator(context.getDefaultAllocator())
210     {
211     }
212 
~ContextDeviceHelper()213     virtual ~ContextDeviceHelper()
214     {
215     }
216 
getDeviceInterface(void) const217     const DeviceInterface &getDeviceInterface(void) const override
218     {
219         return m_deviceInterface;
220     }
getDevice(void) const221     VkDevice getDevice(void) const override
222     {
223         return m_device;
224     }
getQueueFamilyIndex(void) const225     uint32_t getQueueFamilyIndex(void) const override
226     {
227         return m_queueFamilyIndex;
228     }
getQueue(void) const229     VkQueue getQueue(void) const override
230     {
231         return m_queue;
232     }
getAllocator(void) const233     Allocator &getAllocator(void) const override
234     {
235         return m_allocator;
236     }
237 
238 protected:
239     const DeviceInterface &m_deviceInterface;
240     const VkDevice m_device;
241     const uint32_t m_queueFamilyIndex;
242     const VkQueue m_queue;
243     Allocator &m_allocator;
244 };
245 
246 class NoShaderTessellationAndGeometryPointSizeDeviceHelper : public DeviceHelper
247 {
248 public:
249     // Forbid copy and assignment.
250     NoShaderTessellationAndGeometryPointSizeDeviceHelper(const DeviceHelper &)                 = delete;
251     NoShaderTessellationAndGeometryPointSizeDeviceHelper &operator=(const DeviceHelper &other) = delete;
252 
NoShaderTessellationAndGeometryPointSizeDeviceHelper(Context & context)253     NoShaderTessellationAndGeometryPointSizeDeviceHelper(Context &context)
254     {
255         const auto &vkp           = context.getPlatformInterface();
256         const auto &vki           = context.getInstanceInterface();
257         const auto instance       = context.getInstance();
258         const auto physicalDevice = context.getPhysicalDevice();
259 
260         m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
261 
262         // Get device features (these have to be checked in checkSupport).
263         VkPhysicalDeviceFeatures2 features2                            = initVulkanStructure();
264         VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT gplFeatures = initVulkanStructure();
265         VkPhysicalDeviceTransformFeedbackFeaturesEXT xfbFeatures       = initVulkanStructure();
266         VkPhysicalDeviceMultiviewFeatures multiviewFeatures            = initVulkanStructure();
267         VkPhysicalDeviceHostQueryResetFeatures hostQueryResetFeat      = initVulkanStructure();
268 
269         const auto addFeatures = makeStructChainAdder(&features2);
270         addFeatures(&xfbFeatures);
271         if (context.isDeviceFunctionalitySupported("VK_EXT_graphics_pipeline_library"))
272             addFeatures(&gplFeatures);
273         if (context.isDeviceFunctionalitySupported("VK_KHR_multiview"))
274             addFeatures(&multiviewFeatures);
275         if (context.isDeviceFunctionalitySupported("VK_EXT_host_query_reset"))
276             addFeatures(&hostQueryResetFeat);
277 
278         vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
279 
280         features2.features.robustBufferAccess = VK_FALSE; // Disable robustness.
281         features2.features.shaderTessellationAndGeometryPointSize =
282             VK_FALSE; // Disable shaderTessellationAndGeometryPointSize.
283 
284         const auto queuePriority = 1.0f;
285         const VkDeviceQueueCreateInfo queueInfo{
286             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
287             nullptr,                                    // const void* pNext;
288             0u,                                         // VkDeviceQueueCreateFlags flags;
289             m_queueFamilyIndex,                         // uint32_t queueFamilyIndex;
290             1u,                                         // uint32_t queueCount;
291             &queuePriority,                             // const float* pQueuePriorities;
292         };
293 
294         const auto creationExtensions = context.getDeviceCreationExtensions();
295 
296         const VkDeviceCreateInfo createInfo{
297             VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
298             &features2,                           // const void* pNext;
299             0u,                                   // VkDeviceCreateFlags flags;
300             1u,                                   // uint32_t queueCreateInfoCount;
301             &queueInfo,                           // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
302             0u,                                   // uint32_t enabledLayerCount;
303             nullptr,                              // const char* const* ppEnabledLayerNames;
304             de::sizeU32(creationExtensions),      // uint32_t enabledExtensionCount;
305             de::dataOrNull(creationExtensions),   // const char* const* ppEnabledExtensionNames;
306             nullptr,                              // const VkPhysicalDeviceFeatures* pEnabledFeatures;
307         };
308 
309         // Create custom device and related objects
310         const auto enableValidation = context.getTestContext().getCommandLine().isValidationEnabled();
311 
312         m_device = createCustomDevice(enableValidation, vkp, instance, vki, physicalDevice, &createInfo);
313         m_vkd.reset(new DeviceDriver(vkp, instance, *m_device, context.getUsedApiVersion(),
314                                      context.getTestContext().getCommandLine()));
315         m_queue = getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
316         m_allocator.reset(
317             new SimpleAllocator(*m_vkd, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
318     }
319 
~NoShaderTessellationAndGeometryPointSizeDeviceHelper()320     virtual ~NoShaderTessellationAndGeometryPointSizeDeviceHelper()
321     {
322     }
323 
getDeviceInterface(void) const324     const vk::DeviceInterface &getDeviceInterface(void) const override
325     {
326         return *m_vkd;
327     }
getDevice(void) const328     vk::VkDevice getDevice(void) const override
329     {
330         return m_device.get();
331     }
getQueueFamilyIndex(void) const332     uint32_t getQueueFamilyIndex(void) const override
333     {
334         return m_queueFamilyIndex;
335     }
getQueue(void) const336     vk::VkQueue getQueue(void) const override
337     {
338         return m_queue;
339     }
getAllocator(void) const340     vk::Allocator &getAllocator(void) const override
341     {
342         return *m_allocator;
343     }
344 
345 protected:
346     vk::Move<vk::VkDevice> m_device;
347     std::unique_ptr<vk::DeviceDriver> m_vkd;
348     uint32_t m_queueFamilyIndex;
349     vk::VkQueue m_queue;
350     std::unique_ptr<vk::SimpleAllocator> m_allocator;
351 };
352 
353 std::unique_ptr<DeviceHelper> g_noShaderTessellationAndGeometryPointSizeHelper;
354 std::unique_ptr<DeviceHelper> g_contextDeviceHelper;
355 
getDeviceHelper(Context & context,const TestParameters & parameters)356 DeviceHelper &getDeviceHelper(Context &context, const TestParameters &parameters)
357 {
358     const bool isPoints         = parameters.isPoints();
359     const bool pointSizeWanted  = parameters.pointSizeWanted();
360     const bool usingTessGeom    = parameters.usingTessGeom();
361     const bool featureAvailable = context.getDeviceFeatures().shaderTessellationAndGeometryPointSize;
362 
363     if (isPoints && !pointSizeWanted && usingTessGeom && featureAvailable)
364     {
365         // We can run these tests, but we must use a custom device with no shaderTessellationAndGeometryPointSize.
366         if (!g_noShaderTessellationAndGeometryPointSizeHelper)
367             g_noShaderTessellationAndGeometryPointSizeHelper.reset(
368                 new NoShaderTessellationAndGeometryPointSizeDeviceHelper(context));
369         return *g_noShaderTessellationAndGeometryPointSizeHelper;
370     }
371 
372     // The default device works otherwise.
373     if (!g_contextDeviceHelper)
374         g_contextDeviceHelper.reset(new ContextDeviceHelper(context));
375     return *g_contextDeviceHelper;
376 }
377 
cleanupDevices()378 void cleanupDevices()
379 {
380     g_noShaderTessellationAndGeometryPointSizeHelper.reset(nullptr);
381     g_contextDeviceHelper.reset(nullptr);
382 }
383 
384 struct TopologyInfo
385 {
386     uint32_t primSize;                                  // The size of the on primitive.
387     std::string topologyName;                           // The suffix for the name of test.
388     std::function<uint64_t(uint64_t)> getNumPrimitives; // The number of primitives generated.
389     std::function<uint64_t(uint64_t)> getNumVertices;   // The number of vertices generated.
390 };
391 
392 const std::map<VkPrimitiveTopology, TopologyInfo> topologyData = {
393     {VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
394      {
395          1,
396          "",
__anonb6d10ff70202() 397          [](uint64_t vertexCount) { return vertexCount; },
__anonb6d10ff70302() 398          [](uint64_t primCount) { return primCount; },
399      }},
400     {VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
401      {
402          2,
403          "line_list_",
__anonb6d10ff70402() 404          [](uint64_t vertexCount) { return vertexCount / 2u; },
__anonb6d10ff70502() 405          [](uint64_t primCount) { return primCount * 2u; },
406      }},
407     {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
408      {
409          2,
410          "line_strip_",
__anonb6d10ff70602() 411          [](uint64_t vertexCount) { return vertexCount - 1u; },
__anonb6d10ff70702() 412          [](uint64_t primCount) { return primCount + 1u; },
413      }},
414     {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
415      {
416          3,
417          "triangle_list_",
__anonb6d10ff70802() 418          [](uint64_t vertexCount) { return vertexCount / 3u; },
__anonb6d10ff70902() 419          [](uint64_t primCount) { return primCount * 3u; },
420      }},
421     {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
422      {
423          3,
424          "triangle_strip_",
__anonb6d10ff70a02() 425          [](uint64_t vertexCount) { return vertexCount - 2u; },
__anonb6d10ff70b02() 426          [](uint64_t primCount) { return primCount + 2u; },
427      }},
428     {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
429      {
430          3,
431          "triangle_fan_",
__anonb6d10ff70c02() 432          [](uint64_t vertexCount) { return vertexCount - 2u; },
__anonb6d10ff70d02() 433          [](uint64_t primCount) { return primCount + 2u; },
434      }},
435     {VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
436      {
437          2,
438          "line_list_with_adjacency_",
__anonb6d10ff70e02() 439          [](uint64_t vertexCount) { return vertexCount / 4u; },
__anonb6d10ff70f02() 440          [](uint64_t primCount) { return primCount * 4u; },
441      }},
442     {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
443      {
444          2,
445          "line_strip_with_adjacency_",
__anonb6d10ff71002() 446          [](uint64_t vertexCount) { return vertexCount - 3u; },
__anonb6d10ff71102() 447          [](uint64_t primCount) { return primCount + 3u; },
448      }},
449     {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
450      {
451          3,
452          "triangle_list_with_adjacency_",
__anonb6d10ff71202() 453          [](uint64_t vertexCount) { return vertexCount / 6u; },
__anonb6d10ff71302() 454          [](uint64_t primCount) { return primCount * 6u; },
455      }},
456     {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
457      {
458          3,
459          "triangle_strip_with_adjacency_",
__anonb6d10ff71402() 460          [](uint64_t vertexCount) { return (vertexCount - 4u) / 2u; },
__anonb6d10ff71502() 461          [](uint64_t primCount) { return primCount * 2u + 4u; },
462      }},
463     {VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
464      {
465          3,
466          "patch_list_",
__anonb6d10ff71602() 467          [](uint64_t vertexCount) { return vertexCount / 3u; },
__anonb6d10ff71702() 468          [](uint64_t primCount) { return primCount * 3u; },
469      }},
470 };
471 
472 struct TransformFeedbackQuery
473 {
474     uint32_t written;
475     uint32_t attempts;
476 };
477 
478 const uint32_t MINIMUM_TF_BUFFER_SIZE = (1 << 27);
479 const uint32_t IMAGE_SIZE             = 64u;
480 
481 template <typename T>
makeSharedPtr(Move<T> move)482 inline SharedPtr<Unique<T>> makeSharedPtr(Move<T> move)
483 {
484     return SharedPtr<Unique<T>>(new Unique<T>(move));
485 }
486 
487 template <typename T>
getInvalidatedHostPtr(const DeviceInterface & vk,const VkDevice device,Allocation & bufAlloc)488 const T *getInvalidatedHostPtr(const DeviceInterface &vk, const VkDevice device, Allocation &bufAlloc)
489 {
490     invalidateAlloc(vk, device, bufAlloc);
491 
492     return static_cast<T *>(bufAlloc.getHostPtr());
493 }
494 
495 using PipelineLayoutWrapperPtr = std::unique_ptr<PipelineLayoutWrapper>;
496 
makePipelineLayout(PipelineConstructionType pipelineConstructionType,const DeviceInterface & vk,const VkDevice device,const uint32_t pcSize=sizeof (uint32_t))497 PipelineLayoutWrapperPtr makePipelineLayout(PipelineConstructionType pipelineConstructionType,
498                                             const DeviceInterface &vk, const VkDevice device,
499                                             const uint32_t pcSize = sizeof(uint32_t))
500 {
501     const VkPushConstantRange pushConstantRanges = {
502         VK_SHADER_STAGE_VERTEX_BIT, //  VkShaderStageFlags stageFlags;
503         0u,                         //  uint32_t offset;
504         pcSize,                     //  uint32_t size;
505     };
506 
507     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
508         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, //  VkStructureType sType;
509         DE_NULL,                                       //  const void* pNext;
510         (VkPipelineLayoutCreateFlags)0,                //  VkPipelineLayoutCreateFlags flags;
511         0u,                                            //  uint32_t setLayoutCount;
512         DE_NULL,                                       //  const VkDescriptorSetLayout* pSetLayouts;
513         1u,                                            //  uint32_t pushConstantRangeCount;
514         &pushConstantRanges,                           //  const VkPushConstantRange* pPushConstantRanges;
515     };
516 
517     PipelineLayoutWrapperPtr pipelineLayoutWrapper(
518         new PipelineLayoutWrapper(pipelineConstructionType, vk, device, &pipelineLayoutCreateInfo));
519     return pipelineLayoutWrapper;
520 }
521 
522 using GraphicsPipelineWrapperPtr = std::unique_ptr<GraphicsPipelineWrapper>;
523 
makeGraphicsPipeline(const PipelineConstructionType pipelineConstructionType,const InstanceInterface & vki,const DeviceInterface & vk,const VkPhysicalDevice physicalDevice,const VkDevice device,const std::vector<std::string> & deviceExtensions,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper & vertexModule,const ShaderWrapper & tessellationControlModule,const ShaderWrapper & tessellationEvalModule,const ShaderWrapper & geometryModule,const ShaderWrapper & fragmentModule,const VkExtent2D renderSize,const uint32_t subpass,const uint32_t * rasterizationStreamPtr=DE_NULL,const VkPrimitiveTopology topology=VK_PRIMITIVE_TOPOLOGY_POINT_LIST,const bool inputVertices=false,const bool depthClipControl=false,const uint32_t attachmentCount=0u)524 GraphicsPipelineWrapperPtr makeGraphicsPipeline(
525     const PipelineConstructionType pipelineConstructionType, const InstanceInterface &vki, const DeviceInterface &vk,
526     const VkPhysicalDevice physicalDevice, const VkDevice device, const std::vector<std::string> &deviceExtensions,
527     const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass, const ShaderWrapper &vertexModule,
528     const ShaderWrapper &tessellationControlModule, const ShaderWrapper &tessellationEvalModule,
529     const ShaderWrapper &geometryModule, const ShaderWrapper &fragmentModule, const VkExtent2D renderSize,
530     const uint32_t subpass, const uint32_t *rasterizationStreamPtr = DE_NULL,
531     const VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, const bool inputVertices = false,
532     const bool depthClipControl = false, const uint32_t attachmentCount = 0u)
533 {
534     const std::vector<VkViewport> viewports(1u, makeViewport(renderSize));
535     const std::vector<VkRect2D> scissors(1u, makeRect2D(renderSize));
536 
537     const VkPipelineViewportDepthClipControlCreateInfoEXT depthClipControlCreateInfo = {
538         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT, // VkStructureType sType;
539         DE_NULL,                                                                // const void* pNext;
540         VK_TRUE,                                                                // VkBool32 negativeOneToOne;
541     };
542 
543     const void *pipelineViewportStatePNext = (depthClipControl ? &depthClipControlCreateInfo : nullptr);
544 
545     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
546     const VkPipelineVertexInputStateCreateInfo *vertexInputStateCreateInfoPtr =
547         (inputVertices ? nullptr : &vertexInputStateCreateInfo);
548     const VkBool32 disableRasterization = (fragmentModule.getModule() == VK_NULL_HANDLE);
549     const uint32_t rasterizationStream  = ((!rasterizationStreamPtr) ? 0u : *rasterizationStreamPtr);
550 
551     const VkPipelineRasterizationStateStreamCreateInfoEXT rasterizationStateStreamCreateInfo = {
552         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT, //  VkStructureType sType;
553         DE_NULL,                                                               //  const void* pNext;
554         0,                  //  VkPipelineRasterizationStateStreamCreateFlagsEXT flags;
555         rasterizationStream //  uint32_t rasterizationStream;
556     };
557 
558     const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
559         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //  VkStructureType                            sType
560         &rasterizationStateStreamCreateInfo,                        //  const void*                                pNext
561         0u,                                                         //  VkPipelineRasterizationStateCreateFlags    flags
562         VK_FALSE,                        //  VkBool32                                depthClampEnable
563         disableRasterization,            //  VkBool32                                rasterizerDiscardEnable
564         VK_POLYGON_MODE_FILL,            //  VkPolygonMode                            polygonMode
565         VK_CULL_MODE_NONE,               //  VkCullModeFlags                            cullMode
566         VK_FRONT_FACE_COUNTER_CLOCKWISE, //  VkFrontFace                                frontFace
567         VK_FALSE,                        //  VkBool32                                depthBiasEnable
568         0.0f,                            //  float                                    depthBiasConstantFactor
569         0.0f,                            //  float                                    depthBiasClamp
570         0.0f,                            //  float                                    depthBiasSlopeFactor
571         1.0f                             //  float                                    lineWidth
572     };
573 
574     const VkPipelineRasterizationStateCreateInfo *rasterizationStateCreateInfoPtr =
575         ((!rasterizationStreamPtr) ? nullptr : &rasterizationStateCreateInfo);
576     const VkPipelineColorBlendAttachmentState defaultAttachmentState = {
577         VK_FALSE,                 // VkBool32 blendEnable;
578         VK_BLEND_FACTOR_ZERO,     // VkBlendFactor srcColorBlendFactor;
579         VK_BLEND_FACTOR_ZERO,     // VkBlendFactor dstColorBlendFactor;
580         VK_BLEND_OP_ADD,          // VkBlendOp colorBlendOp;
581         VK_BLEND_FACTOR_ZERO,     // VkBlendFactor srcAlphaBlendFactor;
582         VK_BLEND_FACTOR_ZERO,     // VkBlendFactor dstAlphaBlendFactor;
583         VK_BLEND_OP_ADD,          // VkBlendOp alphaBlendOp;
584         (VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask;
585          | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT),
586     };
587     const std::vector<VkPipelineColorBlendAttachmentState> attachmentStates(attachmentCount, defaultAttachmentState);
588     const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
589         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
590         nullptr,                                                  // const void* pNext;
591         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
592         VK_FALSE,                                                 // VkBool32 logicOpEnable;
593         VK_LOGIC_OP_CLEAR,                                        // VkLogicOp logicOp;
594         de::sizeU32(attachmentStates),                            // uint32_t attachmentCount;
595         de::dataOrNull(attachmentStates), // const VkPipelineColorBlendAttachmentState* pAttachments;
596         {0.0f, 0.0f, 0.0f, 0.0f},         // float blendConstants[4];
597     };
598 
599     GraphicsPipelineWrapperPtr pipelineWrapperPtr(
600         new GraphicsPipelineWrapper(vki, vk, physicalDevice, device, deviceExtensions, pipelineConstructionType));
601     auto &pipelineWrapper = *pipelineWrapperPtr;
602 
603     pipelineWrapper.setMonolithicPipelineLayout(pipelineLayout)
604         .setDefaultDepthStencilState()
605         .setDefaultMultisampleState()
606         .setDefaultPatchControlPoints(3u)
607         .setDefaultTopology(topology)
608         .setDefaultRasterizationState()
609         .setDefaultRasterizerDiscardEnable(disableRasterization)
610         .setViewportStatePnext(pipelineViewportStatePNext)
611         .setupVertexInputState(vertexInputStateCreateInfoPtr)
612         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, subpass, vertexModule,
613                                           rasterizationStateCreateInfoPtr, tessellationControlModule,
614                                           tessellationEvalModule, geometryModule)
615         .setupFragmentShaderState(pipelineLayout, renderPass, subpass, fragmentModule)
616         .setupFragmentOutputState(renderPass, subpass, &colorBlendStateCreateInfo)
617         .buildPipeline();
618 
619     return pipelineWrapperPtr;
620 }
621 
makeImageCreateInfo(const VkImageCreateFlags flags,const VkImageType type,const VkFormat format,const VkExtent2D size,const uint32_t numLayers,const VkImageUsageFlags usage)622 VkImageCreateInfo makeImageCreateInfo(const VkImageCreateFlags flags, const VkImageType type, const VkFormat format,
623                                       const VkExtent2D size, const uint32_t numLayers, const VkImageUsageFlags usage)
624 {
625     const VkExtent3D extent             = {size.width, size.height, 1u};
626     const VkImageCreateInfo imageParams = {
627         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
628         DE_NULL,                             // const void* pNext;
629         flags,                               // VkImageCreateFlags flags;
630         type,                                // VkImageType imageType;
631         format,                              // VkFormat format;
632         extent,                              // VkExtent3D extent;
633         1u,                                  // uint32_t mipLevels;
634         numLayers,                           // uint32_t arrayLayers;
635         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
636         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
637         usage,                               // VkImageUsageFlags usage;
638         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
639         0u,                                  // uint32_t queueFamilyIndexCount;
640         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
641         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
642     };
643     return imageParams;
644 }
645 
makeCustomRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat format=VK_FORMAT_UNDEFINED)646 Move<VkRenderPass> makeCustomRenderPass(const DeviceInterface &vk, const VkDevice device,
647                                         const VkFormat format = VK_FORMAT_UNDEFINED)
648 {
649     std::vector<VkSubpassDescription> subpassDescriptions;
650     std::vector<VkSubpassDependency> subpassDependencies;
651     const bool hasColorAtt = (format != VK_FORMAT_UNDEFINED);
652 
653     std::vector<VkAttachmentDescription> attachmentDescs;
654     std::vector<VkAttachmentReference> attachmentRefs;
655 
656     if (hasColorAtt)
657     {
658         attachmentDescs.push_back(makeAttachmentDescription(
659             0u, format, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
660             VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
661             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
662         attachmentRefs.push_back(makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
663     }
664 
665     const VkSubpassDescription description = {
666         (VkSubpassDescriptionFlags)0,    //  VkSubpassDescriptionFlags flags;
667         VK_PIPELINE_BIND_POINT_GRAPHICS, //  VkPipelineBindPoint pipelineBindPoint;
668         0u,                              //  uint32_t inputAttachmentCount;
669         nullptr,                         //  const VkAttachmentReference* pInputAttachments;
670         de::sizeU32(attachmentRefs),     //  uint32_t colorAttachmentCount;
671         de::dataOrNull(attachmentRefs),  //  const VkAttachmentReference* pColorAttachments;
672         nullptr,                         //  const VkAttachmentReference* pResolveAttachments;
673         nullptr,                         //  const VkAttachmentReference* pDepthStencilAttachment;
674         0u,                              //  uint32_t preserveAttachmentCount;
675         nullptr,                         //  const uint32_t* pPreserveAttachments;
676     };
677     subpassDescriptions.push_back(description);
678 
679     const VkSubpassDependency dependency = {
680         0u,                                                 //  uint32_t srcSubpass;
681         0u,                                                 //  uint32_t dstSubpass;
682         VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,       //  VkPipelineStageFlags srcStageMask;
683         VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,                //  VkPipelineStageFlags dstStageMask;
684         VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, //  VkAccessFlags srcAccessMask;
685         VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,  //  VkAccessFlags dstAccessMask;
686         0u                                                  //  VkDependencyFlags dependencyFlags;
687     };
688     subpassDependencies.push_back(dependency);
689 
690     const VkRenderPassCreateInfo renderPassInfo = {
691         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, //  VkStructureType sType;
692         nullptr,                                   //  const void* pNext;
693         static_cast<VkRenderPassCreateFlags>(0u),  //  VkRenderPassCreateFlags flags;
694         de::sizeU32(attachmentDescs),              //  uint32_t attachmentCount;
695         de::dataOrNull(attachmentDescs),           //  const VkAttachmentDescription* pAttachments;
696         de::sizeU32(subpassDescriptions),          //  uint32_t subpassCount;
697         de::dataOrNull(subpassDescriptions),       //  const VkSubpassDescription* pSubpasses;
698         de::sizeU32(subpassDependencies),          //  uint32_t dependencyCount;
699         de::dataOrNull(subpassDependencies),       //  const VkSubpassDependency* pDependencies;
700     };
701 
702     return createRenderPass(vk, device, &renderPassInfo);
703 }
704 
makeImageMemoryBarrier(const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask,const VkImageLayout oldLayout,const VkImageLayout newLayout,const VkImage image,const VkImageSubresourceRange subresourceRange)705 VkImageMemoryBarrier makeImageMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask,
706                                             const VkImageLayout oldLayout, const VkImageLayout newLayout,
707                                             const VkImage image, const VkImageSubresourceRange subresourceRange)
708 {
709     const VkImageMemoryBarrier barrier = {
710         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
711         DE_NULL,                                // const void* pNext;
712         srcAccessMask,                          // VkAccessFlags outputMask;
713         dstAccessMask,                          // VkAccessFlags inputMask;
714         oldLayout,                              // VkImageLayout oldLayout;
715         newLayout,                              // VkImageLayout newLayout;
716         VK_QUEUE_FAMILY_IGNORED,                // uint32_t srcQueueFamilyIndex;
717         VK_QUEUE_FAMILY_IGNORED,                // uint32_t destQueueFamilyIndex;
718         image,                                  // VkImage image;
719         subresourceRange,                       // VkImageSubresourceRange subresourceRange;
720     };
721     return barrier;
722 }
723 
makeBufferMemoryBarrier(const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask,const VkBuffer buffer,const VkDeviceSize offset,const VkDeviceSize bufferSizeBytes)724 VkBufferMemoryBarrier makeBufferMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask,
725                                               const VkBuffer buffer, const VkDeviceSize offset,
726                                               const VkDeviceSize bufferSizeBytes)
727 {
728     const VkBufferMemoryBarrier barrier = {
729         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, //  VkStructureType sType;
730         DE_NULL,                                 //  const void* pNext;
731         srcAccessMask,                           //  VkAccessFlags srcAccessMask;
732         dstAccessMask,                           //  VkAccessFlags dstAccessMask;
733         VK_QUEUE_FAMILY_IGNORED,                 //  uint32_t srcQueueFamilyIndex;
734         VK_QUEUE_FAMILY_IGNORED,                 //  uint32_t destQueueFamilyIndex;
735         buffer,                                  //  VkBuffer buffer;
736         offset,                                  //  VkDeviceSize offset;
737         bufferSizeBytes,                         //  VkDeviceSize size;
738     };
739     return barrier;
740 }
741 
makeMemoryBarrier(const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask)742 VkMemoryBarrier makeMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask)
743 {
744     const VkMemoryBarrier barrier = {
745         VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
746         DE_NULL,                          // const void* pNext;
747         srcAccessMask,                    // VkAccessFlags outputMask;
748         dstAccessMask,                    // VkAccessFlags inputMask;
749     };
750     return barrier;
751 }
752 
makeQueryPoolCreateInfo(const uint32_t queryCountersNumber)753 VkQueryPoolCreateInfo makeQueryPoolCreateInfo(const uint32_t queryCountersNumber)
754 {
755     const VkQueryPoolCreateInfo queryPoolCreateInfo = {
756         VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,    //  VkStructureType sType;
757         DE_NULL,                                     //  const void* pNext;
758         (VkQueryPoolCreateFlags)0,                   //  VkQueryPoolCreateFlags flags;
759         VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, //  VkQueryType queryType;
760         queryCountersNumber,                         //  uint32_t queryCount;
761         0u,                                          //  VkQueryPipelineStatisticFlags pipelineStatistics;
762     };
763 
764     return queryPoolCreateInfo;
765 }
766 
fillBuffer(const DeviceInterface & vk,const VkDevice device,Allocation & bufferAlloc,VkDeviceSize bufferSize,const void * data,const VkDeviceSize dataSize)767 void fillBuffer(const DeviceInterface &vk, const VkDevice device, Allocation &bufferAlloc, VkDeviceSize bufferSize,
768                 const void *data, const VkDeviceSize dataSize)
769 {
770     const VkMappedMemoryRange memRange = {
771         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, //  VkStructureType sType;
772         DE_NULL,                               //  const void* pNext;
773         bufferAlloc.getMemory(),               //  VkDeviceMemory memory;
774         bufferAlloc.getOffset(),               //  VkDeviceSize offset;
775         VK_WHOLE_SIZE                          //  VkDeviceSize size;
776     };
777     std::vector<uint8_t> dataVec(static_cast<uint32_t>(bufferSize), 0u);
778 
779     DE_ASSERT(bufferSize >= dataSize);
780 
781     deMemcpy(&dataVec[0], data, static_cast<uint32_t>(dataSize));
782 
783     deMemcpy(bufferAlloc.getHostPtr(), &dataVec[0], dataVec.size());
784     VK_CHECK(vk.flushMappedMemoryRanges(device, 1u, &memRange));
785 }
786 
destripedLineCount(const std::vector<uint32_t> & lineStripeSizesList)787 uint32_t destripedLineCount(const std::vector<uint32_t> &lineStripeSizesList)
788 {
789     uint32_t result = 0;
790 
791     DE_ASSERT(!lineStripeSizesList.empty());
792 
793     for (auto x : lineStripeSizesList)
794         result += x > 1 ? x - 1 : 0;
795 
796     return result;
797 }
798 
destripedTriangleCount(const std::vector<uint32_t> & triangleStripeSizesList)799 uint32_t destripedTriangleCount(const std::vector<uint32_t> &triangleStripeSizesList)
800 {
801     uint32_t result = 0;
802 
803     DE_ASSERT(!triangleStripeSizesList.empty());
804 
805     for (auto x : triangleStripeSizesList)
806         result += x > 2 ? x - 2 : 0;
807 
808     return result;
809 }
810 
811 class TransformFeedbackTestInstance : public TestInstance
812 {
813 public:
814     TransformFeedbackTestInstance(Context &context, const TestParameters &parameters);
815 
816 protected:
817     void validateLimits();
818     std::vector<VkDeviceSize> generateSizesList(const size_t bufBytes, const size_t chunkCount);
819     std::vector<VkDeviceSize> generateOffsetsList(const std::vector<VkDeviceSize> &sizesList);
820     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
821                                        const uint32_t bufBytes);
822 
823     const VkExtent2D m_imageExtent2D;
824     const TestParameters m_parameters;
825     VkPhysicalDeviceTransformFeedbackPropertiesEXT m_transformFeedbackProperties;
826     de::Random m_rnd;
827 };
828 
TransformFeedbackTestInstance(Context & context,const TestParameters & parameters)829 TransformFeedbackTestInstance::TransformFeedbackTestInstance(Context &context, const TestParameters &parameters)
830     : TestInstance(context)
831     , m_imageExtent2D(makeExtent2D(IMAGE_SIZE, IMAGE_SIZE))
832     , m_parameters(parameters)
833     , m_rnd(context.getTestContext().getCommandLine().getBaseSeed())
834 {
835     VkPhysicalDeviceProperties2 deviceProperties2;
836 
837     deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
838     deMemset(&m_transformFeedbackProperties, 0, sizeof(m_transformFeedbackProperties));
839 
840     deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
841     deviceProperties2.pNext = &m_transformFeedbackProperties;
842 
843     m_transformFeedbackProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
844     m_transformFeedbackProperties.pNext = DE_NULL;
845 
846     context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &deviceProperties2);
847 
848     validateLimits();
849 }
850 
validateLimits()851 void TransformFeedbackTestInstance::validateLimits()
852 {
853     VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBuffers, 1);
854     VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferSize, MINIMUM_TF_BUFFER_SIZE);
855     VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize, 512);
856     VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize, 512);
857     VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride, 512);
858 
859     VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackQueries);
860     VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackStreamsLinesTriangles);
861     VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackRasterizationStreamSelect);
862     VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackDraw);
863 }
864 
generateSizesList(const size_t bufBytes,const size_t chunkCount)865 std::vector<VkDeviceSize> TransformFeedbackTestInstance::generateSizesList(const size_t bufBytes,
866                                                                            const size_t chunkCount)
867 {
868     const int minChunkSlot = static_cast<int>(1);
869     const int maxChunkSlot = static_cast<int>(bufBytes / sizeof(uint32_t));
870     int prevOffsetSlot     = 0;
871     std::map<int, bool> offsetsSet;
872     std::vector<VkDeviceSize> result;
873 
874     DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
875     DE_ASSERT(bufBytes % sizeof(uint32_t) == 0);
876     DE_ASSERT(minChunkSlot <= maxChunkSlot);
877     DE_ASSERT(chunkCount > 0);
878     // To be effective this algorithm requires that chunkCount is much less than amount of chunks possible
879     DE_ASSERT(8 * chunkCount <= static_cast<size_t>(maxChunkSlot));
880 
881     offsetsSet[0] = true;
882 
883     // Create a list of unique offsets first
884     for (size_t chunkNdx = 1; chunkNdx < chunkCount; ++chunkNdx)
885     {
886         int chunkSlot;
887 
888         do
889         {
890             chunkSlot = m_rnd.getInt(minChunkSlot, maxChunkSlot - 1);
891         } while (offsetsSet.find(chunkSlot) != offsetsSet.end());
892 
893         offsetsSet[chunkSlot] = true;
894     }
895     offsetsSet[maxChunkSlot] = true;
896 
897     // Calculate sizes of offsets list
898     result.reserve(chunkCount);
899     for (std::map<int, bool>::iterator mapIt = offsetsSet.begin(); mapIt != offsetsSet.end(); ++mapIt)
900     {
901         const int offsetSlot = mapIt->first;
902 
903         if (offsetSlot == 0)
904             continue;
905 
906         DE_ASSERT(prevOffsetSlot < offsetSlot && offsetSlot > 0);
907 
908         result.push_back(
909             static_cast<VkDeviceSize>(static_cast<size_t>(offsetSlot - prevOffsetSlot) * sizeof(uint32_t)));
910 
911         prevOffsetSlot = offsetSlot;
912     }
913 
914     DE_ASSERT(result.size() == chunkCount);
915 
916     return result;
917 }
918 
generateOffsetsList(const std::vector<VkDeviceSize> & sizesList)919 std::vector<VkDeviceSize> TransformFeedbackTestInstance::generateOffsetsList(const std::vector<VkDeviceSize> &sizesList)
920 {
921     VkDeviceSize offset = 0ull;
922     std::vector<VkDeviceSize> result;
923 
924     result.reserve(sizesList.size());
925 
926     for (size_t chunkNdx = 0; chunkNdx < sizesList.size(); ++chunkNdx)
927     {
928         result.push_back(offset);
929 
930         offset += sizesList[chunkNdx];
931     }
932 
933     DE_ASSERT(sizesList.size() == result.size());
934 
935     return result;
936 }
937 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes)938 void TransformFeedbackTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
939                                                                   const MovePtr<Allocation> &bufAlloc,
940                                                                   const uint32_t bufBytes)
941 {
942     const DeviceInterface &vk = deviceHelper.getDeviceInterface();
943     const VkDevice device     = deviceHelper.getDevice();
944     const uint32_t numPoints  = static_cast<uint32_t>(bufBytes / sizeof(uint32_t));
945     const uint32_t *tfData    = getInvalidatedHostPtr<uint32_t>(vk, device, *bufAlloc);
946 
947     for (uint32_t i = 0; i < numPoints; ++i)
948         if (tfData[i] != i)
949             TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) +
950                      " expected:" + de::toString(i));
951 }
952 
953 class TransformFeedbackBasicTestInstance : public TransformFeedbackTestInstance
954 {
955 public:
956     TransformFeedbackBasicTestInstance(Context &context, const TestParameters &parameters);
957 
958 protected:
959     tcu::TestStatus iterate(void);
960 };
961 
TransformFeedbackBasicTestInstance(Context & context,const TestParameters & parameters)962 TransformFeedbackBasicTestInstance::TransformFeedbackBasicTestInstance(Context &context,
963                                                                        const TestParameters &parameters)
964     : TransformFeedbackTestInstance(context, parameters)
965 {
966 }
967 
iterate(void)968 tcu::TestStatus TransformFeedbackBasicTestInstance::iterate(void)
969 {
970     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
971     const auto &vki                 = m_context.getInstanceInterface();
972     const auto physicalDevice       = m_context.getPhysicalDevice();
973     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
974     const VkDevice device           = deviceHelper.getDevice();
975     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
976     const VkQueue queue             = deviceHelper.getQueue();
977     Allocator &allocator            = deviceHelper.getAllocator();
978 
979     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
980     const ShaderWrapper nullModule;
981     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
982     const Unique<VkFramebuffer> framebuffer(
983         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
984     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
985     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
986                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
987                                              vertexModule, nullModule, nullModule, nullModule, nullModule,
988                                              m_imageExtent2D, 0u, &m_parameters.streamId));
989     const Unique<VkCommandPool> cmdPool(
990         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
991     const Unique<VkCommandBuffer> cmdBuffer(
992         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
993 
994     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
995         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
996     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
997     const MovePtr<Allocation> tfBufAllocation =
998         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
999     const VkMemoryBarrier tfMemoryBarrier =
1000         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1001     const std::vector<VkDeviceSize> tfBufBindingSizes =
1002         generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
1003     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
1004 
1005     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1006 
1007     beginCommandBuffer(vk, *cmdBuffer);
1008     {
1009         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1010         {
1011             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1012 
1013             for (uint32_t drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
1014             {
1015                 const uint32_t startValue = static_cast<uint32_t>(tfBufBindingOffsets[drawNdx] / sizeof(uint32_t));
1016                 const uint32_t numPoints  = static_cast<uint32_t>(tfBufBindingSizes[drawNdx] / sizeof(uint32_t));
1017 
1018                 vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[drawNdx],
1019                                                       &tfBufBindingSizes[drawNdx]);
1020 
1021                 vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u,
1022                                     sizeof(startValue), &startValue);
1023 
1024                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1025                 {
1026                     vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
1027                 }
1028                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1029             }
1030         }
1031         endRenderPass(vk, *cmdBuffer);
1032 
1033         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1034                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1035     }
1036     endCommandBuffer(vk, *cmdBuffer);
1037     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1038 
1039     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
1040 
1041     return tcu::TestStatus::pass("Pass");
1042 }
1043 
1044 class TransformFeedbackResumeTestInstance : public TransformFeedbackTestInstance
1045 {
1046 public:
1047     TransformFeedbackResumeTestInstance(Context &context, const TestParameters &parameters);
1048 
1049 protected:
1050     tcu::TestStatus iterate(void);
1051 };
1052 
TransformFeedbackResumeTestInstance(Context & context,const TestParameters & parameters)1053 TransformFeedbackResumeTestInstance::TransformFeedbackResumeTestInstance(Context &context,
1054                                                                          const TestParameters &parameters)
1055     : TransformFeedbackTestInstance(context, parameters)
1056 {
1057 }
1058 
iterate(void)1059 tcu::TestStatus TransformFeedbackResumeTestInstance::iterate(void)
1060 {
1061     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
1062     const auto &vki                 = m_context.getInstanceInterface();
1063     const auto physicalDevice       = m_context.getPhysicalDevice();
1064     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
1065     const VkDevice device           = deviceHelper.getDevice();
1066     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
1067     const VkQueue queue             = deviceHelper.getQueue();
1068     Allocator &allocator            = deviceHelper.getAllocator();
1069 
1070     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1071     const ShaderWrapper kNullModule;
1072     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1073     const Unique<VkFramebuffer> framebuffer(
1074         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1075     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
1076     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
1077                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
1078                                              vertexModule, kNullModule, kNullModule, kNullModule, kNullModule,
1079                                              m_imageExtent2D, 0u, &m_parameters.streamId));
1080 
1081     const Unique<VkCommandPool> cmdPool(
1082         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1083     const Unique<VkCommandBuffer> cmdBuffer(
1084         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1085 
1086     VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
1087         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1088 
1089 #ifndef CTS_USES_VULKANSC
1090     vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
1091     if (m_parameters.useMaintenance5)
1092     {
1093         bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)tfBufCreateInfo.usage;
1094         tfBufCreateInfo.pNext   = &bufferUsageFlags2;
1095         tfBufCreateInfo.usage   = 0;
1096     }
1097 #endif // CTS_USES_VULKANSC
1098 
1099     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
1100     const MovePtr<Allocation> tfBufAllocation =
1101         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1102     const VkMemoryBarrier tfMemoryBarrier =
1103         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1104     const std::vector<VkDeviceSize> tfBufBindingSizes   = std::vector<VkDeviceSize>(1, m_parameters.bufferSize);
1105     const std::vector<VkDeviceSize> tfBufBindingOffsets = std::vector<VkDeviceSize>(1, 0ull);
1106 
1107     const size_t tfcBufSize = 16 * sizeof(uint32_t) * m_parameters.partCount;
1108     VkBufferCreateInfo tfcBufCreateInfo =
1109         makeBufferCreateInfo(tfcBufSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT);
1110 
1111 #ifndef CTS_USES_VULKANSC
1112     if (m_parameters.useMaintenance5)
1113     {
1114         bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)tfcBufCreateInfo.usage;
1115         tfcBufCreateInfo.pNext  = &bufferUsageFlags2;
1116         tfcBufCreateInfo.usage  = 0;
1117     }
1118 #endif // CTS_USES_VULKANSC
1119 
1120     const Move<VkBuffer> tfcBuf = createBuffer(vk, device, &tfcBufCreateInfo);
1121     const MovePtr<Allocation> tfcBufAllocation =
1122         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfcBuf), MemoryRequirement::Any);
1123     const std::vector<VkDeviceSize> tfcBufBindingOffsets =
1124         generateOffsetsList(generateSizesList(tfcBufSize, m_parameters.partCount));
1125     const VkBufferMemoryBarrier tfcBufBarrier =
1126         makeBufferMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
1127                                 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, *tfcBuf, 0ull, VK_WHOLE_SIZE);
1128 
1129     const std::vector<VkDeviceSize> chunkSizesList = generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
1130     const std::vector<VkDeviceSize> chunkOffsetsList = generateOffsetsList(chunkSizesList);
1131 
1132     DE_ASSERT(tfBufBindingSizes.size() == 1);
1133     DE_ASSERT(tfBufBindingOffsets.size() == 1);
1134 
1135     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1136     VK_CHECK(vk.bindBufferMemory(device, *tfcBuf, tfcBufAllocation->getMemory(), tfcBufAllocation->getOffset()));
1137 
1138     beginCommandBuffer(vk, *cmdBuffer);
1139     {
1140         for (size_t drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
1141         {
1142             const uint32_t startValue        = static_cast<uint32_t>(chunkOffsetsList[drawNdx] / sizeof(uint32_t));
1143             const uint32_t numPoints         = static_cast<uint32_t>(chunkSizesList[drawNdx] / sizeof(uint32_t));
1144             const uint32_t countBuffersCount = (drawNdx == 0) ? 0 : 1;
1145 
1146             beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1147             {
1148 
1149                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1150 
1151                 vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[0],
1152                                                       &tfBufBindingSizes[0]);
1153 
1154                 vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u,
1155                                     sizeof(startValue), &startValue);
1156 
1157                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, countBuffersCount, (drawNdx == 0) ? DE_NULL : &*tfcBuf,
1158                                                 (drawNdx == 0) ? DE_NULL : &tfcBufBindingOffsets[drawNdx - 1]);
1159                 {
1160                     vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
1161                 }
1162                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf, &tfcBufBindingOffsets[drawNdx]);
1163             }
1164             endRenderPass(vk, *cmdBuffer);
1165 
1166             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
1167                                   VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 0u, DE_NULL, 1u, &tfcBufBarrier, 0u,
1168                                   DE_NULL);
1169         }
1170 
1171         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1172                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1173     }
1174     endCommandBuffer(vk, *cmdBuffer);
1175     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1176 
1177     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
1178 
1179     return tcu::TestStatus::pass("Pass");
1180 }
1181 
1182 class TransformFeedbackWindingOrderTestInstance : public TransformFeedbackTestInstance
1183 {
1184 public:
1185     TransformFeedbackWindingOrderTestInstance(Context &context, const TestParameters &parameters);
1186 
1187 protected:
1188     struct TopologyParameters
1189     {
1190         // number of vertex in primitive; 2 for line, 3 for triangle
1191         uint32_t vertexPerPrimitive;
1192 
1193         // pointer to function calculating number of points that
1194         // will be generated for given part count
1195         std::function<uint32_t(uint32_t)> getNumGeneratedPoints;
1196 
1197         // pointer to function generating expected values; parameter is
1198         // primitive index, result array with expected data for primitive vertex
1199         std::function<std::vector<uint32_t>(uint32_t)> getExpectedValuesForPrimitive;
1200     };
1201     typedef const std::map<VkPrimitiveTopology, TopologyParameters> TopologyParametersMap;
1202 
1203 protected:
1204     const TopologyParametersMap &getTopologyParametersMap(void);
1205     tcu::TestStatus iterate(void);
1206     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
1207                                        const uint32_t bufBytes);
1208 
1209 private:
1210     TopologyParameters m_tParameters;
1211     const bool m_requiresTesselationStage;
1212 };
1213 
TransformFeedbackWindingOrderTestInstance(Context & context,const TestParameters & parameters)1214 TransformFeedbackWindingOrderTestInstance::TransformFeedbackWindingOrderTestInstance(Context &context,
1215                                                                                      const TestParameters &parameters)
1216     : TransformFeedbackTestInstance(context, parameters)
1217     , m_requiresTesselationStage(parameters.primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
1218 {
1219     if (m_requiresTesselationStage && !context.getDeviceFeatures().tessellationShader)
1220         throw tcu::NotSupportedError("Tessellation shader not supported");
1221 
1222     TopologyParametersMap topologyParametersMap = getTopologyParametersMap();
1223     DE_ASSERT(topologyParametersMap.find(parameters.primTopology) != topologyParametersMap.end());
1224     m_tParameters = topologyParametersMap.at(parameters.primTopology);
1225 }
1226 
1227 const TransformFeedbackWindingOrderTestInstance::TopologyParametersMap &TransformFeedbackWindingOrderTestInstance::
getTopologyParametersMap(void)1228     getTopologyParametersMap(void)
1229 {
1230     static const TopologyParametersMap topologyParametersMap = {
1231         {VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
1232          {1u, [](uint32_t partCount) { return partCount; },
1233           [](uint32_t i) {
1234               return std::vector<uint32_t>{i, i + 1u};
1235           }}},
1236         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
1237          {2u, [](uint32_t partCount) { return partCount; },
1238           [](uint32_t i) {
1239               return std::vector<uint32_t>{2 * i, 2 * i + 1u};
1240           }}},
1241         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
1242          {2u, [](uint32_t partCount) { return 2u * (partCount - 1); },
1243           [](uint32_t i) {
1244               return std::vector<uint32_t>{i, i + 1u};
1245           }}},
1246         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1247          {3u, [](uint32_t partCount) { return partCount; },
1248           [](uint32_t i) {
1249               return std::vector<uint32_t>{3 * i, 3 * i + 1u, 3 * i + 2u};
1250           }}},
1251         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1252          {3u, [](uint32_t partCount) { return 3u * (partCount - 2); },
1253           [](uint32_t i)
1254           {
1255               const uint32_t iMod2 = i % 2;
1256               return std::vector<uint32_t>{i, i + 1 + iMod2, i + 2 - iMod2};
1257           }}},
1258         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
1259          {3u, [](uint32_t partCount) { return partCount; },
1260           [](uint32_t i) {
1261               return std::vector<uint32_t>{i + 1, i + 2, 0};
1262           }}},
1263         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
1264          {2u,
1265           [](uint32_t partCount)
1266           {
1267               return partCount / 4u;
1268           }, // note: this cant be replaced with partCount / 2 as for partCount=6 we will get 3 instead of 2
1269           [](uint32_t i) {
1270               return std::vector<uint32_t>{i + 1u, i + 2u};
1271           }}},
1272         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
1273          {2u, [](uint32_t partCount) { return 2u * (partCount - 3u); },
1274           [](uint32_t i) {
1275               return std::vector<uint32_t>{i + 1u, i + 2u};
1276           }}},
1277         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
1278          {3u, [](uint32_t partCount) { return partCount / 2u; },
1279           [](uint32_t i) {
1280               return std::vector<uint32_t>{6 * i, 6 * i + 2u, 6 * i + 4u};
1281           }}},
1282         {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
1283          {3u, [](uint32_t partCount) { return 3u * (partCount / 2u - 2u); },
1284           [](uint32_t i)
1285           {
1286               const bool even = (0 == i % 2);
1287               if (even)
1288                   return std::vector<uint32_t>{2 * i + 0, 2 * i + 2, 2 * i + 4};
1289               return std::vector<uint32_t>{2 * i + 0, 2 * i + 4, 2 * i + 2};
1290           }}},
1291         {VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
1292          {9u, [](uint32_t partCount) { return partCount * 3u; },
1293           [](uint32_t i)
1294           {
1295               // we cant generate vertex numbers in tesselation evaluation shader;
1296               // check if patch index is correct for every 9 generated vertex
1297               return std::vector<uint32_t>(9, i);
1298           }}}};
1299 
1300     return topologyParametersMap;
1301 }
1302 
iterate(void)1303 tcu::TestStatus TransformFeedbackWindingOrderTestInstance::iterate(void)
1304 {
1305     DE_ASSERT(m_parameters.partCount >= 6);
1306 
1307     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
1308     const auto &vki                 = m_context.getInstanceInterface();
1309     const auto physicalDevice       = m_context.getPhysicalDevice();
1310     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
1311     const VkDevice device           = deviceHelper.getDevice();
1312     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
1313     const VkQueue queue             = deviceHelper.getQueue();
1314     Allocator &allocator            = deviceHelper.getAllocator();
1315 
1316     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1317     ShaderWrapper tescModule;
1318     ShaderWrapper teseModule;
1319     const ShaderWrapper kNullModule;
1320 
1321     if (m_requiresTesselationStage)
1322     {
1323         tescModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tesc"), 0u);
1324         teseModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tese"), 0u);
1325     }
1326 
1327     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1328     const Unique<VkFramebuffer> framebuffer(
1329         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1330     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
1331     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
1332                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
1333                                              vertexModule, tescModule, teseModule, kNullModule, kNullModule,
1334                                              m_imageExtent2D, 0u, DE_NULL, m_parameters.primTopology));
1335     const Unique<VkCommandPool> cmdPool(
1336         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1337     const Unique<VkCommandBuffer> cmdBuffer(
1338         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1339     const VkDeviceSize bufferSize = m_tParameters.getNumGeneratedPoints(m_parameters.partCount) * sizeof(uint32_t);
1340     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
1341         bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1342     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
1343     const MovePtr<Allocation> tfBufAllocation =
1344         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1345     const VkMemoryBarrier tfMemoryBarrier =
1346         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1347     const VkDeviceSize tfBufBindingSize   = bufferSize;
1348     const VkDeviceSize tfBufBindingOffset = 0u;
1349     const uint32_t startValue             = 0u;
1350 
1351     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1352 
1353     beginCommandBuffer(vk, *cmdBuffer);
1354     {
1355         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1356         {
1357             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1358 
1359             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
1360 
1361             vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(startValue),
1362                                 &startValue);
1363 
1364             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1365             {
1366                 vk.cmdDraw(*cmdBuffer, m_parameters.partCount, 1u, 0u, 0u);
1367             }
1368             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1369         }
1370         endRenderPass(vk, *cmdBuffer);
1371 
1372         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1373                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1374     }
1375     endCommandBuffer(vk, *cmdBuffer);
1376     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1377 
1378     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, static_cast<uint32_t>(bufferSize));
1379 
1380     return tcu::TestStatus::pass("Pass");
1381 }
1382 
1383 template <typename T, int Size>
operator >(const tcu::Vector<T,Size> & a,const tcu::Vector<T,Size> & b)1384 bool operator>(const tcu::Vector<T, Size> &a, const tcu::Vector<T, Size> &b)
1385 {
1386     return tcu::boolAny(tcu::greaterThan(a, b));
1387 }
1388 
1389 template <typename T, int Size>
elemAbsDiff(const tcu::Vector<T,Size> & a,const tcu::Vector<T,Size> & b)1390 tcu::Vector<T, Size> elemAbsDiff(const tcu::Vector<T, Size> &a, const tcu::Vector<T, Size> &b)
1391 {
1392     return tcu::absDiff(a, b);
1393 }
1394 
elemAbsDiff(uint32_t a,uint32_t b)1395 uint32_t elemAbsDiff(uint32_t a, uint32_t b)
1396 {
1397     if (a > b)
1398         return a - b;
1399     return b - a;
1400 }
1401 
1402 template <typename T>
verifyVertexDataWithWinding(const std::vector<T> & reference,const T * result,const size_t vertexCount,const size_t verticesPerPrimitive,const T & threshold)1403 std::vector<std::string> verifyVertexDataWithWinding(const std::vector<T> &reference, const T *result,
1404                                                      const size_t vertexCount, const size_t verticesPerPrimitive,
1405                                                      const T &threshold)
1406 {
1407     //DE_ASSERT(vertexCount % verticesPerPrimitive == 0);
1408     //DE_ASSERT(reference.size() == vertexCount);
1409     const size_t primitiveCount = vertexCount / verticesPerPrimitive;
1410 
1411     std::vector<std::string> errors;
1412 
1413     for (size_t primIdx = 0; primIdx < primitiveCount; ++primIdx)
1414     {
1415         const auto pastVertexCount = verticesPerPrimitive * primIdx;
1416         const T *resultPrim        = result + pastVertexCount;
1417         const T *referencePrim     = &reference.at(pastVertexCount);
1418         bool primitiveOK           = false;
1419 
1420         // Vertices must be in the same winding order, but the first vertex may vary. We test every rotation below.
1421         // E.g. vertices 0 1 2 could be stored as 0 1 2, 2 0 1 or 1 2 0.
1422         for (size_t firstVertex = 0; firstVertex < verticesPerPrimitive; ++firstVertex)
1423         {
1424             bool match = true;
1425             for (size_t vertIdx = 0; vertIdx < verticesPerPrimitive; ++vertIdx)
1426             {
1427                 const auto &refVertex = referencePrim[(firstVertex + vertIdx) % verticesPerPrimitive]; // Rotation.
1428                 const auto &resVertex = resultPrim[vertIdx];
1429 
1430                 if (elemAbsDiff(refVertex, resVertex) > threshold)
1431                 {
1432                     match = false;
1433                     break;
1434                 }
1435             }
1436 
1437             if (match)
1438             {
1439                 primitiveOK = true;
1440                 break;
1441             }
1442         }
1443 
1444         if (!primitiveOK)
1445         {
1446             // Log error.
1447             std::ostringstream err;
1448             err << "Primitive " << primIdx << " failed: expected rotation of [";
1449             for (size_t i = 0; i < verticesPerPrimitive; ++i)
1450                 err << ((i > 0) ? ", " : "") << referencePrim[i];
1451             err << "] but found [";
1452             for (size_t i = 0; i < verticesPerPrimitive; ++i)
1453                 err << ((i > 0) ? ", " : "") << resultPrim[i];
1454             err << "]; threshold: " << threshold;
1455             errors.push_back(err.str());
1456         }
1457     }
1458 
1459     return errors;
1460 }
1461 
checkErrorVec(tcu::TestLog & log,const std::vector<std::string> & errors)1462 void checkErrorVec(tcu::TestLog &log, const std::vector<std::string> &errors)
1463 {
1464     if (!errors.empty())
1465     {
1466         for (const auto &err : errors)
1467             log << tcu::TestLog::Message << err << tcu::TestLog::EndMessage;
1468         TCU_FAIL("Vertex data verification failed; check log for details");
1469     }
1470 }
1471 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes)1472 void TransformFeedbackWindingOrderTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
1473                                                                               const MovePtr<Allocation> &bufAlloc,
1474                                                                               const uint32_t bufBytes)
1475 {
1476     const DeviceInterface &vk         = deviceHelper.getDeviceInterface();
1477     const VkDevice device             = deviceHelper.getDevice();
1478     const uint32_t numPoints          = static_cast<uint32_t>(bufBytes / sizeof(uint32_t));
1479     const uint32_t vertexPerPrimitive = m_tParameters.vertexPerPrimitive;
1480     const uint32_t numPrimitives      = numPoints / vertexPerPrimitive;
1481     const uint32_t *tfData            = getInvalidatedHostPtr<uint32_t>(vk, device, *bufAlloc);
1482 
1483     std::vector<uint32_t> referenceValues;
1484     referenceValues.reserve(numPrimitives * vertexPerPrimitive);
1485 
1486     for (uint32_t primIdx = 0; primIdx < numPrimitives; ++primIdx)
1487     {
1488         const auto expectedValues = m_tParameters.getExpectedValuesForPrimitive(primIdx);
1489         for (const auto &value : expectedValues)
1490             referenceValues.push_back(value);
1491     }
1492 
1493     const auto errors =
1494         verifyVertexDataWithWinding(referenceValues, tfData, numPoints, vertexPerPrimitive, 0u /*threshold*/);
1495     checkErrorVec(m_context.getTestContext().getLog(), errors);
1496 }
1497 
1498 class TransformFeedbackBuiltinTestInstance : public TransformFeedbackTestInstance
1499 {
1500 public:
1501     TransformFeedbackBuiltinTestInstance(Context &context, const TestParameters &parameters);
1502 
1503 protected:
1504     tcu::TestStatus iterate(void);
1505     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
1506                                        const VkDeviceSize offset, const uint32_t bufBytes,
1507                                        const uint32_t onePeriodicity);
1508 };
1509 
TransformFeedbackBuiltinTestInstance(Context & context,const TestParameters & parameters)1510 TransformFeedbackBuiltinTestInstance::TransformFeedbackBuiltinTestInstance(Context &context,
1511                                                                            const TestParameters &parameters)
1512     : TransformFeedbackTestInstance(context, parameters)
1513 {
1514     const InstanceInterface &vki            = m_context.getInstanceInterface();
1515     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
1516     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
1517 
1518     const uint32_t tfBuffersSupported = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1519     const uint32_t tfBuffersRequired  = m_parameters.partCount;
1520 
1521     if ((m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE || m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) &&
1522         !features.shaderClipDistance)
1523         TCU_THROW(NotSupportedError, std::string("shaderClipDistance feature is not supported"));
1524     if ((m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE || m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) &&
1525         !features.shaderCullDistance)
1526         TCU_THROW(NotSupportedError, std::string("shaderCullDistance feature is not supported"));
1527     if (tfBuffersSupported < tfBuffersRequired)
1528         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
1529                                                  ", while test requires " + de::toString(tfBuffersRequired))
1530                                          .c_str());
1531 }
1532 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const VkDeviceSize offset,const uint32_t bufBytes,const uint32_t onePeriodicity)1533 void TransformFeedbackBuiltinTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
1534                                                                          const MovePtr<Allocation> &bufAlloc,
1535                                                                          const VkDeviceSize offset,
1536                                                                          const uint32_t bufBytes,
1537                                                                          const uint32_t onePeriodicity)
1538 {
1539     const DeviceInterface &vk  = deviceHelper.getDeviceInterface();
1540     const VkDevice device      = deviceHelper.getDevice();
1541     const uint32_t numPoints   = bufBytes / static_cast<uint32_t>(sizeof(float));
1542     const uint8_t *tfDataBytes = getInvalidatedHostPtr<uint8_t>(vk, device, *bufAlloc);
1543     const float *tfData        = (float *)&tfDataBytes[offset];
1544 
1545     for (uint32_t i = 0; i < numPoints; ++i)
1546     {
1547         // onePeriodicity, when different from zero, indicates the periodic position of a 1.0 value in the results buffer. This is
1548         // typically used when we need to emit a PointSize value together with other interesting data to the XFB buffer.
1549         const bool isOne       = (onePeriodicity > 0u && (i % onePeriodicity == onePeriodicity - 1u));
1550         const uint32_t divisor = 32768u;
1551         const float epsilon    = (isOne ? 0.0f : 1.0f / float(divisor));
1552         const float expected   = (isOne ? 1.0f : float(i) / float(divisor));
1553 
1554         if (deAbs(tfData[i] - expected) > epsilon)
1555             TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) +
1556                      " expected:" + de::toString(expected));
1557     }
1558 }
1559 
iterate(void)1560 tcu::TestStatus TransformFeedbackBuiltinTestInstance::iterate(void)
1561 {
1562     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
1563     const auto &vki                 = m_context.getInstanceInterface();
1564     const auto physicalDevice       = m_context.getPhysicalDevice();
1565     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
1566     const VkDevice device           = deviceHelper.getDevice();
1567     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
1568     const VkQueue queue             = deviceHelper.getQueue();
1569     Allocator &allocator            = deviceHelper.getAllocator();
1570 
1571     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1572     const ShaderWrapper kNullModule;
1573     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1574     const Unique<VkFramebuffer> framebuffer(
1575         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1576     const auto &pipelineLayout(
1577         TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
1578     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
1579                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
1580                                              vertexModule, kNullModule, kNullModule, kNullModule, kNullModule,
1581                                              m_imageExtent2D, 0u, &m_parameters.streamId));
1582     const Unique<VkCommandPool> cmdPool(
1583         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1584     const Unique<VkCommandBuffer> cmdBuffer(
1585         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1586 
1587     const VkDeviceSize tfBufSize             = m_parameters.bufferSize * m_parameters.partCount;
1588     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
1589         tfBufSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1590     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
1591     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1592     const MovePtr<Allocation> tfBufAllocation =
1593         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1594     const VkMemoryBarrier tfMemoryBarrier =
1595         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1596     const std::vector<VkDeviceSize> tfBufBindingSizes =
1597         std::vector<VkDeviceSize>(m_parameters.partCount, m_parameters.bufferSize);
1598     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
1599     const uint32_t perVertexDataSize =
1600         (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)     ? static_cast<uint32_t>(1u * sizeof(float)) :
1601         (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)  ? static_cast<uint32_t>(8u * sizeof(float)) :
1602         (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)  ? static_cast<uint32_t>(8u * sizeof(float)) :
1603         (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ? static_cast<uint32_t>(6u * sizeof(float)) :
1604                                                                  0u;
1605     const bool pointSizeWanted    = m_parameters.pointSizeWanted();
1606     const uint32_t onePeriodicity = (pointSizeWanted && m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)  ? 8u :
1607                                     (pointSizeWanted && m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)  ? 8u :
1608                                     (pointSizeWanted && m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ? 6u :
1609                                                                                                                 0u;
1610     const uint32_t numPoints      = m_parameters.bufferSize / perVertexDataSize;
1611 
1612     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1613 
1614     beginCommandBuffer(vk, *cmdBuffer);
1615     {
1616         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1617         {
1618             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1619 
1620             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, m_parameters.partCount, &tfBufArray[0],
1621                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1622 
1623             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1624             {
1625                 vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
1626             }
1627             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1628         }
1629         endRenderPass(vk, *cmdBuffer);
1630 
1631         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1632                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1633     }
1634     endCommandBuffer(vk, *cmdBuffer);
1635     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1636 
1637     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, tfBufBindingOffsets[m_parameters.partCount - 1],
1638                                   numPoints * perVertexDataSize, onePeriodicity);
1639 
1640     return tcu::TestStatus::pass("Pass");
1641 }
1642 
1643 class TransformFeedbackDepthClipControlTestInstance : public TransformFeedbackTestInstance
1644 {
1645 public:
1646     TransformFeedbackDepthClipControlTestInstance(Context &context, const TestParameters &parameters);
1647 
1648 protected:
1649     uint32_t getFloatsPerVertex(void) const;
1650     uint32_t getActualBufferSize(void) const;
1651     tcu::TestStatus iterate(void);
1652     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
1653                                        const VkDeviceSize offset, const uint32_t bufBytes);
1654 };
1655 
TransformFeedbackDepthClipControlTestInstance(Context & context,const TestParameters & parameters)1656 TransformFeedbackDepthClipControlTestInstance::TransformFeedbackDepthClipControlTestInstance(
1657     Context &context, const TestParameters &parameters)
1658     : TransformFeedbackTestInstance(context, parameters)
1659 {
1660     const InstanceInterface &vki            = m_context.getInstanceInterface();
1661     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
1662     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
1663 
1664     const uint32_t tfBuffersSupported = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1665     const uint32_t tfBuffersRequired  = m_parameters.partCount;
1666 
1667     if (!context.isDeviceFunctionalitySupported("VK_EXT_depth_clip_control"))
1668         TCU_THROW(NotSupportedError, "VK_EXT_depth_clip_control is not supported");
1669 
1670     if (parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY && !features.geometryShader)
1671         TCU_THROW(NotSupportedError, "Geometry shader not supported");
1672 
1673     if (parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE && !features.tessellationShader)
1674         TCU_THROW(NotSupportedError, "Tessellation shader not supported");
1675 
1676     if (tfBuffersSupported < tfBuffersRequired)
1677         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
1678                                                  ", while test requires " + de::toString(tfBuffersRequired))
1679                                          .c_str());
1680 }
1681 
getFloatsPerVertex(void) const1682 uint32_t TransformFeedbackDepthClipControlTestInstance::getFloatsPerVertex(void) const
1683 {
1684     return (m_parameters.pointSizeWanted() ?
1685                 5u :
1686                 4u); // 4 for position, 1 for pointsize in some cases. Needs to match shaders.
1687 }
1688 
getActualBufferSize(void) const1689 uint32_t TransformFeedbackDepthClipControlTestInstance::getActualBufferSize(void) const
1690 {
1691     if (m_parameters.testType != TEST_TYPE_DEPTH_CLIP_CONTROL_TESE || !m_parameters.pointSizeWanted())
1692         return m_parameters.bufferSize;
1693 
1694     // For cases using tesellation and point size, we want the same number of points in the PointSize and the non-PointSize case,
1695     // which means the buffer size has to change a bit, and we'll consider the buffer size indicated in the test parameters as a
1696     // reference to calculate the number of points in the non-PointSize case. For PointSize cases we'll calculate the actual buffer
1697     // size based on the target number of points and the amount of data used by each one, reversing the usual test logic.
1698 
1699     // These have to match shader code.
1700     const auto floatsPerVertexNoPointSize = 4u;
1701     const auto floatsPerVertexPointSize   = 5u;
1702     const auto vertexSizeNoPointSize      = static_cast<uint32_t>(sizeof(float)) * floatsPerVertexNoPointSize;
1703     const auto vertexSizePointSize        = static_cast<uint32_t>(sizeof(float)) * floatsPerVertexPointSize;
1704 
1705     const auto numVertices      = m_parameters.bufferSize / vertexSizeNoPointSize;
1706     const auto actualBufferSize = numVertices * vertexSizePointSize;
1707 
1708     return actualBufferSize;
1709 }
1710 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const VkDeviceSize offset,const uint32_t bufBytes)1711 void TransformFeedbackDepthClipControlTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
1712                                                                                   const MovePtr<Allocation> &bufAlloc,
1713                                                                                   const VkDeviceSize offset,
1714                                                                                   const uint32_t bufBytes)
1715 {
1716     const DeviceInterface &vk  = deviceHelper.getDeviceInterface();
1717     const VkDevice device      = deviceHelper.getDevice();
1718     const uint32_t flPerVertex = getFloatsPerVertex();
1719     const uint32_t numVertices = bufBytes / static_cast<uint32_t>(sizeof(float) * flPerVertex);
1720     const uint8_t *tfDataBytes = getInvalidatedHostPtr<uint8_t>(vk, device, *bufAlloc);
1721     const float *tfData        = (float *)&tfDataBytes[offset];
1722     std::vector<float> result;
1723 
1724     // We only care about the depth (z) value.
1725     for (uint32_t i = 0; i < numVertices; i++)
1726         result.push_back(tfData[i * flPerVertex + 2]);
1727 
1728     // Tessellation generates triangles whose vertex data might be written into
1729     // transform feedback buffer in a different order than generated by the vertex
1730     // shader. Sort the values here to allow comparison.
1731     if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
1732     {
1733         std::sort(result.begin(), result.end());
1734     }
1735 
1736     // Verify the vertex depth values match with the ones written by the shader.
1737     for (uint32_t i = 0; i < numVertices; i++)
1738     {
1739         const float expected = (float)i / 3.0f - 1.0f;
1740         const float epsilon  = 0.0001f;
1741 
1742         if (deAbs(result[i] - expected) > epsilon)
1743             TCU_FAIL(std::string("Failed at vertex ") + de::toString(i) +
1744                      " depth. Received:" + de::toString(result[i]) + " expected:" + de::toString(expected));
1745     }
1746 }
1747 
iterate(void)1748 tcu::TestStatus TransformFeedbackDepthClipControlTestInstance::iterate(void)
1749 {
1750     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
1751     const auto &vki                 = m_context.getInstanceInterface();
1752     const auto physicalDevice       = m_context.getPhysicalDevice();
1753     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
1754     const VkDevice device           = deviceHelper.getDevice();
1755     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
1756     const VkQueue queue             = deviceHelper.getQueue();
1757     Allocator &allocator            = deviceHelper.getAllocator();
1758 
1759     const ShaderWrapper kNullModule;
1760     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1761     ShaderWrapper geomModule;
1762     ShaderWrapper tescModule;
1763     ShaderWrapper teseModule;
1764     const bool hasGeomShader   = m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY;
1765     const bool hasTessellation = m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE;
1766 
1767     if (hasGeomShader)
1768         geomModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
1769 
1770     if (hasTessellation)
1771     {
1772         tescModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tesc"), 0u);
1773         teseModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tese"), 0u);
1774     }
1775 
1776     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1777     const Unique<VkFramebuffer> framebuffer(
1778         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1779     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
1780     const auto pipeline(makeGraphicsPipeline(
1781         m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
1782         *pipelineLayout, *renderPass, vertexModule, tescModule, teseModule, geomModule, kNullModule, m_imageExtent2D,
1783         0u, &m_parameters.streamId, m_parameters.primTopology, false, true));
1784     const Unique<VkCommandPool> cmdPool(
1785         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1786     const Unique<VkCommandBuffer> cmdBuffer(
1787         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1788     const auto bufferSizeParam               = getActualBufferSize();
1789     const VkDeviceSize tfBufSize             = bufferSizeParam * m_parameters.partCount;
1790     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
1791         tfBufSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1792     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
1793     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1794     const MovePtr<Allocation> tfBufAllocation =
1795         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1796     const VkMemoryBarrier tfMemoryBarrier =
1797         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1798     const std::vector<VkDeviceSize> tfBufBindingSizes =
1799         std::vector<VkDeviceSize>(m_parameters.partCount, bufferSizeParam);
1800     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
1801     const uint32_t floatsPerVertex                      = getFloatsPerVertex();
1802     const uint32_t perVertexDataSize                    = static_cast<uint32_t>(floatsPerVertex * sizeof(float));
1803     const uint32_t numVertices                          = bufferSizeParam / perVertexDataSize;
1804 
1805     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1806 
1807     beginCommandBuffer(vk, *cmdBuffer);
1808     {
1809         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1810         {
1811             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1812 
1813             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, m_parameters.partCount, &tfBufArray[0],
1814                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1815 
1816             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1817             {
1818                 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
1819             }
1820             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1821         }
1822         endRenderPass(vk, *cmdBuffer);
1823 
1824         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1825                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1826     }
1827     endCommandBuffer(vk, *cmdBuffer);
1828     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1829 
1830     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, tfBufBindingOffsets[m_parameters.partCount - 1],
1831                                   bufferSizeParam);
1832 
1833     return tcu::TestStatus::pass("Pass");
1834 }
1835 
1836 class TransformFeedbackMultistreamTestInstance : public TransformFeedbackTestInstance
1837 {
1838 public:
1839     TransformFeedbackMultistreamTestInstance(Context &context, const TestParameters &parameters);
1840 
1841 protected:
1842     std::vector<VkDeviceSize> generateSizesList(const size_t bufBytes, const size_t chunkCount);
1843     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
1844                                        const uint32_t bufBytes);
1845     tcu::TestStatus iterate(void);
1846 };
1847 
TransformFeedbackMultistreamTestInstance(Context & context,const TestParameters & parameters)1848 TransformFeedbackMultistreamTestInstance::TransformFeedbackMultistreamTestInstance(Context &context,
1849                                                                                    const TestParameters &parameters)
1850     : TransformFeedbackTestInstance(context, parameters)
1851 {
1852     const InstanceInterface &vki            = m_context.getInstanceInterface();
1853     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
1854     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
1855     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
1856         m_context.getTransformFeedbackFeaturesEXT();
1857     const uint32_t streamsSupported            = m_transformFeedbackProperties.maxTransformFeedbackStreams;
1858     const uint32_t streamsRequired             = m_parameters.streamId + 1;
1859     const uint32_t tfBuffersSupported          = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1860     const uint32_t tfBuffersRequired           = m_parameters.partCount;
1861     const uint32_t bytesPerVertex              = m_parameters.bufferSize / m_parameters.partCount;
1862     const uint32_t tfStreamDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
1863     const uint32_t tfBufferDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
1864     const uint32_t tfBufferDataStrideSupported = m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
1865 
1866     DE_ASSERT(m_parameters.partCount == 2u);
1867 
1868     if (!features.geometryShader)
1869         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
1870 
1871     if (transformFeedbackFeatures.geometryStreams == false)
1872         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
1873 
1874     if (streamsSupported < streamsRequired)
1875         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
1876                                                  ", while test requires " + de::toString(streamsRequired))
1877                                          .c_str());
1878 
1879     if (tfBuffersSupported < tfBuffersRequired)
1880         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
1881                                                  ", while test requires " + de::toString(tfBuffersRequired))
1882                                          .c_str());
1883 
1884     if (tfStreamDataSizeSupported < bytesPerVertex)
1885         TCU_THROW(NotSupportedError,
1886                   std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) +
1887                               ", while test requires " + de::toString(bytesPerVertex))
1888                       .c_str());
1889 
1890     if (tfBufferDataSizeSupported < bytesPerVertex)
1891         TCU_THROW(NotSupportedError,
1892                   std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) +
1893                               ", while test requires " + de::toString(bytesPerVertex))
1894                       .c_str());
1895 
1896     if (tfBufferDataStrideSupported < bytesPerVertex)
1897         TCU_THROW(NotSupportedError,
1898                   std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) +
1899                               ", while test requires " + de::toString(bytesPerVertex))
1900                       .c_str());
1901 }
1902 
generateSizesList(const size_t bufBytes,const size_t chunkCount)1903 std::vector<VkDeviceSize> TransformFeedbackMultistreamTestInstance::generateSizesList(const size_t bufBytes,
1904                                                                                       const size_t chunkCount)
1905 {
1906     const VkDeviceSize chunkSize = bufBytes / chunkCount;
1907     std::vector<VkDeviceSize> result(chunkCount, chunkSize);
1908 
1909     DE_ASSERT(chunkSize * chunkCount == bufBytes);
1910     DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
1911     DE_ASSERT(bufBytes % sizeof(uint32_t) == 0);
1912     DE_ASSERT(chunkCount > 0);
1913     DE_ASSERT(result.size() == chunkCount);
1914 
1915     return result;
1916 }
1917 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes)1918 void TransformFeedbackMultistreamTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
1919                                                                              const MovePtr<Allocation> &bufAlloc,
1920                                                                              const uint32_t bufBytes)
1921 {
1922     const DeviceInterface &vk = deviceHelper.getDeviceInterface();
1923     const VkDevice device     = deviceHelper.getDevice();
1924     const uint32_t numPoints  = static_cast<uint32_t>(bufBytes / sizeof(uint32_t));
1925     const float *tfData       = getInvalidatedHostPtr<float>(vk, device, *bufAlloc);
1926 
1927     for (uint32_t i = 0; i < numPoints; ++i)
1928         if (tfData[i] != float(i))
1929             TCU_FAIL(std::string("Failed at item ") + de::toString(float(i)) + " received:" + de::toString(tfData[i]) +
1930                      " expected:" + de::toString(i));
1931 }
1932 
iterate(void)1933 tcu::TestStatus TransformFeedbackMultistreamTestInstance::iterate(void)
1934 {
1935     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
1936     const auto &vki                 = m_context.getInstanceInterface();
1937     const auto physicalDevice       = m_context.getPhysicalDevice();
1938     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
1939     const VkDevice device           = deviceHelper.getDevice();
1940     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
1941     const VkQueue queue             = deviceHelper.getQueue();
1942     Allocator &allocator            = deviceHelper.getAllocator();
1943 
1944     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1945 
1946     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1947     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
1948     const ShaderWrapper kNullModule;
1949 
1950     const Unique<VkFramebuffer> framebuffer(
1951         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1952     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
1953     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
1954                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
1955                                              vertexModule, kNullModule, kNullModule, geomModule, kNullModule,
1956                                              m_imageExtent2D, 0u));
1957     const Unique<VkCommandPool> cmdPool(
1958         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1959     const Unique<VkCommandBuffer> cmdBuffer(
1960         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1961 
1962     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
1963         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1964     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
1965     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1966     const MovePtr<Allocation> tfBufAllocation =
1967         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1968     const VkMemoryBarrier tfMemoryBarrier =
1969         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1970     const std::vector<VkDeviceSize> tfBufBindingSizes =
1971         generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
1972     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
1973 
1974     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1975 
1976     beginCommandBuffer(vk, *cmdBuffer);
1977     {
1978         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1979         {
1980             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
1981 
1982             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0],
1983                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1984 
1985             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1986             {
1987                 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
1988             }
1989             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1990         }
1991         endRenderPass(vk, *cmdBuffer);
1992 
1993         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1994                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1995     }
1996     endCommandBuffer(vk, *cmdBuffer);
1997     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1998 
1999     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
2000 
2001     return tcu::TestStatus::pass("Pass");
2002 }
2003 
2004 class TransformFeedbackMultistreamSameLocationTestInstance final : public TransformFeedbackTestInstance
2005 {
2006 public:
2007     TransformFeedbackMultistreamSameLocationTestInstance(Context &context, const TestParameters &parameters);
2008 
2009 protected:
2010     tcu::TestStatus iterate(void) override;
2011     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
2012                                        uint32_t bufBytes);
2013 };
2014 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes)2015 void TransformFeedbackMultistreamSameLocationTestInstance::verifyTransformFeedbackBuffer(
2016     const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc, const uint32_t bufBytes)
2017 {
2018     const DeviceInterface &vk = deviceHelper.getDeviceInterface();
2019     const VkDevice device     = deviceHelper.getDevice();
2020     const auto numPoints      = static_cast<uint32_t>(bufBytes / sizeof(uint32_t));
2021     const auto *tuData        = getInvalidatedHostPtr<uint32_t>(vk, device, *bufAlloc);
2022 
2023     for (uint32_t i = 0; i < numPoints; ++i)
2024         if (tuData[i] != i * 2 - ((i / 16) == 0 ? 0 : 31))
2025             TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tuData[i]) +
2026                      " expected:" + de::toString(i));
2027 
2028     return;
2029 }
2030 
TransformFeedbackMultistreamSameLocationTestInstance(Context & context,const TestParameters & parameters)2031 TransformFeedbackMultistreamSameLocationTestInstance::TransformFeedbackMultistreamSameLocationTestInstance(
2032     Context &context, const TestParameters &parameters)
2033     : TransformFeedbackTestInstance(context, parameters)
2034 {
2035     const InstanceInterface &vki            = m_context.getInstanceInterface();
2036     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
2037     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
2038     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
2039         m_context.getTransformFeedbackFeaturesEXT();
2040     const uint32_t streamsSupported            = m_transformFeedbackProperties.maxTransformFeedbackStreams;
2041     const uint32_t streamsRequired             = m_parameters.streamId + 1;
2042     const uint32_t tfBuffersSupported          = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
2043     const uint32_t tfBuffersRequired           = 1;
2044     const uint32_t bytesPerVertex              = 4;
2045     const uint32_t tfStreamDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
2046     const uint32_t tfBufferDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
2047     const uint32_t tfBufferDataStrideSupported = m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
2048 
2049     if (!features.geometryShader)
2050         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2051 
2052     if (transformFeedbackFeatures.geometryStreams == false)
2053         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2054 
2055     if (streamsSupported < streamsRequired)
2056         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
2057                                                  ", while test requires " + de::toString(streamsRequired))
2058                                          .c_str());
2059 
2060     if (tfBuffersSupported < tfBuffersRequired)
2061         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
2062                                                  ", while test requires " + de::toString(tfBuffersRequired))
2063                                          .c_str());
2064 
2065     if (tfStreamDataSizeSupported < bytesPerVertex)
2066         TCU_THROW(NotSupportedError,
2067                   std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) +
2068                               ", while test requires " + de::toString(bytesPerVertex))
2069                       .c_str());
2070 
2071     if (tfBufferDataSizeSupported < bytesPerVertex)
2072         TCU_THROW(NotSupportedError,
2073                   std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) +
2074                               ", while test requires " + de::toString(bytesPerVertex))
2075                       .c_str());
2076 
2077     if (tfBufferDataStrideSupported < bytesPerVertex)
2078         TCU_THROW(NotSupportedError,
2079                   std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) +
2080                               ", while test requires " + de::toString(bytesPerVertex))
2081                       .c_str());
2082 }
2083 
iterate(void)2084 tcu::TestStatus TransformFeedbackMultistreamSameLocationTestInstance::iterate(void)
2085 {
2086     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
2087     const auto &vki                 = m_context.getInstanceInterface();
2088     const auto physicalDevice       = m_context.getPhysicalDevice();
2089     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
2090     const VkDevice device           = deviceHelper.getDevice();
2091     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
2092     const VkQueue queue             = deviceHelper.getQueue();
2093     Allocator &allocator            = deviceHelper.getAllocator();
2094 
2095     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
2096 
2097     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
2098     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
2099     const ShaderWrapper kNullModule;
2100 
2101     const Unique<VkFramebuffer> framebuffer(
2102         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2103     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
2104     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
2105                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
2106                                              vertexModule, kNullModule, kNullModule, geomModule, kNullModule,
2107                                              m_imageExtent2D, 0u));
2108     const Unique<VkCommandPool> cmdPool(
2109         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2110     const Unique<VkCommandBuffer> cmdBuffer(
2111         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2112 
2113     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
2114         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2115     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
2116     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
2117     const MovePtr<Allocation> tfBufAllocation =
2118         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2119     const VkMemoryBarrier tfMemoryBarrier =
2120         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2121     const std::vector<VkDeviceSize> tfBufBindingSizes   = {m_parameters.bufferSize / 2, m_parameters.bufferSize / 2};
2122     const std::vector<VkDeviceSize> tfBufBindingOffsets = {0, m_parameters.bufferSize / 2};
2123 
2124     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2125 
2126     beginCommandBuffer(vk, *cmdBuffer);
2127     {
2128         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2129         {
2130             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
2131 
2132             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0],
2133                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
2134 
2135             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2136             {
2137                 vk.cmdDraw(*cmdBuffer, 16u, 1u, 0u, 0u);
2138             }
2139             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2140         }
2141         endRenderPass(vk, *cmdBuffer);
2142 
2143         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
2144                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2145     }
2146     endCommandBuffer(vk, *cmdBuffer);
2147     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2148 
2149     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
2150 
2151     return tcu::TestStatus::pass("Pass");
2152 }
2153 
2154 class TransformFeedbackStreamsTestInstance : public TransformFeedbackTestInstance
2155 {
2156 public:
2157     TransformFeedbackStreamsTestInstance(Context &context, const TestParameters &parameters);
2158 
2159 protected:
2160     tcu::TestStatus iterate(void);
2161     bool verifyImage(const VkFormat imageFormat, const VkExtent2D &size, const void *resultData);
2162 };
2163 
TransformFeedbackStreamsTestInstance(Context & context,const TestParameters & parameters)2164 TransformFeedbackStreamsTestInstance::TransformFeedbackStreamsTestInstance(Context &context,
2165                                                                            const TestParameters &parameters)
2166     : TransformFeedbackTestInstance(context, parameters)
2167 {
2168     const InstanceInterface &vki            = m_context.getInstanceInterface();
2169     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
2170     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
2171     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
2172         m_context.getTransformFeedbackFeaturesEXT();
2173     const uint32_t streamsSupported  = m_transformFeedbackProperties.maxTransformFeedbackStreams;
2174     const uint32_t streamsRequired   = m_parameters.streamId + 1;
2175     const bool geomPointSizeRequired = m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE;
2176 
2177     if (!features.geometryShader)
2178         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2179 
2180     if (transformFeedbackFeatures.geometryStreams == false)
2181         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2182 
2183     if (streamsSupported < streamsRequired)
2184         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
2185                                                  ", while test requires " + de::toString(streamsRequired))
2186                                          .c_str());
2187 
2188     if (geomPointSizeRequired && !features.shaderTessellationAndGeometryPointSize)
2189         TCU_THROW(NotSupportedError, "shaderTessellationAndGeometryPointSize feature is not supported");
2190 }
2191 
verifyImage(const VkFormat imageFormat,const VkExtent2D & size,const void * resultData)2192 bool TransformFeedbackStreamsTestInstance::verifyImage(const VkFormat imageFormat, const VkExtent2D &size,
2193                                                        const void *resultData)
2194 {
2195     const tcu::RGBA magentaRGBA(tcu::RGBA(0xFF, 0x00, 0xFF, 0xFF));
2196     const tcu::Vec4 magenta(magentaRGBA.toVec());
2197     const tcu::Vec4 black(tcu::RGBA::black().toVec());
2198     const tcu::TextureFormat textureFormat(mapVkFormat(imageFormat));
2199     const int dataSize(size.width * size.height * textureFormat.getPixelSize());
2200     tcu::TextureLevel referenceImage(textureFormat, size.width, size.height);
2201     tcu::PixelBufferAccess referenceAccess(referenceImage.getAccess());
2202 
2203     // Generate reference image
2204     if (m_parameters.testType == TEST_TYPE_STREAMS)
2205     {
2206         for (int y = 0; y < referenceImage.getHeight(); ++y)
2207         {
2208             const tcu::Vec4 &validColor = y < referenceImage.getHeight() / 2 ? black : magenta;
2209 
2210             for (int x = 0; x < referenceImage.getWidth(); ++x)
2211                 referenceAccess.setPixel(validColor, x, y);
2212         }
2213     }
2214 
2215     if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE ||
2216         m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
2217     {
2218         for (int y = 0; y < referenceImage.getHeight(); ++y)
2219             for (int x = 0; x < referenceImage.getWidth(); ++x)
2220             {
2221                 const tcu::Vec4 &validColor =
2222                     (y >= referenceImage.getHeight() / 2) && (x >= referenceImage.getWidth() / 2) ? magenta : black;
2223 
2224                 referenceAccess.setPixel(validColor, x, y);
2225             }
2226     }
2227 
2228     if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
2229     {
2230         const int pointSize         = static_cast<int>(m_parameters.pointSize);
2231         const tcu::Vec4 &validColor = black;
2232 
2233         for (int y = 0; y < referenceImage.getHeight(); ++y)
2234             for (int x = 0; x < referenceImage.getWidth(); ++x)
2235                 referenceAccess.setPixel(validColor, x, y);
2236 
2237         referenceAccess.setPixel(magenta, (1 + referenceImage.getWidth()) / 4 - 1,
2238                                  (referenceImage.getHeight() * 3) / 4 - 1);
2239 
2240         for (int y = 0; y < pointSize; ++y)
2241             for (int x = 0; x < pointSize; ++x)
2242                 referenceAccess.setPixel(magenta, x + (referenceImage.getWidth() * 3) / 4 - 1,
2243                                          y + (referenceImage.getHeight() * 3) / 4 - 1);
2244     }
2245 
2246     if (deMemCmp(resultData, referenceAccess.getDataPtr(), dataSize) != 0)
2247     {
2248         const tcu::ConstPixelBufferAccess resultImage(textureFormat, size.width, size.height, 1, resultData);
2249         bool ok;
2250 
2251         ok = tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Image comparison", "", referenceAccess,
2252                                       resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
2253 
2254         return ok;
2255     }
2256 
2257     return true;
2258 }
2259 
iterate(void)2260 tcu::TestStatus TransformFeedbackStreamsTestInstance::iterate(void)
2261 {
2262     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
2263     const auto &vki                 = m_context.getInstanceInterface();
2264     const auto physicalDevice       = m_context.getPhysicalDevice();
2265     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
2266     const VkDevice device           = deviceHelper.getDevice();
2267     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
2268     const VkQueue queue             = deviceHelper.getQueue();
2269     Allocator &allocator            = deviceHelper.getAllocator();
2270 
2271     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_R8G8B8A8_UNORM));
2272 
2273     const ShaderWrapper vertModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
2274     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
2275     const ShaderWrapper fragModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
2276     const ShaderWrapper kNullModule;
2277 
2278     const VkFormat colorFormat              = VK_FORMAT_R8G8B8A8_UNORM;
2279     const VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2280     const tcu::RGBA clearColor(tcu::RGBA::black());
2281     const VkImageSubresourceRange colorSubresRange(
2282         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2283     const VkDeviceSize colorBufferSize(m_imageExtent2D.width * m_imageExtent2D.height *
2284                                        tcu::getPixelSize(mapVkFormat(colorFormat)));
2285     const Unique<VkImage> colorImage(makeImage(
2286         vk, device, makeImageCreateInfo(0u, VK_IMAGE_TYPE_2D, colorFormat, m_imageExtent2D, 1u, imageUsageFlags)));
2287     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
2288     const Unique<VkImageView> colorAttachment(
2289         makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresRange));
2290     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
2291     const UniquePtr<Allocation> colorBufferAlloc(
2292         bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
2293 
2294     const Unique<VkFramebuffer> framebuffer(
2295         makeFramebuffer(vk, device, *renderPass, *colorAttachment, m_imageExtent2D.width, m_imageExtent2D.height));
2296     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
2297     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
2298                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass, vertModule,
2299                                              kNullModule, kNullModule, geomModule, fragModule, m_imageExtent2D, 0u,
2300                                              &m_parameters.streamId, m_parameters.primTopology, false, false, 1u));
2301     const Unique<VkCommandPool> cmdPool(
2302         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2303     const Unique<VkCommandBuffer> cmdBuffer(
2304         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2305 
2306     const VkImageMemoryBarrier preCopyBarrier = makeImageMemoryBarrier(
2307         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2308         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorImage, colorSubresRange);
2309     const VkBufferImageCopy region =
2310         makeBufferImageCopy(makeExtent3D(m_imageExtent2D.width, m_imageExtent2D.height, 1u),
2311                             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
2312     const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
2313         VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, VK_WHOLE_SIZE);
2314 
2315     beginCommandBuffer(vk, *cmdBuffer);
2316     {
2317         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D), clearColor.toVec());
2318         {
2319             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
2320 
2321             vk.cmdDraw(*cmdBuffer, 2u, 1u, 0u, 0u);
2322         }
2323         endRenderPass(vk, *cmdBuffer);
2324 
2325         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
2326                               0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier);
2327         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u,
2328                                 &region);
2329         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL,
2330                               1u, &postCopyBarrier, DE_NULL, 0u);
2331 
2332         invalidateAlloc(vk, device, *colorBufferAlloc);
2333     }
2334     endCommandBuffer(vk, *cmdBuffer);
2335     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2336 
2337     if (!verifyImage(colorFormat, m_imageExtent2D, colorBufferAlloc->getHostPtr()))
2338         return tcu::TestStatus::fail("Fail");
2339 
2340     return tcu::TestStatus::pass("Pass");
2341 }
2342 
2343 class TransformFeedbackIndirectDrawTestInstance : public TransformFeedbackTestInstance
2344 {
2345 public:
2346     TransformFeedbackIndirectDrawTestInstance(Context &context, const TestParameters &parameters, bool multiview);
2347 
2348 protected:
2349     tcu::TestStatus iterate(void);
2350     bool verifyImage(const VkFormat imageFormat, const VkExtent2D &size, const void *resultData,
2351                      uint32_t layerIdx = std::numeric_limits<uint32_t>::max());
2352 
2353     const bool m_multiview;
2354 };
2355 
TransformFeedbackIndirectDrawTestInstance(Context & context,const TestParameters & parameters,bool multiview)2356 TransformFeedbackIndirectDrawTestInstance::TransformFeedbackIndirectDrawTestInstance(Context &context,
2357                                                                                      const TestParameters &parameters,
2358                                                                                      bool multiview)
2359     : TransformFeedbackTestInstance(context, parameters)
2360     , m_multiview(multiview)
2361 {
2362     const InstanceInterface &vki               = m_context.getInstanceInterface();
2363     const VkPhysicalDevice physDevice          = m_context.getPhysicalDevice();
2364     const VkPhysicalDeviceLimits limits        = getPhysicalDeviceProperties(vki, physDevice).limits;
2365     const uint32_t tfBufferDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
2366     const uint32_t tfBufferDataStrideSupported = m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
2367 
2368     if (m_transformFeedbackProperties.transformFeedbackDraw == false)
2369         TCU_THROW(NotSupportedError, "transformFeedbackDraw feature is not supported");
2370 
2371     if (limits.maxVertexInputBindingStride < m_parameters.vertexStride)
2372         TCU_THROW(NotSupportedError,
2373                   std::string("maxVertexInputBindingStride=" + de::toString(limits.maxVertexInputBindingStride) +
2374                               ", while test requires " + de::toString(m_parameters.vertexStride))
2375                       .c_str());
2376 
2377     if (tfBufferDataSizeSupported < m_parameters.vertexStride)
2378         TCU_THROW(NotSupportedError,
2379                   std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) +
2380                               ", while test requires " + de::toString(m_parameters.vertexStride))
2381                       .c_str());
2382 
2383     if (tfBufferDataStrideSupported < m_parameters.vertexStride)
2384         TCU_THROW(NotSupportedError,
2385                   std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) +
2386                               ", while test requires " + de::toString(m_parameters.vertexStride))
2387                       .c_str());
2388 }
2389 
verifyImage(const VkFormat imageFormat,const VkExtent2D & size,const void * resultData,uint32_t layerIdx)2390 bool TransformFeedbackIndirectDrawTestInstance::verifyImage(const VkFormat imageFormat, const VkExtent2D &size,
2391                                                             const void *resultData, uint32_t layerIdx)
2392 {
2393     const tcu::Vec4 white(tcu::RGBA::white().toVec());
2394     const tcu::TextureFormat textureFormat(mapVkFormat(imageFormat));
2395     const int dataSize(size.width * size.height * textureFormat.getPixelSize());
2396     tcu::TextureLevel referenceImage(textureFormat, size.width, size.height);
2397     tcu::PixelBufferAccess referenceAccess(referenceImage.getAccess());
2398     const bool isMultilayer = (layerIdx != std::numeric_limits<uint32_t>::max());
2399     const std::string setName =
2400         "Image comparison" + (isMultilayer ? " (layer " + std::to_string(layerIdx) + ")" : std::string());
2401 
2402     // Generate reference image
2403     for (int y = 0; y < referenceImage.getHeight(); ++y)
2404         for (int x = 0; x < referenceImage.getWidth(); ++x)
2405             referenceAccess.setPixel(white, x, y);
2406 
2407     if (deMemCmp(resultData, referenceAccess.getDataPtr(), dataSize) != 0)
2408     {
2409         const tcu::ConstPixelBufferAccess resultImage(textureFormat, size.width, size.height, 1, resultData);
2410         bool ok;
2411 
2412         ok = tcu::intThresholdCompare(m_context.getTestContext().getLog(), setName.c_str(), "", referenceAccess,
2413                                       resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
2414 
2415         return ok;
2416     }
2417 
2418     return true;
2419 }
2420 
iterate(void)2421 tcu::TestStatus TransformFeedbackIndirectDrawTestInstance::iterate(void)
2422 {
2423     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
2424     const auto &vki                 = m_context.getInstanceInterface();
2425     const auto physicalDevice       = m_context.getPhysicalDevice();
2426     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
2427     const VkDevice device           = deviceHelper.getDevice();
2428     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
2429     const VkQueue queue             = deviceHelper.getQueue();
2430     Allocator &allocator            = deviceHelper.getAllocator();
2431     const uint32_t layerCount       = (m_multiview ? 2u : 1u);
2432     const auto colorViewType        = (layerCount > 1u ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
2433 
2434     // Only used for multiview.
2435     const std::vector<uint32_t> subpassViewMasks{((1u << layerCount) - 1u)};
2436 
2437     const VkRenderPassMultiviewCreateInfo multiviewCreateInfo = {
2438         VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, // VkStructureType sType;
2439         nullptr,                                             // const void* pNext;
2440         de::sizeU32(subpassViewMasks),                       // uint32_t subpassCount;
2441         de::dataOrNull(subpassViewMasks),                    // const uint32_t* pViewMasks;
2442         0u,                                                  // uint32_t dependencyCount;
2443         nullptr,                                             // const int32_t* pViewOffsets;
2444         de::sizeU32(subpassViewMasks),                       // uint32_t correlationMaskCount;
2445         de::dataOrNull(subpassViewMasks),                    // const uint32_t* pCorrelationMasks;
2446     };
2447 
2448     const Unique<VkRenderPass> renderPass(
2449         makeRenderPass(vk, device, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR,
2450                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2451                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2452                        nullptr, (m_multiview ? &multiviewCreateInfo : nullptr)));
2453 
2454     const ShaderWrapper vertModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
2455     const ShaderWrapper fragModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
2456     const ShaderWrapper kNullModule;
2457 
2458     const VkFormat colorFormat              = VK_FORMAT_R8G8B8A8_UNORM;
2459     const VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2460     const tcu::RGBA clearColor(tcu::RGBA::black());
2461     const VkImageSubresourceRange colorSubresRange(
2462         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, layerCount));
2463     const VkDeviceSize layerSize(m_imageExtent2D.width * m_imageExtent2D.height *
2464                                  static_cast<uint32_t>(tcu::getPixelSize(mapVkFormat(colorFormat))));
2465     const VkDeviceSize colorBufferSize(layerSize * layerCount);
2466     const Unique<VkImage> colorImage(makeImage(
2467         vk, device,
2468         makeImageCreateInfo(0u, VK_IMAGE_TYPE_2D, colorFormat, m_imageExtent2D, layerCount, imageUsageFlags)));
2469     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
2470     const Unique<VkImageView> colorAttachment(
2471         makeImageView(vk, device, *colorImage, colorViewType, colorFormat, colorSubresRange));
2472     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
2473     const UniquePtr<Allocation> colorBufferAlloc(
2474         bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
2475 
2476     const uint32_t vertexCount                 = 6u;
2477     const VkDeviceSize vertexBufferSize        = vertexCount * m_parameters.vertexStride;
2478     const VkBufferUsageFlags vertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
2479                                                  VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT |
2480                                                  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
2481     const Unique<VkBuffer> vertexBuffer(makeBuffer(vk, device, vertexBufferSize, vertexBufferUsage));
2482     const UniquePtr<Allocation> vertexBufferAlloc(
2483         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
2484     const VkDeviceSize vertexBufferOffset(0u);
2485     const float vertexBufferVals[] = {
2486         -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f, +1.0f, -1.0f, 0.0f, 1.0f,
2487         -1.0f, +1.0f, 0.0f, 1.0f, +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f,
2488     };
2489 
2490     const uint32_t counterBufferValue           = m_parameters.vertexStride * vertexCount;
2491     const VkDeviceSize counterBufferSize        = sizeof(counterBufferValue);
2492     const VkBufferUsageFlags counterBufferUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
2493                                                   VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT |
2494                                                   VK_BUFFER_USAGE_TRANSFER_DST_BIT;
2495     const Unique<VkBuffer> counterBuffer(makeBuffer(vk, device, counterBufferSize, counterBufferUsage));
2496     const UniquePtr<Allocation> counterBufferAlloc(
2497         bindBuffer(vk, device, allocator, *counterBuffer, MemoryRequirement::HostVisible));
2498 
2499     // Note: for multiview the framebuffer layer count is also 1.
2500     const Unique<VkFramebuffer> framebuffer(
2501         makeFramebuffer(vk, device, *renderPass, *colorAttachment, m_imageExtent2D.width, m_imageExtent2D.height));
2502     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
2503     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
2504                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass, vertModule,
2505                                              kNullModule, kNullModule, kNullModule, fragModule, m_imageExtent2D, 0u,
2506                                              DE_NULL, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, true, false, 1u));
2507     const Unique<VkCommandPool> cmdPool(
2508         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2509     const Unique<VkCommandBuffer> cmdBuffer(
2510         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2511 
2512     const VkImageMemoryBarrier preCopyBarrier = makeImageMemoryBarrier(
2513         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2514         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorImage, colorSubresRange);
2515     const VkBufferImageCopy region =
2516         makeBufferImageCopy(makeExtent3D(m_imageExtent2D.width, m_imageExtent2D.height, 1u),
2517                             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, layerCount));
2518     const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
2519         VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, VK_WHOLE_SIZE);
2520 
2521     fillBuffer(vk, device, *counterBufferAlloc, counterBufferSize, &counterBufferValue, counterBufferSize);
2522     fillBuffer(vk, device, *vertexBufferAlloc, vertexBufferSize, vertexBufferVals, sizeof(vertexBufferVals));
2523 
2524     beginCommandBuffer(vk, *cmdBuffer);
2525     {
2526         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D), clearColor.toVec());
2527         {
2528             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*vertexBuffer, &vertexBufferOffset);
2529 
2530             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
2531 
2532             vk.cmdDrawIndirectByteCountEXT(*cmdBuffer, 1u, 0u, *counterBuffer, 0u, 0u, m_parameters.vertexStride);
2533         }
2534         endRenderPass(vk, *cmdBuffer);
2535 
2536         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
2537                               0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier);
2538         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u,
2539                                 &region);
2540         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL,
2541                               1u, &postCopyBarrier, DE_NULL, 0u);
2542 
2543         invalidateAlloc(vk, device, *colorBufferAlloc);
2544     }
2545     endCommandBuffer(vk, *cmdBuffer);
2546     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2547 
2548     bool fail = false;
2549     for (uint32_t layerIdx = 0u; layerIdx < layerCount; ++layerIdx)
2550     {
2551         const auto dataPtr = reinterpret_cast<uint8_t *>(colorBufferAlloc->getHostPtr()) + layerIdx * layerSize;
2552         if (!verifyImage(colorFormat, m_imageExtent2D, dataPtr))
2553             fail = true;
2554     }
2555 
2556     if (fail)
2557         return tcu::TestStatus::fail("Fail; check log for details");
2558 
2559     return tcu::TestStatus::pass("Pass");
2560 }
2561 
2562 class TransformFeedbackBackwardDependencyTestInstance : public TransformFeedbackTestInstance
2563 {
2564 public:
2565     TransformFeedbackBackwardDependencyTestInstance(Context &context, const TestParameters &parameters);
2566 
2567 protected:
2568     tcu::TestStatus iterate(void);
2569     std::vector<VkDeviceSize> generateSizesList(const size_t bufBytes, const size_t chunkCount);
2570 };
2571 
TransformFeedbackBackwardDependencyTestInstance(Context & context,const TestParameters & parameters)2572 TransformFeedbackBackwardDependencyTestInstance::TransformFeedbackBackwardDependencyTestInstance(
2573     Context &context, const TestParameters &parameters)
2574     : TransformFeedbackTestInstance(context, parameters)
2575 {
2576     if (m_transformFeedbackProperties.transformFeedbackDraw == false)
2577         TCU_THROW(NotSupportedError, "transformFeedbackDraw feature is not supported");
2578 }
2579 
generateSizesList(const size_t bufBytes,const size_t chunkCount)2580 std::vector<VkDeviceSize> TransformFeedbackBackwardDependencyTestInstance::generateSizesList(const size_t bufBytes,
2581                                                                                              const size_t chunkCount)
2582 {
2583     const VkDeviceSize chunkSize = bufBytes / chunkCount;
2584     std::vector<VkDeviceSize> result(chunkCount, chunkSize);
2585 
2586     DE_ASSERT(chunkSize * chunkCount == bufBytes);
2587     DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
2588     DE_ASSERT(bufBytes % sizeof(uint32_t) == 0);
2589     DE_ASSERT(chunkCount > 0);
2590     DE_ASSERT(result.size() == chunkCount);
2591 
2592     return result;
2593 }
2594 
iterate(void)2595 tcu::TestStatus TransformFeedbackBackwardDependencyTestInstance::iterate(void)
2596 {
2597     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
2598     const auto &vki                 = m_context.getInstanceInterface();
2599     const auto physicalDevice       = m_context.getPhysicalDevice();
2600     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
2601     const VkDevice device           = deviceHelper.getDevice();
2602     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
2603     const VkQueue queue             = deviceHelper.getQueue();
2604     Allocator &allocator            = deviceHelper.getAllocator();
2605 
2606     const std::vector<VkDeviceSize> chunkSizesList = generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
2607     const std::vector<VkDeviceSize> chunkOffsetsList = generateOffsetsList(chunkSizesList);
2608 
2609     const uint32_t numPoints = static_cast<uint32_t>(chunkSizesList[0] / sizeof(uint32_t));
2610     const bool indirectDraw  = (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT);
2611 
2612     // Color buffer.
2613     const tcu::IVec3 fbExtent(static_cast<int>(numPoints), 1, 1);
2614     const auto vkExtent = makeExtent3D(fbExtent);
2615     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
2616     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
2617 
2618     const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
2619     const auto colorUsage  = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2620     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2621     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
2622     ImageWithBuffer colorBuffer(vk, device, allocator, vkExtent, colorFormat, colorUsage, VK_IMAGE_TYPE_2D);
2623 
2624     // Must match vertex shader.
2625     struct PushConstants
2626     {
2627         uint32_t startValue;
2628         float width;
2629         float posY;
2630     };
2631 
2632     const auto pcSize = static_cast<uint32_t>(sizeof(PushConstants));
2633     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
2634     const ShaderWrapper fragModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
2635     const ShaderWrapper kNullModule;
2636     const Unique<VkRenderPass> renderPass(TransformFeedback::makeCustomRenderPass(vk, device, colorFormat));
2637     const Unique<VkFramebuffer> framebuffer(
2638         makeFramebuffer(vk, device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height));
2639     const auto pipelineLayout(
2640         TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device, pcSize));
2641     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
2642                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
2643                                              vertexModule, kNullModule, kNullModule, kNullModule, fragModule,
2644                                              makeExtent2D(vkExtent.width, vkExtent.height), 0u, nullptr,
2645                                              VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false, false, 1u));
2646     const Unique<VkCommandPool> cmdPool(
2647         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2648     const Unique<VkCommandBuffer> cmdBuffer(
2649         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2650 
2651     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
2652         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2653     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
2654     const MovePtr<Allocation> tfBufAllocation =
2655         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2656     const VkMemoryBarrier tfMemoryBarrier =
2657         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2658     const VkDeviceSize tfBufBindingSize   = m_parameters.bufferSize;
2659     const VkDeviceSize tfBufBindingOffset = 0ull;
2660 
2661     const size_t tfcBufSize                   = sizeof(uint32_t);
2662     const VkBufferCreateInfo tfcBufCreateInfo = makeBufferCreateInfo(
2663         tfcBufSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
2664     const Move<VkBuffer> tfcBuf = createBuffer(vk, device, &tfcBufCreateInfo);
2665     const MovePtr<Allocation> tfcBufAllocation =
2666         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfcBuf), MemoryRequirement::Any);
2667     const VkDeviceSize tfcBufBindingOffset = 0ull;
2668     const VkMemoryBarrier tfcMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
2669                                                                VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT);
2670 
2671     using BufferWithMemoryPtr = std::unique_ptr<BufferWithMemory>;
2672     BufferWithMemoryPtr indirectBuffer;
2673     VkDeviceSize indirectBufferSize;
2674     VkBufferCreateInfo indirectBufferInfo;
2675     std::vector<VkDrawIndirectCommand> indirectCommands;
2676     const auto indirectStructSize = static_cast<uint32_t>(sizeof(decltype(indirectCommands)::value_type));
2677     const auto indirectStride     = indirectStructSize * 2u; // See below.
2678 
2679     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2680     VK_CHECK(vk.bindBufferMemory(device, *tfcBuf, tfcBufAllocation->getMemory(), tfcBufAllocation->getOffset()));
2681 
2682     DE_ASSERT(m_parameters.partCount == 2u);
2683 
2684     if (indirectDraw)
2685     {
2686         // Prepare indirect commands. The first entry will be used as the count.
2687         // Each subsequent indirect command will be padded with an unused structure.
2688         indirectCommands.reserve(numPoints + 1u);
2689         indirectCommands.push_back(VkDrawIndirectCommand{numPoints, 0u, 0u, 0u});
2690 
2691         for (uint32_t drawIdx = 0u; drawIdx < numPoints; ++drawIdx)
2692         {
2693             indirectCommands.push_back(VkDrawIndirectCommand{1u, 1u, drawIdx, 0u});
2694             indirectCommands.push_back(VkDrawIndirectCommand{0u, 0u, 0u, 0u});
2695         }
2696 
2697         indirectBufferSize = static_cast<VkDeviceSize>(de::dataSize(indirectCommands));
2698         indirectBufferInfo = makeBufferCreateInfo(indirectBufferSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
2699 
2700         indirectBuffer.reset(
2701             new BufferWithMemory(vk, device, allocator, indirectBufferInfo, MemoryRequirement::HostVisible));
2702         auto &indirectBufferAlloc = indirectBuffer->getAllocation();
2703         void *indirectBufferData  = indirectBufferAlloc.getHostPtr();
2704 
2705         deMemcpy(indirectBufferData, de::dataOrNull(indirectCommands), de::dataSize(indirectCommands));
2706         flushAlloc(vk, device, indirectBufferAlloc);
2707     }
2708 
2709     beginCommandBuffer(vk, *cmdBuffer);
2710     {
2711         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
2712         {
2713             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
2714 
2715             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
2716 
2717             {
2718                 const uint32_t startValue = static_cast<uint32_t>(chunkOffsetsList[0] / sizeof(uint32_t));
2719                 const PushConstants pcData{
2720                     startValue, static_cast<float>(vkExtent.width),
2721                     static_cast<float>(10.0f), // Push the points offscreen.
2722                 };
2723 
2724                 vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u, pcSize, &pcData);
2725 
2726                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2727                 {
2728                     if (indirectDraw)
2729                         vk.cmdDrawIndirectCount(*cmdBuffer, indirectBuffer->get(), indirectStructSize,
2730                                                 indirectBuffer->get(), 0u, numPoints, indirectStride);
2731                     else
2732                         vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
2733                 }
2734                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf,
2735                                               m_parameters.noOffsetArray ? DE_NULL : &tfcBufBindingOffset);
2736             }
2737 
2738             if (indirectDraw)
2739             {
2740                 // This should be a no-op but allows us to reset the indirect draw counter in case it could influence the follow-up indirect draw.
2741                 vk.cmdDrawIndirectCount(*cmdBuffer, indirectBuffer->get(), indirectStructSize, indirectBuffer->get(),
2742                                         0u, 0u /*no draws*/, indirectStride);
2743             }
2744 
2745             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
2746                                   VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 1u, &tfcMemoryBarrier, 0u, DE_NULL, DE_NULL,
2747                                   0u);
2748 
2749             {
2750                 const uint32_t startValue = static_cast<uint32_t>(chunkOffsetsList[1] / sizeof(uint32_t));
2751                 const PushConstants pcData{
2752                     startValue, static_cast<float>(vkExtent.width),
2753                     static_cast<float>(0.0f), // Points onscreen in this second draw.
2754                 };
2755 
2756                 vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u, pcSize, &pcData);
2757 
2758                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf,
2759                                                 m_parameters.noOffsetArray ? DE_NULL : &tfcBufBindingOffset);
2760                 {
2761                     vk.cmdDrawIndirectByteCountEXT(*cmdBuffer, 1u, 0u, *tfcBuf, 0u, 0u, 4u);
2762                 }
2763                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2764             }
2765         }
2766         endRenderPass(vk, *cmdBuffer);
2767 
2768         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
2769                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2770     }
2771     copyImageToBuffer(vk, *cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1));
2772     endCommandBuffer(vk, *cmdBuffer);
2773     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2774 
2775     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
2776 
2777     // Verify color buffer, to check vkCmdDrawIndirectByteCountEXT worked.
2778     const auto tcuFormat = mapVkFormat(colorFormat);
2779     tcu::TextureLevel refLevel(tcuFormat, fbExtent.x(), fbExtent.y());
2780     const auto refAccess = refLevel.getAccess();
2781     const auto resAlloc  = colorBuffer.getBufferAllocation();
2782     tcu::ConstPixelBufferAccess resAccess(tcuFormat, fbExtent, resAlloc.getHostPtr());
2783     auto &log = m_context.getTestContext().getLog();
2784     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f);
2785 
2786     tcu::clear(refAccess, geomColor);
2787     invalidateAlloc(vk, device, resAlloc);
2788 
2789     if (!tcu::floatThresholdCompare(log, "Result", "", refAccess, resAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
2790         return tcu::TestStatus::fail("Color buffer contains unexpected results; check log for details");
2791 
2792     return tcu::TestStatus::pass("Pass");
2793 }
2794 
2795 class TransformFeedbackQueryTestInstance : public TransformFeedbackTestInstance
2796 {
2797 public:
2798     TransformFeedbackQueryTestInstance(Context &context, const TestParameters &parameters);
2799 
2800 protected:
2801     tcu::TestStatus iterate(void);
2802 };
2803 
TransformFeedbackQueryTestInstance(Context & context,const TestParameters & parameters)2804 TransformFeedbackQueryTestInstance::TransformFeedbackQueryTestInstance(Context &context,
2805                                                                        const TestParameters &parameters)
2806     : TransformFeedbackTestInstance(context, parameters)
2807 {
2808     const InstanceInterface &vki            = m_context.getInstanceInterface();
2809     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
2810     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
2811     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
2812         m_context.getTransformFeedbackFeaturesEXT();
2813     const uint32_t streamsSupported = m_transformFeedbackProperties.maxTransformFeedbackStreams;
2814     const uint32_t streamsRequired  = m_parameters.streamId + 1;
2815 
2816     if (!features.geometryShader)
2817         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2818 
2819     if (streamsRequired > 1 && transformFeedbackFeatures.geometryStreams == false)
2820         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2821 
2822     if (streamsSupported < streamsRequired)
2823         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
2824                                                  ", while test requires " + de::toString(streamsRequired))
2825                                          .c_str());
2826 
2827     if (m_transformFeedbackProperties.transformFeedbackQueries == false)
2828         TCU_THROW(NotSupportedError, "transformFeedbackQueries feature is not supported");
2829 }
2830 
iterate(void)2831 tcu::TestStatus TransformFeedbackQueryTestInstance::iterate(void)
2832 {
2833     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
2834     const auto &vki                 = m_context.getInstanceInterface();
2835     const auto physicalDevice       = m_context.getPhysicalDevice();
2836     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
2837     const VkDevice device           = deviceHelper.getDevice();
2838     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
2839     const VkQueue queue             = deviceHelper.getQueue();
2840     Allocator &allocator            = deviceHelper.getAllocator();
2841 
2842     const uint64_t overflowVertices    = 3u;
2843     const uint32_t bytesPerVertex      = static_cast<uint32_t>(4 * sizeof(float));
2844     const uint64_t numVerticesInBuffer = m_parameters.bufferSize / bytesPerVertex;
2845     const uint64_t numVerticesToWrite  = numVerticesInBuffer + overflowVertices;
2846     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
2847 
2848     const ShaderWrapper vertModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
2849     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
2850     const ShaderWrapper kNullModule;
2851 
2852     const Unique<VkFramebuffer> framebuffer(
2853         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2854     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
2855     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
2856                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass, vertModule,
2857                                              kNullModule, kNullModule, geomModule, kNullModule, m_imageExtent2D, 0u,
2858                                              &m_parameters.streamId, m_parameters.primTopology));
2859     const Unique<VkCommandPool> cmdPool(
2860         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2861     const Unique<VkCommandBuffer> cmdBuffer(
2862         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2863 
2864     const uint32_t tfBufferSize =
2865         (uint32_t)topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesInBuffer) *
2866         (uint32_t)topologyData.at(m_parameters.primTopology).primSize * bytesPerVertex;
2867     const VkBufferCreateInfo tfBufCreateInfo =
2868         makeBufferCreateInfo(tfBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2869     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
2870     const MovePtr<Allocation> tfBufAllocation =
2871         bindBuffer(vk, device, allocator, *tfBuf, MemoryRequirement::HostVisible);
2872     const VkDeviceSize tfBufBindingSize   = tfBufferSize;
2873     const VkDeviceSize tfBufBindingOffset = 0ull;
2874 
2875     const size_t queryResultWidth                 = (m_parameters.query64bits ? sizeof(uint64_t) : sizeof(uint32_t));
2876     const vk::VkQueryControlFlags queryExtraFlags = (m_parameters.query64bits ? vk::VK_QUERY_RESULT_64_BIT : 0);
2877     const uint32_t queryCountersNumber            = 1u;
2878     const uint32_t queryIndex                     = 0u;
2879     constexpr uint32_t queryResultElements        = 2u;
2880     const uint32_t queryDataSize                  = static_cast<uint32_t>(queryResultElements * queryResultWidth) +
2881                                    (m_parameters.queryResultWithAvailability ? (uint32_t)queryResultWidth : 0u);
2882     const VkQueryPoolCreateInfo queryPoolCreateInfo = makeQueryPoolCreateInfo(queryCountersNumber);
2883     const Unique<VkQueryPool> queryPool(createQueryPool(vk, device, &queryPoolCreateInfo));
2884 
2885     const VkQueryResultFlagBits queryWait =
2886         m_parameters.queryResultWithAvailability ? VK_QUERY_RESULT_WITH_AVAILABILITY_BIT : VK_QUERY_RESULT_WAIT_BIT;
2887 
2888     Move<VkBuffer> queryPoolResultsBuffer;
2889     de::MovePtr<Allocation> queryPoolResultsBufferAlloc;
2890 
2891     tcu::TestLog &log = m_context.getTestContext().getLog();
2892 
2893     DE_ASSERT(numVerticesInBuffer * bytesPerVertex == m_parameters.bufferSize);
2894 
2895     if (m_parameters.testType == TEST_TYPE_QUERY_COPY || m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2896     {
2897         const VkBufferCreateInfo bufferParams = {
2898             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType      sType;
2899             DE_NULL,                              // const void*          pNext;
2900             0u,                                   // VkBufferCreateFlags  flags;
2901             queryDataSize,                        // VkDeviceSize         size;
2902             VK_BUFFER_USAGE_TRANSFER_DST_BIT,     // VkBufferUsageFlags   usage;
2903             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode;
2904             1u,                                   // uint32_t             queueFamilyCount;
2905             &queueFamilyIndex                     // const uint32_t*      pQueueFamilyIndices;
2906         };
2907 
2908         queryPoolResultsBuffer      = createBuffer(vk, device, &bufferParams);
2909         queryPoolResultsBufferAlloc = allocator.allocate(
2910             getBufferMemoryRequirements(vk, device, *queryPoolResultsBuffer), MemoryRequirement::HostVisible);
2911 
2912         VK_CHECK(vk.bindBufferMemory(device, *queryPoolResultsBuffer, queryPoolResultsBufferAlloc->getMemory(),
2913                                      queryPoolResultsBufferAlloc->getOffset()));
2914     }
2915 
2916     beginCommandBuffer(vk, *cmdBuffer);
2917     {
2918         if (m_parameters.testType != TEST_TYPE_QUERY_RESET)
2919             vk.cmdResetQueryPool(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber);
2920 
2921         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2922         {
2923             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
2924 
2925             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, 1u, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
2926 
2927             if (m_parameters.streamId == 0 && m_parameters.streamId0Mode != STREAM_ID_0_BEGIN_QUERY_INDEXED)
2928                 vk.cmdBeginQuery(*cmdBuffer, *queryPool, queryIndex, 0u);
2929             else
2930                 vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex, 0u, m_parameters.streamId);
2931             {
2932                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2933                 {
2934                     vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(numVerticesToWrite), 1u, 0u, 0u);
2935                 }
2936                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2937             }
2938             if (m_parameters.streamId == 0 && m_parameters.streamId0Mode != STREAM_ID_0_END_QUERY_INDEXED)
2939                 vk.cmdEndQuery(*cmdBuffer, *queryPool, queryIndex);
2940             else
2941                 vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex, m_parameters.streamId);
2942         }
2943         endRenderPass(vk, *cmdBuffer);
2944 
2945         if (m_parameters.testType == TEST_TYPE_QUERY_COPY || m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2946         {
2947             VkDeviceSize copyStride = queryDataSize;
2948             if (queryCountersNumber == 1u && m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2949                 copyStride = 0;
2950 
2951             vk.cmdCopyQueryPoolResults(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber, *queryPoolResultsBuffer,
2952                                        0u, copyStride, (queryWait | queryExtraFlags));
2953 
2954             const VkBufferMemoryBarrier bufferBarrier = {
2955                 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
2956                 DE_NULL,                                 // const void* pNext;
2957                 VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags srcAccessMask;
2958                 VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags dstAccessMask;
2959                 VK_QUEUE_FAMILY_IGNORED,                 // uint32_t srcQueueFamilyIndex;
2960                 VK_QUEUE_FAMILY_IGNORED,                 // uint32_t dstQueueFamilyIndex;
2961                 *queryPoolResultsBuffer,                 // VkBuffer buffer;
2962                 0ull,                                    // VkDeviceSize offset;
2963                 VK_WHOLE_SIZE                            // VkDeviceSize size;
2964             };
2965             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
2966                                   DE_NULL, 1u, &bufferBarrier, 0u, DE_NULL);
2967         }
2968     }
2969     endCommandBuffer(vk, *cmdBuffer);
2970 
2971     if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
2972         vk.resetQueryPool(device, *queryPool, queryIndex, queryCountersNumber);
2973     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2974 
2975     {
2976         union Results
2977         {
2978             uint32_t elements32[queryResultElements];
2979             uint64_t elements64[queryResultElements];
2980         };
2981 
2982         std::vector<uint8_t> queryData(queryDataSize, 0u);
2983         const Results *queryResults = reinterpret_cast<Results *>(queryData.data());
2984 
2985         if (m_parameters.testType != TEST_TYPE_QUERY_COPY && m_parameters.testType != TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2986         {
2987             vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber, queryDataSize, queryData.data(),
2988                                    queryDataSize, (queryWait | queryExtraFlags));
2989         }
2990         else
2991         {
2992             invalidateAlloc(vk, device, *queryPoolResultsBufferAlloc);
2993             deMemcpy(queryData.data(), queryPoolResultsBufferAlloc->getHostPtr(), queryData.size());
2994         }
2995 
2996         // Query results not available
2997         if (*reinterpret_cast<uint32_t *>(&queryData[queryDataSize - queryResultWidth]) == 0)
2998             return tcu::TestStatus::pass("Pass");
2999 
3000         // The number of primitives successfully written to the corresponding transform feedback buffer.
3001         const uint64_t numPrimitivesWritten =
3002             (m_parameters.query64bits ? queryResults->elements64[0] : queryResults->elements32[0]);
3003 
3004         // The number of primitives output to the vertex stream.
3005         const uint64_t numPrimitivesNeeded =
3006             (m_parameters.query64bits ? queryResults->elements64[1] : queryResults->elements32[1]);
3007 
3008         // Count how many primitives we should get by using selected topology.
3009         const auto primitivesInBuffer =
3010             topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesInBuffer);
3011         const auto primitivesToWrite = topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesToWrite);
3012 
3013         log << tcu::TestLog::Message << "Primitives Written / Expected :  " << de::toString(numPrimitivesWritten)
3014             << " / " << de::toString(primitivesInBuffer) << tcu::TestLog::EndMessage;
3015         log << tcu::TestLog::Message << "Primitives  Needed / Expected :  " << de::toString(numPrimitivesNeeded)
3016             << " / " << de::toString(primitivesToWrite) << tcu::TestLog::EndMessage;
3017 
3018         if (numPrimitivesWritten != primitivesInBuffer)
3019             return tcu::TestStatus::fail("numPrimitivesWritten=" + de::toString(numPrimitivesWritten) +
3020                                          " while expected " + de::toString(primitivesInBuffer));
3021 
3022         if (numPrimitivesNeeded != primitivesToWrite)
3023             return tcu::TestStatus::fail("numPrimitivesNeeded=" + de::toString(numPrimitivesNeeded) +
3024                                          " while expected " + de::toString(primitivesToWrite));
3025     }
3026 
3027     if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
3028     {
3029         constexpr uint32_t queryResetElements = queryResultElements + 1; // For the availability bit.
3030 
3031         union Results
3032         {
3033             uint32_t elements32[queryResetElements];
3034             uint64_t elements64[queryResetElements];
3035         };
3036 
3037         const uint32_t queryDataAvailSize(static_cast<uint32_t>(queryResetElements * queryResultWidth));
3038         std::vector<uint8_t> queryData(queryDataAvailSize, 0u);
3039         Results *queryResults = reinterpret_cast<Results *>(queryData.data());
3040 
3041         // Initialize values
3042         if (m_parameters.query64bits)
3043         {
3044             queryResults->elements64[0] = 1u; // numPrimitivesWritten
3045             queryResults->elements64[1] = 1u; // numPrimitivesNeeded
3046             queryResults->elements64[2] = 1u; // Availability bit
3047         }
3048         else
3049         {
3050             queryResults->elements32[0] = 1u; // numPrimitivesWritten
3051             queryResults->elements32[1] = 1u; // numPrimitivesNeeded
3052             queryResults->elements32[2] = 1u; // Availability bit
3053         }
3054 
3055         vk.resetQueryPool(device, *queryPool, queryIndex, queryCountersNumber);
3056 
3057         vk::VkResult res = vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber,
3058                                                   queryDataAvailSize, queryData.data(), queryDataAvailSize,
3059                                                   (vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | queryExtraFlags));
3060         const uint64_t numPrimitivesWritten =
3061             (m_parameters.query64bits ? queryResults->elements64[0] : queryResults->elements32[0]);
3062         const uint64_t numPrimitivesNeeded =
3063             (m_parameters.query64bits ? queryResults->elements64[1] : queryResults->elements32[1]);
3064         const uint64_t availabilityState =
3065             (m_parameters.query64bits ? queryResults->elements64[2] : queryResults->elements32[2]);
3066 
3067         /* From the Vulkan spec:
3068          *
3069          * If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are both not set then no result values are written to pData
3070          * for queries that are in the unavailable state at the time of the call, and vkGetQueryPoolResults returns VK_NOT_READY.
3071          * However, availability state is still written to pData for those queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set.
3072          */
3073         if (res != vk::VK_NOT_READY || availabilityState != 0u)
3074             return tcu::TestStatus::fail("QueryPoolResults incorrect reset");
3075         if (numPrimitivesWritten != 1u || numPrimitivesNeeded != 1u)
3076             return tcu::TestStatus::fail("QueryPoolResults data was modified");
3077     }
3078 
3079     return tcu::TestStatus::pass("Pass");
3080 }
3081 
3082 class TransformFeedbackMultiQueryTestInstance : public TransformFeedbackTestInstance
3083 {
3084 public:
3085     TransformFeedbackMultiQueryTestInstance(Context &context, const TestParameters &parameters);
3086 
3087 protected:
3088     std::vector<VkDeviceSize> generateSizesList(const size_t bufBytes, const size_t chunkCount);
3089     void verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
3090                                        const uint32_t bufBytes, const uint32_t bufOffset, const float expected);
3091     tcu::TestStatus iterate(void);
3092 };
3093 
TransformFeedbackMultiQueryTestInstance(Context & context,const TestParameters & parameters)3094 TransformFeedbackMultiQueryTestInstance::TransformFeedbackMultiQueryTestInstance(Context &context,
3095                                                                                  const TestParameters &parameters)
3096     : TransformFeedbackTestInstance(context, parameters)
3097 {
3098     const InstanceInterface &vki            = m_context.getInstanceInterface();
3099     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
3100     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
3101     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
3102         m_context.getTransformFeedbackFeaturesEXT();
3103     const uint32_t streamsSupported            = m_transformFeedbackProperties.maxTransformFeedbackStreams;
3104     const uint32_t streamsRequired             = m_parameters.streamId + 1;
3105     const uint32_t tfBuffersSupported          = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
3106     const uint32_t tfBuffersRequired           = m_parameters.partCount;
3107     const uint32_t bytesPerVertex              = m_parameters.bufferSize / m_parameters.partCount;
3108     const uint32_t tfStreamDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
3109     const uint32_t tfBufferDataSizeSupported   = m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
3110     const uint32_t tfBufferDataStrideSupported = m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
3111 
3112     DE_ASSERT(m_parameters.partCount == 2u);
3113 
3114     if (!features.geometryShader)
3115         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
3116 
3117     if (transformFeedbackFeatures.geometryStreams == false)
3118         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
3119 
3120     if (streamsSupported < streamsRequired)
3121         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
3122                                                  ", while test requires " + de::toString(streamsRequired))
3123                                          .c_str());
3124 
3125     if (tfBuffersSupported < tfBuffersRequired)
3126         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
3127                                                  ", while test requires " + de::toString(tfBuffersRequired))
3128                                          .c_str());
3129 
3130     if (tfStreamDataSizeSupported < bytesPerVertex)
3131         TCU_THROW(NotSupportedError,
3132                   std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) +
3133                               ", while test requires " + de::toString(bytesPerVertex))
3134                       .c_str());
3135 
3136     if (tfBufferDataSizeSupported < bytesPerVertex)
3137         TCU_THROW(NotSupportedError,
3138                   std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) +
3139                               ", while test requires " + de::toString(bytesPerVertex))
3140                       .c_str());
3141 
3142     if (tfBufferDataStrideSupported < bytesPerVertex)
3143         TCU_THROW(NotSupportedError,
3144                   std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) +
3145                               ", while test requires " + de::toString(bytesPerVertex))
3146                       .c_str());
3147 
3148     if (m_transformFeedbackProperties.transformFeedbackQueries == false)
3149         TCU_THROW(NotSupportedError, "transformFeedbackQueries feature is not supported");
3150 }
3151 
generateSizesList(const size_t bufBytes,const size_t chunkCount)3152 std::vector<VkDeviceSize> TransformFeedbackMultiQueryTestInstance::generateSizesList(const size_t bufBytes,
3153                                                                                      const size_t chunkCount)
3154 {
3155     const VkDeviceSize chunkSize = bufBytes / chunkCount;
3156     std::vector<VkDeviceSize> result(chunkCount, chunkSize);
3157 
3158     DE_ASSERT(chunkSize * chunkCount == bufBytes);
3159     DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
3160     DE_ASSERT(bufBytes % sizeof(uint32_t) == 0);
3161     DE_ASSERT(chunkCount > 0);
3162     DE_ASSERT(result.size() == chunkCount);
3163 
3164     return result;
3165 }
3166 
verifyTransformFeedbackBuffer(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes,const uint32_t bufOffset,const float expected)3167 void TransformFeedbackMultiQueryTestInstance::verifyTransformFeedbackBuffer(const DeviceHelper &deviceHelper,
3168                                                                             const MovePtr<Allocation> &bufAlloc,
3169                                                                             const uint32_t bufBytes,
3170                                                                             const uint32_t bufOffset,
3171                                                                             const float expected)
3172 {
3173     const DeviceInterface &vk = deviceHelper.getDeviceInterface();
3174     const VkDevice device     = deviceHelper.getDevice();
3175     const uint32_t numPoints  = bufBytes / static_cast<uint32_t>(sizeof(float));
3176     const uint8_t *tfDataRaw  = getInvalidatedHostPtr<uint8_t>(vk, device, *bufAlloc);
3177     const float *tfData       = reinterpret_cast<const float *>(&tfDataRaw[bufOffset]);
3178 
3179     for (uint32_t i = 0; i < numPoints; ++i)
3180         if (tfData[i] != expected)
3181             TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) +
3182                      " expected:" + de::toString(expected));
3183 }
3184 
iterate(void)3185 tcu::TestStatus TransformFeedbackMultiQueryTestInstance::iterate(void)
3186 {
3187     const auto &deviceHelper                       = getDeviceHelper(m_context, m_parameters);
3188     const auto &vki                                = m_context.getInstanceInterface();
3189     const auto physicalDevice                      = m_context.getPhysicalDevice();
3190     const DeviceInterface &vk                      = deviceHelper.getDeviceInterface();
3191     const VkDevice device                          = deviceHelper.getDevice();
3192     const uint32_t queueFamilyIndex                = deviceHelper.getQueueFamilyIndex();
3193     const std::vector<uint32_t> queueFamilyIndices = {queueFamilyIndex};
3194     const VkQueue queue                            = deviceHelper.getQueue();
3195     Allocator &allocator                           = deviceHelper.getAllocator();
3196 
3197     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
3198 
3199     const ShaderWrapper vertModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
3200     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
3201     const ShaderWrapper kNullModule;
3202 
3203     const Unique<VkFramebuffer> framebuffer(
3204         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
3205     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
3206     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
3207                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass, vertModule,
3208                                              kNullModule, kNullModule, geomModule, kNullModule, m_imageExtent2D, 0u));
3209     const Unique<VkCommandPool> cmdPool(
3210         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
3211     const Unique<VkCommandBuffer> cmdBuffer(
3212         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3213 
3214     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
3215         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3216     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
3217     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
3218     const MovePtr<Allocation> tfBufAllocation =
3219         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
3220     const VkMemoryBarrier tfMemoryBarrier =
3221         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3222     const std::vector<VkDeviceSize> tfBufBindingSizes =
3223         generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
3224     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
3225     const std::vector<float> tfBufExpectedValues        = {0.5f, 0.5f + float(m_parameters.streamId)};
3226     const uint32_t maxBufferSizeBytes =
3227         static_cast<uint32_t>(*std::max_element(tfBufBindingSizes.begin(), tfBufBindingSizes.end()));
3228     const uint32_t bytesPerVertex      = static_cast<uint32_t>(4 * sizeof(float));
3229     const uint32_t numVerticesInBuffer = maxBufferSizeBytes / bytesPerVertex;
3230     const uint32_t numDrawVertices     = numVerticesInBuffer / 2;
3231 
3232     const uint32_t queryIndex                       = 0u;
3233     const uint32_t queryCountersNumber              = 2u;
3234     const uint32_t queryStride                      = sizeof(TransformFeedbackQuery);
3235     const uint32_t queryDataSize                    = queryCountersNumber * queryStride;
3236     const VkQueryPoolCreateInfo queryPoolCreateInfo = makeQueryPoolCreateInfo(queryCountersNumber);
3237     const Unique<VkQueryPool> queryPool(createQueryPool(vk, device, &queryPoolCreateInfo));
3238     const uint32_t queryInvalidCounterValue = 999999u;
3239     std::vector<TransformFeedbackQuery> queryResultData(
3240         queryCountersNumber, TransformFeedbackQuery{queryInvalidCounterValue, queryInvalidCounterValue});
3241     const std::vector<TransformFeedbackQuery> queryExpectedData(
3242         {TransformFeedbackQuery{numVerticesInBuffer, 3 * numDrawVertices},
3243          TransformFeedbackQuery{numDrawVertices, numDrawVertices}});
3244 
3245     const VkBufferCreateInfo queryBufferCreateInfo =
3246         makeBufferCreateInfo(queryDataSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, queueFamilyIndices);
3247     const Move<VkBuffer> queryPoolResultsBuffer           = createBuffer(vk, device, &queryBufferCreateInfo);
3248     const MovePtr<Allocation> queryPoolResultsBufferAlloc = allocator.allocate(
3249         getBufferMemoryRequirements(vk, device, *queryPoolResultsBuffer), MemoryRequirement::HostVisible);
3250 
3251     DE_ASSERT(queryCountersNumber == queryExpectedData.size());
3252 
3253     VK_CHECK(vk.bindBufferMemory(device, *queryPoolResultsBuffer, queryPoolResultsBufferAlloc->getMemory(),
3254                                  queryPoolResultsBufferAlloc->getOffset()));
3255 
3256     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
3257 
3258     beginCommandBuffer(vk, *cmdBuffer);
3259     {
3260         vk.cmdResetQueryPool(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber);
3261 
3262         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
3263         {
3264             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
3265 
3266             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0],
3267                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
3268 
3269             vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 0, 0u, 0u);
3270             vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 1, 0u, m_parameters.streamId);
3271             {
3272                 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3273                 {
3274                     vk.cmdDraw(*cmdBuffer, numDrawVertices, 1u, 0u, 0u);
3275                 }
3276                 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3277             }
3278             vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 1, m_parameters.streamId);
3279             vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 0, 0);
3280         }
3281         endRenderPass(vk, *cmdBuffer);
3282 
3283         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
3284                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
3285     }
3286     endCommandBuffer(vk, *cmdBuffer);
3287     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
3288 
3289     vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber, queryDataSize, queryResultData.data(),
3290                            queryStride, (vk::VK_QUERY_RESULT_WAIT_BIT));
3291 
3292     DE_ASSERT(queryResultData.size() == queryCountersNumber && queryExpectedData.size() == queryCountersNumber);
3293     DE_ASSERT(queryCountersNumber > 0);
3294 
3295     for (size_t counterNdx = 0; counterNdx < queryCountersNumber; ++counterNdx)
3296     {
3297         const TransformFeedbackQuery &result   = queryResultData[counterNdx];
3298         const TransformFeedbackQuery &expected = queryExpectedData[counterNdx];
3299 
3300         DE_ASSERT(expected.written != queryInvalidCounterValue);
3301         DE_ASSERT(expected.attempts != queryInvalidCounterValue);
3302 
3303         if (result.written == queryInvalidCounterValue || result.attempts == queryInvalidCounterValue)
3304             return tcu::TestStatus::fail("Query counters read failed");
3305 
3306         if (result.written != expected.written)
3307         {
3308             const std::string comment = "At counter " + de::toString(counterNdx) + " vertices written " +
3309                                         de::toString(result.written) + ", while expected " +
3310                                         de::toString(expected.written);
3311 
3312             return tcu::TestStatus::fail(comment.c_str());
3313         }
3314 
3315         if (result.attempts != expected.attempts)
3316         {
3317             const std::string comment = "At counter " + de::toString(counterNdx) + " attempts committed " +
3318                                         de::toString(result.attempts) + ", while expected " +
3319                                         de::toString(expected.attempts);
3320 
3321             return tcu::TestStatus::fail(comment.c_str());
3322         }
3323 
3324         if (counterNdx == 0 && !m_parameters.omitShaderWrite)
3325             verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, bytesPerVertex * expected.written,
3326                                           static_cast<uint32_t>(tfBufBindingOffsets[counterNdx]),
3327                                           tfBufExpectedValues[counterNdx]);
3328     }
3329 
3330     return tcu::TestStatus::pass("Pass");
3331 }
3332 
3333 class TransformFeedbackLinesOrTrianglesTestInstance : public TransformFeedbackTestInstance
3334 {
3335 public:
3336     TransformFeedbackLinesOrTrianglesTestInstance(Context &context, const TestParameters &parameters);
3337 
3338 protected:
3339     std::vector<VkDeviceSize> generateSizesList(const size_t bufBytes, const size_t chunkCount);
3340     void verifyTransformFeedbackBufferLines(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
3341                                             const uint32_t bufBytes, const std::vector<uint32_t> &primitives,
3342                                             const uint32_t invocationCount, const uint32_t partCount);
3343     void verifyTransformFeedbackBufferTriangles(const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc,
3344                                                 const uint32_t bufBytes, const std::vector<uint32_t> &primitives,
3345                                                 const uint32_t invocationCount, const uint32_t partCount);
3346     tcu::TestStatus iterate(void);
3347 };
3348 
TransformFeedbackLinesOrTrianglesTestInstance(Context & context,const TestParameters & parameters)3349 TransformFeedbackLinesOrTrianglesTestInstance::TransformFeedbackLinesOrTrianglesTestInstance(
3350     Context &context, const TestParameters &parameters)
3351     : TransformFeedbackTestInstance(context, parameters)
3352 {
3353     const InstanceInterface &vki            = m_context.getInstanceInterface();
3354     const VkPhysicalDevice physDevice       = m_context.getPhysicalDevice();
3355     const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
3356     const VkPhysicalDeviceTransformFeedbackFeaturesEXT &transformFeedbackFeatures =
3357         m_context.getTransformFeedbackFeaturesEXT();
3358     const uint32_t streamsSupported   = m_transformFeedbackProperties.maxTransformFeedbackStreams;
3359     const uint32_t streamsRequired    = m_parameters.streamId + 1;
3360     const uint32_t tfBuffersSupported = m_transformFeedbackProperties.maxTransformFeedbackBuffers;
3361     const uint32_t tfBuffersRequired  = m_parameters.partCount;
3362 
3363     DE_ASSERT(m_parameters.partCount == 2u);
3364 
3365     if (m_transformFeedbackProperties.transformFeedbackStreamsLinesTriangles == false)
3366         TCU_THROW(NotSupportedError, "transformFeedbackStreamsLinesTriangles required");
3367 
3368     if (!features.geometryShader)
3369         TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
3370 
3371     if (transformFeedbackFeatures.geometryStreams == false)
3372         TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
3373 
3374     if (streamsSupported < streamsRequired)
3375         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) +
3376                                                  ", while test requires " + de::toString(streamsRequired))
3377                                          .c_str());
3378 
3379     if (tfBuffersSupported < tfBuffersRequired)
3380         TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) +
3381                                                  ", while test requires " + de::toString(tfBuffersRequired))
3382                                          .c_str());
3383 }
3384 
generateSizesList(const size_t bufBytes,const size_t chunkCount)3385 std::vector<VkDeviceSize> TransformFeedbackLinesOrTrianglesTestInstance::generateSizesList(const size_t bufBytes,
3386                                                                                            const size_t chunkCount)
3387 {
3388     const VkDeviceSize chunkSize = bufBytes / chunkCount;
3389     std::vector<VkDeviceSize> result(chunkCount, chunkSize);
3390 
3391     DE_ASSERT(chunkSize * chunkCount == bufBytes);
3392     DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
3393     DE_ASSERT(bufBytes % sizeof(uint32_t) == 0);
3394     DE_ASSERT(chunkCount > 0);
3395     DE_ASSERT(result.size() == chunkCount);
3396 
3397     return result;
3398 }
3399 
verifyTransformFeedbackBufferLines(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes,const std::vector<uint32_t> & primitives,const uint32_t invocationCount,const uint32_t partCount)3400 void TransformFeedbackLinesOrTrianglesTestInstance::verifyTransformFeedbackBufferLines(
3401     const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc, const uint32_t bufBytes,
3402     const std::vector<uint32_t> &primitives, const uint32_t invocationCount, const uint32_t partCount)
3403 {
3404     const DeviceInterface &vk  = deviceHelper.getDeviceInterface();
3405     const VkDevice device      = deviceHelper.getDevice();
3406     const tcu::Vec4 *tfData    = getInvalidatedHostPtr<tcu::Vec4>(vk, device, *bufAlloc);
3407     const uint32_t stripeCount = static_cast<uint32_t>(primitives.size());
3408     const uint32_t vertexCount = 2 * destripedLineCount(primitives) * invocationCount * partCount;
3409     const uint32_t numPoints   = static_cast<uint32_t>(bufBytes / sizeof(tcu::Vec4));
3410     uint32_t n                 = 0;
3411     std::vector<tcu::Vec4> reference;
3412 
3413     reference.reserve(vertexCount);
3414 
3415     for (uint32_t partNdx = 0; partNdx < partCount; ++partNdx)
3416     {
3417         for (uint32_t invocationNdx = 0; invocationNdx < invocationCount; ++invocationNdx)
3418         {
3419             for (uint32_t stripeNdx = 0; stripeNdx < stripeCount; ++stripeNdx)
3420             {
3421                 const uint32_t stripeVertexCount = primitives[stripeNdx];
3422 
3423                 for (uint32_t vertexNdx = 0; vertexNdx < stripeVertexCount; ++vertexNdx)
3424                 {
3425                     const bool firstOrLast = vertexNdx == 0 || vertexNdx == stripeVertexCount - 1;
3426                     const tcu::Vec4 v(float(n++), float(invocationNdx), float(stripeNdx), float(vertexNdx));
3427 
3428                     reference.push_back(v);
3429 
3430                     if (!firstOrLast)
3431                         reference.push_back(v);
3432                 }
3433             }
3434         }
3435     }
3436 
3437     DE_ASSERT(reference.size() == numPoints);
3438 
3439     const tcu::Vec4 threshold(0.0001f, 0.0001f, 0.0001f, 0.0001f);
3440     const auto errors = verifyVertexDataWithWinding(reference, tfData, numPoints, 2u, threshold);
3441     checkErrorVec(m_context.getTestContext().getLog(), errors);
3442 }
3443 
verifyTransformFeedbackBufferTriangles(const DeviceHelper & deviceHelper,const MovePtr<Allocation> & bufAlloc,const uint32_t bufBytes,const std::vector<uint32_t> & primitives,const uint32_t invocationCount,const uint32_t partCount)3444 void TransformFeedbackLinesOrTrianglesTestInstance::verifyTransformFeedbackBufferTriangles(
3445     const DeviceHelper &deviceHelper, const MovePtr<Allocation> &bufAlloc, const uint32_t bufBytes,
3446     const std::vector<uint32_t> &primitives, const uint32_t invocationCount, const uint32_t partCount)
3447 {
3448     const DeviceInterface &vk  = deviceHelper.getDeviceInterface();
3449     const VkDevice device      = deviceHelper.getDevice();
3450     const tcu::Vec4 *tfData    = getInvalidatedHostPtr<tcu::Vec4>(vk, device, *bufAlloc);
3451     const uint32_t stripeCount = static_cast<uint32_t>(primitives.size());
3452     const uint32_t vertexCount = 3 * destripedLineCount(primitives) * invocationCount * partCount;
3453     const uint32_t numPoints   = static_cast<uint32_t>(bufBytes / sizeof(tcu::Vec4));
3454     uint32_t n                 = 0;
3455     std::vector<tcu::Vec4> reference;
3456 
3457     reference.reserve(vertexCount);
3458 
3459     for (uint32_t partNdx = 0; partNdx < partCount; ++partNdx)
3460     {
3461         for (uint32_t invocationNdx = 0; invocationNdx < invocationCount; ++invocationNdx)
3462         {
3463             for (uint32_t stripeNdx = 0; stripeNdx < stripeCount; ++stripeNdx)
3464             {
3465                 const uint32_t stripeVertexCount = primitives[stripeNdx];
3466                 const uint32_t trianglesCount    = stripeVertexCount - 2;
3467                 std::vector<tcu::Vec4> stripe(stripeVertexCount);
3468 
3469                 for (uint32_t vertexNdx = 0; vertexNdx < stripeVertexCount; ++vertexNdx)
3470                     stripe[vertexNdx] = tcu::Vec4(float(n++), float(invocationNdx), float(stripeNdx), float(vertexNdx));
3471 
3472                 for (uint32_t triangleNdx = 0; triangleNdx < trianglesCount; ++triangleNdx)
3473                 {
3474                     if (triangleNdx % 2 == 0)
3475                     {
3476                         reference.push_back(stripe[triangleNdx + 0]);
3477                         reference.push_back(stripe[triangleNdx + 1]);
3478                         reference.push_back(stripe[triangleNdx + 2]);
3479                     }
3480                     else
3481                     {
3482                         reference.push_back(stripe[triangleNdx + 0]);
3483                         reference.push_back(stripe[triangleNdx + 2]);
3484                         reference.push_back(stripe[triangleNdx + 1]);
3485                     }
3486                 }
3487             }
3488         }
3489     }
3490 
3491     DE_ASSERT(reference.size() == numPoints);
3492 
3493     const tcu::Vec4 threshold(0.0001f, 0.0001f, 0.0001f, 0.0001f);
3494     const auto errors = verifyVertexDataWithWinding(reference, tfData, numPoints, 3u, threshold);
3495     checkErrorVec(m_context.getTestContext().getLog(), errors);
3496 }
3497 
iterate(void)3498 tcu::TestStatus TransformFeedbackLinesOrTrianglesTestInstance::iterate(void)
3499 {
3500     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
3501     const auto &vki                 = m_context.getInstanceInterface();
3502     const auto physicalDevice       = m_context.getPhysicalDevice();
3503     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
3504     const VkDevice device           = deviceHelper.getDevice();
3505     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
3506     const VkQueue queue             = deviceHelper.getQueue();
3507     Allocator &allocator            = deviceHelper.getAllocator();
3508 
3509     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
3510 
3511     const ShaderWrapper vertexModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
3512     const ShaderWrapper geomModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
3513     const ShaderWrapper kNullModule;
3514 
3515     const Unique<VkFramebuffer> framebuffer(
3516         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
3517     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
3518     const auto pipeline(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
3519                                              m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
3520                                              vertexModule, kNullModule, kNullModule, geomModule, kNullModule,
3521                                              m_imageExtent2D, 0u, &m_parameters.streamId));
3522     const Unique<VkCommandPool> cmdPool(
3523         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
3524     const Unique<VkCommandBuffer> cmdBuffer(
3525         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3526 
3527     const uint32_t tfBufferSize              = m_parameters.bufferSize;
3528     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
3529         tfBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3530     const Move<VkBuffer> tfBuf             = createBuffer(vk, device, &tfBufCreateInfo);
3531     const std::vector<VkBuffer> tfBufArray = std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
3532     const MovePtr<Allocation> tfBufAllocation =
3533         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
3534     const VkMemoryBarrier tfMemoryBarrier =
3535         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3536     const std::vector<VkDeviceSize> tfBufBindingSizes   = generateSizesList(tfBufferSize, m_parameters.partCount);
3537     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
3538 
3539     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
3540 
3541     beginCommandBuffer(vk, *cmdBuffer);
3542     {
3543         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
3544         {
3545             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getPipeline());
3546 
3547             vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0],
3548                                                   &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
3549 
3550             vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3551             {
3552                 vk.cmdDraw(*cmdBuffer, INVOCATION_COUNT, 1u, 0u, 0u);
3553             }
3554             vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3555         }
3556         endRenderPass(vk, *cmdBuffer);
3557 
3558         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
3559                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
3560     }
3561     endCommandBuffer(vk, *cmdBuffer);
3562     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
3563 
3564     switch (m_parameters.primTopology)
3565     {
3566     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
3567         verifyTransformFeedbackBufferLines(deviceHelper, tfBufAllocation, tfBufferSize, LINES_LIST, INVOCATION_COUNT,
3568                                            m_parameters.partCount);
3569         break;
3570     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
3571         verifyTransformFeedbackBufferTriangles(deviceHelper, tfBufAllocation, tfBufferSize, TRIANGLES_LIST,
3572                                                INVOCATION_COUNT, m_parameters.partCount);
3573         break;
3574     default:
3575         TCU_THROW(InternalError, "Unknown topology");
3576     }
3577 
3578     return tcu::TestStatus::pass("Pass");
3579 }
3580 
3581 class TransformFeedbackDrawOutsideTestInstance : public TransformFeedbackTestInstance
3582 {
3583 public:
3584     TransformFeedbackDrawOutsideTestInstance(Context &context, const TestParameters &parameters);
3585 
3586 protected:
3587     tcu::TestStatus iterate(void);
3588 };
3589 
TransformFeedbackDrawOutsideTestInstance(Context & context,const TestParameters & parameters)3590 TransformFeedbackDrawOutsideTestInstance::TransformFeedbackDrawOutsideTestInstance(Context &context,
3591                                                                                    const TestParameters &parameters)
3592     : TransformFeedbackTestInstance(context, parameters)
3593 {
3594 }
3595 
iterate(void)3596 tcu::TestStatus TransformFeedbackDrawOutsideTestInstance::iterate(void)
3597 {
3598     const auto &deviceHelper        = getDeviceHelper(m_context, m_parameters);
3599     const auto &vki                 = m_context.getInstanceInterface();
3600     const auto physicalDevice       = m_context.getPhysicalDevice();
3601     const DeviceInterface &vk       = deviceHelper.getDeviceInterface();
3602     const VkDevice device           = deviceHelper.getDevice();
3603     const uint32_t queueFamilyIndex = deviceHelper.getQueueFamilyIndex();
3604     const VkQueue queue             = deviceHelper.getQueue();
3605     Allocator &allocator            = deviceHelper.getAllocator();
3606 
3607     const ShaderWrapper vertexModule1(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
3608     const ShaderWrapper vertexModule2(vk, device, m_context.getBinaryCollection().get("vert2"), 0u);
3609     const ShaderWrapper kNullModule;
3610     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
3611     const Unique<VkFramebuffer> framebuffer(
3612         makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
3613     const auto pipelineLayout(TransformFeedback::makePipelineLayout(m_parameters.pipelineConstructionType, vk, device));
3614     const auto pipeline1(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
3615                                               m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
3616                                               vertexModule1, kNullModule, kNullModule, kNullModule, kNullModule,
3617                                               m_imageExtent2D, 0u, &m_parameters.streamId));
3618     const auto pipeline2(makeGraphicsPipeline(m_parameters.pipelineConstructionType, vki, vk, physicalDevice, device,
3619                                               m_context.getDeviceExtensions(), *pipelineLayout, *renderPass,
3620                                               vertexModule2, kNullModule, kNullModule, kNullModule, kNullModule,
3621                                               m_imageExtent2D, 0u, &m_parameters.streamId));
3622     const Unique<VkCommandPool> cmdPool(
3623         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
3624     const Unique<VkCommandBuffer> cmdBuffer(
3625         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3626 
3627     const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(
3628         m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3629     const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
3630     const MovePtr<Allocation> tfBufAllocation =
3631         allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
3632     const VkMemoryBarrier tfMemoryBarrier =
3633         makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3634     const std::vector<VkDeviceSize> tfBufBindingSizes =
3635         generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
3636     const std::vector<VkDeviceSize> tfBufBindingOffsets = generateOffsetsList(tfBufBindingSizes);
3637 
3638     VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
3639 
3640     beginCommandBuffer(vk, *cmdBuffer);
3641     {
3642         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
3643         {
3644             for (uint32_t i = 0; i < 2; ++i)
3645             {
3646                 if (i == 0)
3647                     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline1->getPipeline());
3648                 else
3649                     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline2->getPipeline());
3650 
3651                 for (uint32_t drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
3652                 {
3653                     const uint32_t startValue = static_cast<uint32_t>(tfBufBindingOffsets[drawNdx] / sizeof(uint32_t));
3654                     const uint32_t numPoints  = static_cast<uint32_t>(tfBufBindingSizes[drawNdx] / sizeof(uint32_t));
3655 
3656                     vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[drawNdx],
3657                                                           &tfBufBindingSizes[drawNdx]);
3658 
3659                     vk.cmdPushConstants(*cmdBuffer, pipelineLayout->get(), VK_SHADER_STAGE_VERTEX_BIT, 0u,
3660                                         sizeof(startValue), &startValue);
3661 
3662                     if (i == 0)
3663                         vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3664                     {
3665                         vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
3666                     }
3667                     if (i == 0)
3668                         vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
3669                 }
3670             }
3671         }
3672         endRenderPass(vk, *cmdBuffer);
3673 
3674         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
3675                               1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
3676     }
3677     endCommandBuffer(vk, *cmdBuffer);
3678     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
3679 
3680     verifyTransformFeedbackBuffer(deviceHelper, tfBufAllocation, m_parameters.bufferSize);
3681 
3682     return tcu::TestStatus::pass("Pass");
3683 }
3684 
3685 class TransformFeedbackHolesInstance : public vkt::TestInstance
3686 {
3687 public:
TransformFeedbackHolesInstance(Context & context,const bool extraDraw)3688     TransformFeedbackHolesInstance(Context &context, const bool extraDraw)
3689         : vkt::TestInstance(context)
3690         , m_extraDraw(extraDraw)
3691     {
3692     }
~TransformFeedbackHolesInstance(void)3693     ~TransformFeedbackHolesInstance(void)
3694     {
3695     }
3696 
3697     tcu::TestStatus iterate(void) override;
3698 
3699 protected:
3700     const bool m_extraDraw;
3701 };
3702 
iterate(void)3703 tcu::TestStatus TransformFeedbackHolesInstance::iterate(void)
3704 {
3705     const auto &ctx = m_context.getContextCommonData();
3706     const tcu::IVec3 fbExtent(1, 1, 1);
3707     const auto vkExtent  = makeExtent3D(fbExtent);
3708     const auto fbFormat  = VK_FORMAT_R8G8B8A8_UNORM;
3709     const auto tcuFormat = mapVkFormat(fbFormat);
3710     const auto fbUsage   = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
3711     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3712     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader values.
3713     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
3714     const auto bindPoint    = VK_PIPELINE_BIND_POINT_GRAPHICS;
3715     const auto &binaries    = m_context.getBinaryCollection();
3716     const bool hasGeom      = binaries.contains("geom");
3717     const auto dataStages   = (hasGeom ? VK_SHADER_STAGE_GEOMETRY_BIT : VK_SHADER_STAGE_VERTEX_BIT);
3718     const auto xfbCompCount = 3u;                           // Per vertex.
3719     const auto xfbChunkSize = xfbCompCount * sizeof(float); // Per vertex, in bytes.
3720     const auto totalDraws   = (m_extraDraw ? 2u : 1u);
3721 
3722     // Color buffer with verification buffer.
3723     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage, VK_IMAGE_TYPE_2D);
3724 
3725     // Vertices.
3726     const std::vector<tcu::Vec4> vertices{tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)};
3727 
3728     // Vertex buffer.
3729     const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
3730     const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
3731     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
3732     const auto vbAlloc  = vertexBuffer.getAllocation();
3733     void *vbData        = vbAlloc.getHostPtr();
3734     const auto vbOffset = static_cast<VkDeviceSize>(0);
3735 
3736     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
3737     flushAlloc(ctx.vkd, ctx.device, vbAlloc);
3738 
3739     // XFB buffer. When using an extra draw, leave space for a possible second draw (NB: but it should not be recorded, see below).
3740     const auto xfbSizeFactor = static_cast<VkDeviceSize>(totalDraws);
3741     const auto xfbBufferSize = static_cast<VkDeviceSize>(xfbChunkSize * vertices.size()) * xfbSizeFactor;
3742     const auto xfbBufferInfo = makeBufferCreateInfo(xfbBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3743     BufferWithMemory xfbBuffer(ctx.vkd, ctx.device, ctx.allocator, xfbBufferInfo, MemoryRequirement::HostVisible);
3744     const auto xfbBufferAlloc  = xfbBuffer.getAllocation();
3745     void *xfbBufferData        = xfbBufferAlloc.getHostPtr();
3746     const auto xfbBufferOffset = static_cast<VkDeviceSize>(0);
3747 
3748     deMemset(xfbBufferData, 0, static_cast<size_t>(xfbBufferSize));
3749     flushAlloc(ctx.vkd, ctx.device, xfbBufferAlloc);
3750 
3751     // Push constants.
3752     const tcu::Vec3 pcData{10.0, 20.0, 30.0}; // Must match the expected values in the frag shader.
3753     const auto pcSize  = static_cast<uint32_t>(sizeof(pcData));
3754     const auto pcRange = makePushConstantRange(dataStages, 0u, pcSize);
3755 
3756     const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
3757     const auto renderPass     = makeRenderPass(ctx.vkd, ctx.device, fbFormat);
3758     const auto framebuffer =
3759         makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height);
3760 
3761     // Modules.
3762     const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
3763     const auto geomModule =
3764         (hasGeom ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) : Move<VkShaderModule>());
3765     const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
3766 
3767     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
3768     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
3769 
3770     const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE,
3771                                                VK_NULL_HANDLE, *geomModule, *fragModule, *renderPass, viewports,
3772                                                scissors, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
3773 
3774     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
3775     const auto cmdBuffer = *cmd.cmdBuffer;
3776 
3777     beginCommandBuffer(ctx.vkd, cmdBuffer);
3778     beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
3779     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
3780     ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
3781     ctx.vkd.cmdPushConstants(cmdBuffer, *pipelineLayout, dataStages, 0u, pcSize, &pcData);
3782     ctx.vkd.cmdBindTransformFeedbackBuffersEXT(cmdBuffer, 0u, 1u, &xfbBuffer.get(), &xfbBufferOffset, &xfbBufferSize);
3783     ctx.vkd.cmdBeginTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3784     ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
3785     ctx.vkd.cmdEndTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3786     if (m_extraDraw)
3787     {
3788         // When m_extraDraw is true, record a new draw outside the transform feedback section. The XFB buffer will have enough space
3789         // to record this draw, but it should not be recorded, obviously, so the values in the buffer should stay zero. We are also
3790         // avoiding any state changes between both draws.
3791         ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
3792     }
3793     endRenderPass(ctx.vkd, cmdBuffer);
3794     const auto xfbBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3795     ctx.vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
3796                                1u, &xfbBarrier, 0u, nullptr, 0u, nullptr);
3797     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
3798                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
3799                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
3800                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3801     endCommandBuffer(ctx.vkd, cmdBuffer);
3802     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
3803 
3804     // Verify color output.
3805     invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
3806     tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
3807 
3808     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
3809     auto referenceAccess = referenceLevel.getAccess();
3810     tcu::clear(referenceAccess, geomColor);
3811 
3812     auto &log = m_context.getTestContext().getLog();
3813     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
3814                                     tcu::COMPARE_LOG_ON_ERROR))
3815         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
3816 
3817     // Verify XFB buffer.
3818     const tcu::Vec3 refRecordedValues{pcData.x(), 0.0f,
3819                                       pcData.z()};    // Per-vertex, must match vert/geom shader, note Y is not saved.
3820     const tcu::Vec3 refEmptyValues{0.0f, 0.0f, 0.0f}; // For empty areas of the XFB buffer.
3821     const auto dataPtr = reinterpret_cast<const char *>(xfbBufferData);
3822 
3823     for (uint32_t drawIdx = 0u; drawIdx < totalDraws; ++drawIdx)
3824     {
3825         const auto &refValues = ((drawIdx > 0u) ? refEmptyValues : refRecordedValues);
3826         for (size_t vertIdx = 0u; vertIdx < vertices.size(); ++vertIdx)
3827         {
3828             const auto vertexDataPtr = dataPtr + (vertIdx * xfbChunkSize) + (drawIdx * vertices.size() * xfbChunkSize);
3829             tcu::Vec3 vertValues(0.0f, 0.0f, 0.0f);
3830             deMemcpy(&vertValues, vertexDataPtr, sizeof(vertValues));
3831 
3832             if (vertValues != refValues)
3833             {
3834                 std::ostringstream msg;
3835                 msg << "Invalid data found for vertex " << vertIdx << ": expected " << refRecordedValues
3836                     << " and found " << vertValues;
3837                 TCU_FAIL(msg.str());
3838             }
3839         }
3840     }
3841 
3842     return tcu::TestStatus::pass("Pass");
3843 }
3844 
3845 class TransformFeedbackMaxOutputComponentsInstance : public vkt::TestInstance
3846 {
3847 public:
3848     TransformFeedbackMaxOutputComponentsInstance(Context &context, const TestParameters &parameters);
3849     tcu::TestStatus iterate(void) override;
3850 
3851 protected:
3852     const TestParameters m_parameters;
3853 };
3854 
TransformFeedbackMaxOutputComponentsInstance(Context & context,const TestParameters & parameters)3855 TransformFeedbackMaxOutputComponentsInstance::TransformFeedbackMaxOutputComponentsInstance(
3856     Context &context, const TestParameters &parameters)
3857     : vkt::TestInstance(context)
3858     , m_parameters(parameters)
3859 {
3860 }
3861 
iterate(void)3862 tcu::TestStatus TransformFeedbackMaxOutputComponentsInstance::iterate(void)
3863 {
3864     const auto &ctx = m_context.getContextCommonData();
3865     const tcu::IVec3 fbExtent(1, 1, 1);
3866     const auto vkExtent  = makeExtent3D(fbExtent);
3867     const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
3868 
3869     // Vertices for a full-screen triangle.
3870     const std::vector<tcu::Vec4> vertices{
3871         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
3872         tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
3873         tcu::Vec4(3.0f, -1.0f, 0.0f, 1.0f),
3874     };
3875     const auto totalParts  = m_parameters.partCount + 1u /*gl_Position*/;
3876     const auto totalComps  = totalParts * kVec4Components;
3877     const auto vertexCount = de::sizeU32(vertices);
3878 
3879     // Transform feedback buffer.
3880     const auto xfbBufferSize = static_cast<VkDeviceSize>(vertexCount * totalComps * sizeof(float));
3881     const auto xfbBufferInfo = makeBufferCreateInfo(xfbBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3882     BufferWithMemory xfbBuffer(ctx.vkd, ctx.device, ctx.allocator, xfbBufferInfo, MemoryRequirement::HostVisible);
3883     const auto xfbBufferAlloc  = xfbBuffer.getAllocation();
3884     void *xfbBufferData        = xfbBufferAlloc.getHostPtr();
3885     const auto xfbBufferOffset = static_cast<VkDeviceSize>(0);
3886 
3887     deMemset(xfbBufferData, 0, static_cast<size_t>(xfbBufferSize));
3888     flushAlloc(ctx.vkd, ctx.device, xfbBufferAlloc);
3889 
3890     // Vertex buffer
3891     const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
3892     const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
3893     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
3894     const auto vbAlloc  = vertexBuffer.getAllocation();
3895     void *vbData        = vbAlloc.getHostPtr();
3896     const auto vbOffset = static_cast<VkDeviceSize>(0);
3897 
3898     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
3899     flushAlloc(ctx.vkd, ctx.device, vbAlloc); // strictly speaking, not needed.
3900 
3901     const auto pipelineLayout = vk::makePipelineLayout(ctx.vkd, ctx.device);
3902     const auto renderPass     = vk::makeRenderPass(ctx.vkd, ctx.device);
3903     const auto framebuffer =
3904         makeFramebuffer(ctx.vkd, ctx.device, *renderPass, 0u, nullptr, vkExtent.width, vkExtent.height);
3905 
3906     // Modules.
3907     const auto &binaries  = m_context.getBinaryCollection();
3908     const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
3909 
3910     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
3911     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
3912 
3913     const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
3914         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
3915         nullptr,                                                    // const void* pNext;
3916         0u,                                                         // VkPipelineRasterizationStateCreateFlags flags;
3917         VK_FALSE,                                                   // VkBool32 depthClampEnable;
3918         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
3919         VK_POLYGON_MODE_FILL,                                       // VkPolygonMode polygonMode;
3920         VK_CULL_MODE_NONE,                                          // VkCullModeFlags cullMode;
3921         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
3922         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
3923         0.0f,                                                       // float depthBiasConstantFactor;
3924         0.0f,                                                       // float depthBiasClamp;
3925         0.0f,                                                       // float depthBiasSlopeFactor;
3926         1.0f,                                                       // float lineWidth;
3927     };
3928 
3929     const auto pipeline =
3930         makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE, VK_NULL_HANDLE,
3931                              VK_NULL_HANDLE, VK_NULL_HANDLE, *renderPass, viewports, scissors,
3932                              VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, nullptr, &rasterizationStateCreateInfo);
3933 
3934     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
3935     const auto cmdBuffer = *cmd.cmdBuffer;
3936 
3937     beginCommandBuffer(ctx.vkd, cmdBuffer);
3938     beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u));
3939     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
3940     ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
3941     ctx.vkd.cmdBindTransformFeedbackBuffersEXT(cmdBuffer, 0u, 1u, &xfbBuffer.get(), &xfbBufferOffset, &xfbBufferSize);
3942     ctx.vkd.cmdBeginTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3943     ctx.vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
3944     ctx.vkd.cmdEndTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3945     endRenderPass(ctx.vkd, cmdBuffer);
3946     const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3947     ctx.vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
3948                                1u, &preHostBarrier, 0u, nullptr, 0u, nullptr);
3949     endCommandBuffer(ctx.vkd, cmdBuffer);
3950     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
3951 
3952     // Verify transform feedback buffer.
3953     invalidateAlloc(ctx.vkd, ctx.device, xfbBufferAlloc);
3954 
3955     uint32_t valIdx      = 0u;
3956     const auto xfbValues = reinterpret_cast<const char *>(xfbBufferData);
3957     for (uint32_t vertIdx = 0u; vertIdx < vertexCount; ++vertIdx)
3958         for (uint32_t partIdx = 0u; partIdx < totalParts; ++partIdx)
3959             for (uint32_t compIdx = 0u; compIdx < kVec4Components; ++compIdx)
3960             {
3961                 // Must match vertex shader.
3962                 // Note for outputs other than gl_Position, the component order is reversed due to the xfb offsets in the shader.
3963                 const auto expectedVal =
3964                     ((partIdx == 0u) // gl_Position?
3965                          ?
3966                          (vertices.at(vertIdx)[compIdx]) :
3967                          (static_cast<float>(vertIdx + 1u) * 10000.0f + static_cast<float>(partIdx) * 10.0f +
3968                           static_cast<float>(kVec4Components - 1u - compIdx)));
3969                 const auto bufferOffset = sizeof(float) * valIdx;
3970 
3971                 float result = 0.0f;
3972                 deMemcpy(&result, xfbValues + bufferOffset, sizeof(float));
3973 
3974                 if (result != expectedVal)
3975                 {
3976                     std::ostringstream msg;
3977                     msg << "XFB Buffer value at position " << valIdx << " (" << result
3978                         << ") does not match expected value (" << expectedVal << "); vertex=" << vertIdx
3979                         << " vector=" << partIdx << " component=" << compIdx;
3980                     TCU_FAIL(msg.str());
3981                 }
3982 
3983                 ++valIdx;
3984             }
3985 
3986     return tcu::TestStatus::pass("Pass");
3987 }
3988 
3989 class TransformFeedbackTestCase : public vkt::TestCase
3990 {
3991 public:
3992     TransformFeedbackTestCase(tcu::TestContext &context, const char *name, const TestParameters &parameters);
3993 
3994 protected:
3995     vkt::TestInstance *createInstance(vkt::Context &context) const;
3996     void initPrograms(SourceCollections &programCollection) const;
3997     virtual void checkSupport(Context &context) const;
3998 
3999     TestParameters m_parameters;
4000 };
4001 
TransformFeedbackTestCase(tcu::TestContext & context,const char * name,const TestParameters & parameters)4002 TransformFeedbackTestCase::TransformFeedbackTestCase(tcu::TestContext &context, const char *name,
4003                                                      const TestParameters &parameters)
4004     : TestCase(context, name)
4005     , m_parameters(parameters)
4006 {
4007 }
4008 
vectorToString(const std::vector<uint32_t> & v)4009 std::string vectorToString(const std::vector<uint32_t> &v)
4010 {
4011     std::ostringstream css;
4012 
4013     DE_ASSERT(!v.empty());
4014 
4015     for (auto x : v)
4016         css << x << ",";
4017 
4018     return css.str().substr(0, css.str().size() - 1);
4019 }
4020 
createInstance(vkt::Context & context) const4021 vkt::TestInstance *TransformFeedbackTestCase::createInstance(vkt::Context &context) const
4022 {
4023     if (m_parameters.testType == TEST_TYPE_BASIC)
4024         return new TransformFeedbackBasicTestInstance(context, m_parameters);
4025 
4026     if (m_parameters.testType == TEST_TYPE_RESUME)
4027         return new TransformFeedbackResumeTestInstance(context, m_parameters);
4028 
4029     if (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)
4030         return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
4031 
4032     if (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)
4033         return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
4034 
4035     if (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)
4036         return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
4037 
4038     if (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL)
4039         return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
4040 
4041     if (m_parameters.testType == TEST_TYPE_WINDING)
4042         return new TransformFeedbackWindingOrderTestInstance(context, m_parameters);
4043 
4044     if (m_parameters.testType == TEST_TYPE_STREAMS)
4045         return new TransformFeedbackStreamsTestInstance(context, m_parameters);
4046 
4047     if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
4048         return new TransformFeedbackStreamsTestInstance(context, m_parameters);
4049 
4050     if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE)
4051         return new TransformFeedbackStreamsTestInstance(context, m_parameters);
4052 
4053     if (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
4054         return new TransformFeedbackStreamsTestInstance(context, m_parameters);
4055 
4056     if (m_parameters.testType == TEST_TYPE_MULTISTREAMS)
4057         return new TransformFeedbackMultistreamTestInstance(context, m_parameters);
4058 
4059     if (m_parameters.testType == TEST_TYPE_MULTISTREAMS_SAME_LOCATION)
4060         return new TransformFeedbackMultistreamSameLocationTestInstance(context, m_parameters);
4061 
4062     if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT)
4063         return new TransformFeedbackIndirectDrawTestInstance(context, m_parameters, false);
4064 
4065     if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
4066         return new TransformFeedbackIndirectDrawTestInstance(context, m_parameters, true);
4067 
4068     if (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY ||
4069         m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT)
4070         return new TransformFeedbackBackwardDependencyTestInstance(context, m_parameters);
4071 
4072     if (m_parameters.testType == TEST_TYPE_QUERY_GET || m_parameters.testType == TEST_TYPE_QUERY_COPY ||
4073         m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO || m_parameters.testType == TEST_TYPE_QUERY_RESET)
4074         return new TransformFeedbackQueryTestInstance(context, m_parameters);
4075 
4076     if (m_parameters.testType == TEST_TYPE_MULTIQUERY)
4077         return new TransformFeedbackMultiQueryTestInstance(context, m_parameters);
4078 
4079     if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX ||
4080         m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY ||
4081         m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
4082         return new TransformFeedbackDepthClipControlTestInstance(context, m_parameters);
4083 
4084     if (m_parameters.testType == TEST_TYPE_LINES_TRIANGLES)
4085         return new TransformFeedbackLinesOrTrianglesTestInstance(context, m_parameters);
4086 
4087     if (m_parameters.testType == TEST_TYPE_DRAW_OUTSIDE)
4088         return new TransformFeedbackDrawOutsideTestInstance(context, m_parameters);
4089 
4090     if (m_parameters.testType == TEST_TYPE_HOLES_VERTEX || m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
4091     {
4092         // We repurpose partCount to indicate somehow the number of draws.
4093         const bool extraDraw = (m_parameters.partCount > 1u);
4094         return new TransformFeedbackHolesInstance(context, extraDraw);
4095     }
4096 
4097     if (m_parameters.testType == TEST_TYPE_MAX_OUTPUT_COMPONENTS)
4098         return new TransformFeedbackMaxOutputComponentsInstance(context, m_parameters);
4099 
4100     TCU_THROW(InternalError, "Specified test type not found");
4101 }
4102 
checkSupport(Context & context) const4103 void TransformFeedbackTestCase::checkSupport(Context &context) const
4104 {
4105     context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
4106 
4107     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
4108                                           m_parameters.pipelineConstructionType);
4109 
4110     context.requireDeviceFunctionality("VK_EXT_transform_feedback");
4111 
4112     if (context.getTransformFeedbackFeaturesEXT().transformFeedback == VK_FALSE)
4113         TCU_THROW(NotSupportedError, "transformFeedback feature is not supported");
4114 
4115     if (m_parameters.useMaintenance5)
4116         context.requireDeviceFunctionality("VK_KHR_maintenance5");
4117 
4118     const auto &xfbProperties = context.getTransformFeedbackPropertiesEXT();
4119 
4120     // transformFeedbackRasterizationStreamSelect is required when vertex streams other than zero are rasterized
4121     if (m_parameters.requireRastStreamSelect &&
4122         (xfbProperties.transformFeedbackRasterizationStreamSelect == VK_FALSE) && (m_parameters.streamId > 0))
4123         TCU_THROW(NotSupportedError, "transformFeedbackRasterizationStreamSelect property is not supported");
4124 
4125     if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
4126     {
4127         const auto &features = context.getMultiviewFeatures();
4128         if (!features.multiview)
4129             TCU_THROW(NotSupportedError, "multiview not supported");
4130     }
4131 
4132     if (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT)
4133         context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
4134 
4135     if (m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
4136         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
4137 
4138     if (m_parameters.pointSize > 1u)
4139         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
4140 
4141     if (m_parameters.usingGeom())
4142         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
4143 
4144     if (m_parameters.usingTess())
4145         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
4146 
4147     const auto &coreFeatures = context.getDeviceFeatures();
4148 
4149     if (m_parameters.pointSizeWanted() && m_parameters.usingTessGeom() &&
4150         !coreFeatures.shaderTessellationAndGeometryPointSize)
4151         TCU_THROW(NotSupportedError, "shaderTessellationAndGeometryPointSize not supported");
4152 
4153     if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
4154         context.requireDeviceFunctionality("VK_EXT_host_query_reset");
4155 
4156     if (m_parameters.testType == TEST_TYPE_MAX_OUTPUT_COMPONENTS)
4157     {
4158         const auto &maxComps  = context.getDeviceProperties().limits.maxVertexOutputComponents;
4159         const auto totalComps = (m_parameters.partCount + 1u /*gl_Position*/) * kVec4Components;
4160 
4161         if (totalComps > maxComps)
4162             TCU_THROW(NotSupportedError, "Required number of output components not supported");
4163 
4164         const auto compSize      = static_cast<uint32_t>(sizeof(float));
4165         const auto perVertexSize = totalComps * compSize;
4166         const auto messagePrefix = "Required vertex data size (" + std::to_string(perVertexSize) + ") greater than ";
4167 
4168         if (perVertexSize > xfbProperties.maxTransformFeedbackBufferDataSize)
4169             TCU_THROW(NotSupportedError, messagePrefix + "maxTransformFeedbackBufferDataSize");
4170 
4171         if (perVertexSize > xfbProperties.maxTransformFeedbackStreamDataSize)
4172             TCU_THROW(NotSupportedError, messagePrefix + "maxTransformFeedbackStreamDataSize");
4173 
4174         if (perVertexSize > xfbProperties.maxTransformFeedbackBufferDataStride)
4175             TCU_THROW(NotSupportedError, messagePrefix + "maxTransformFeedbackBufferDataStride");
4176     }
4177 }
4178 
initPrograms(SourceCollections & programCollection) const4179 void TransformFeedbackTestCase::initPrograms(SourceCollections &programCollection) const
4180 {
4181     const bool backwardDependency = (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY ||
4182                                      m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT);
4183     const bool vertexShaderOnly =
4184         m_parameters.testType == TEST_TYPE_BASIC || m_parameters.testType == TEST_TYPE_RESUME ||
4185         (m_parameters.testType == TEST_TYPE_WINDING && m_parameters.primTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
4186     const bool requiresFullPipeline = m_parameters.requiresFullPipeline();
4187     const bool xfbBuiltinPipeline =
4188         m_parameters.testType == TEST_TYPE_XFB_POINTSIZE || m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE ||
4189         m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE || m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL;
4190     const bool pointSizeWanted = m_parameters.pointSizeWanted();
4191     const auto pointSizeStr    = std::to_string(m_parameters.pointSize);
4192 
4193     if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX)
4194     {
4195         // Vertex shader
4196         {
4197             std::ostringstream src;
4198             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4199                 << "\n"
4200                 << "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
4201                 << "{\n"
4202                 << "    vec4 gl_Position;\n"
4203                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
4204                 << "\n"
4205                 << "void main(void)\n"
4206                 << "{\n"
4207                 << "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
4208                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "}\n";
4209 
4210             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4211         }
4212 
4213         return;
4214     }
4215 
4216     if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY)
4217     {
4218         // Vertex shader
4219         {
4220             std::ostringstream src;
4221             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4222                 << "\n"
4223                 << "out gl_PerVertex\n"
4224                 << "{\n"
4225                 << "    vec4  gl_Position;\n"
4226                 << "};\n"
4227                 << "\n"
4228                 << "void main(void)\n"
4229                 << "{\n"
4230                 << "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
4231                 << "}\n";
4232 
4233             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4234         }
4235 
4236         // Geometry shader
4237         {
4238             std::ostringstream src;
4239             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4240                 << "\n"
4241                 << "layout(points) in;\n"
4242                 << "layout(points, max_vertices = 1) out;\n"
4243                 << "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
4244                 << "{\n"
4245                 << "    vec4 gl_Position;\n"
4246                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
4247                 << "\n"
4248                 << "in gl_PerVertex\n"
4249                 << "{\n"
4250                 << "    vec4  gl_Position;\n"
4251                 << "} gl_in[];\n"
4252                 << "\n"
4253                 << "void main(void)\n"
4254                 << "{\n"
4255                 << "    gl_Position = gl_in[0].gl_Position;\n"
4256                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "    EmitVertex();\n"
4257                 << "    EndPrimitive();\n"
4258                 << "}\n";
4259 
4260             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4261         }
4262 
4263         return;
4264     }
4265 
4266     if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
4267     {
4268         // Vertex shader
4269         {
4270             std::ostringstream src;
4271             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4272                 << "\n"
4273                 << "out gl_PerVertex\n"
4274                 << "{\n"
4275                 << "    vec4  gl_Position;\n"
4276                 << "};\n"
4277                 << "\n"
4278                 << "void main(void)\n"
4279                 << "{\n"
4280                 << "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
4281                 << "}\n";
4282 
4283             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4284         }
4285 
4286         // Tesselation control shader
4287         {
4288             std::ostringstream src;
4289             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4290                 << "layout(vertices = 3) out;\n"
4291                 << "in gl_PerVertex\n"
4292                 << "{\n"
4293                 << "    vec4 gl_Position;\n"
4294                 << "} gl_in[gl_MaxPatchVertices];\n"
4295                 << "out gl_PerVertex\n"
4296                 << "{\n"
4297                 << "    vec4 gl_Position;\n"
4298                 << "} gl_out[];\n"
4299                 << "void main (void)\n"
4300                 << "{\n"
4301                 << "    gl_TessLevelInner[0] = 0.0;\n"
4302                 << "    gl_TessLevelOuter[0] = 1.0;\n"
4303                 << "    gl_TessLevelOuter[1] = 1.0;\n"
4304                 << "    gl_TessLevelOuter[2] = 1.0;\n"
4305                 << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
4306                 << "}\n";
4307             programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
4308         }
4309 
4310         // Tessellation evaluation shader
4311         {
4312             std::ostringstream src;
4313             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4314                 << "layout(triangles, ccw) in;\n"
4315                 << "in gl_PerVertex\n"
4316                 << "{\n"
4317                 << "    vec4 gl_Position;\n"
4318                 << "} gl_in[gl_MaxPatchVertices];\n"
4319                 << "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
4320                 << "{\n"
4321                 << "    vec4 gl_Position;\n"
4322                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
4323                 << "\n"
4324                 << "void main (void)\n"
4325                 << "{\n"
4326                 << "    vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position;\n"
4327                 << "    vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position;\n"
4328                 << "    vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position;\n"
4329                 << "    gl_Position = p0 + p1 + p2;\n"
4330                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "}\n";
4331             programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
4332         }
4333 
4334         return;
4335     }
4336 
4337     if (vertexShaderOnly)
4338     {
4339         // Vertex shader
4340         {
4341             std::ostringstream src;
4342             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4343                 << "\n"
4344                 << "layout(push_constant) uniform pushConstants\n"
4345                 << "{\n"
4346                 << "    uint start;\n"
4347                 << "} uInput;\n"
4348                 << "\n"
4349                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
4350                 << "\n"
4351                 << "void main(void)\n"
4352                 << "{\n"
4353                 << "    idx_out = uInput.start + gl_VertexIndex;\n"
4354                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "}\n";
4355 
4356             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4357         }
4358 
4359         return;
4360     }
4361 
4362     if (backwardDependency)
4363     {
4364         // Vertex shader.
4365         {
4366             std::ostringstream src;
4367             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4368                 << "\n"
4369                 << "layout(push_constant, std430) uniform PushConstantBlock\n"
4370                 << "{\n"
4371                 << "    uint  start;\n"
4372                 << "    float width;\n"
4373                 << "    float posY;\n"
4374                 << "} pc;\n"
4375                 << "\n"
4376                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
4377                 << "\n"
4378                 << "void main(void)\n"
4379                 << "{\n"
4380                 << "    idx_out           = pc.start + gl_VertexIndex;\n"
4381                 << "    const float posX  = ((float(gl_VertexIndex) + 0.5) / pc.width) * 2.0 - 1.0;\n"
4382                 << "    gl_Position       = vec4(posX, pc.posY, 0.0, 1.0);\n"
4383                 << "    gl_PointSize      = 1.0;\n"
4384                 << "}\n";
4385 
4386             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4387         }
4388 
4389         // Fragment shader.
4390         {
4391             std::ostringstream frag;
4392             frag << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4393                  << "layout (location=0) out vec4 outColor;\n"
4394                  << "void main (void) { outColor = vec4(0.0, 0.0, 1.0, 1.0); }\n";
4395             programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
4396         }
4397 
4398         return;
4399     }
4400 
4401     if (m_parameters.primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
4402     {
4403         // Vertex shader
4404         {
4405             std::ostringstream src;
4406             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4407                 << "layout(push_constant) uniform pushConstants\n"
4408                 << "{\n"
4409                 << "    uint start;\n"
4410                 << "} uInput;\n"
4411                 << "void main(void)\n"
4412                 << "{\n"
4413                 << "}\n";
4414             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4415         }
4416 
4417         // Tesselation control shader
4418         {
4419             std::ostringstream src;
4420             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4421                 << "layout(vertices = 3) out;\n"
4422                 << "void main (void)\n"
4423                 << "{\n"
4424                 << "    gl_TessLevelInner[0] = 2.0;\n" // generate three triangles out of each patch
4425                 << "    gl_TessLevelOuter[0] = 1.0;\n"
4426                 << "    gl_TessLevelOuter[1] = 1.0;\n"
4427                 << "    gl_TessLevelOuter[2] = 1.0;\n"
4428                 << "}\n";
4429             programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
4430         }
4431 
4432         // Tessellation evaluation shader
4433         {
4434             std::ostringstream src;
4435             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4436                 << "layout(triangles, ccw) in;\n"
4437                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
4438                 << (pointSizeWanted ? "out gl_PerVertex { float gl_PointSize; };\n" : "") << "\n"
4439                 << "\n"
4440                 << "void main (void)\n"
4441                 << "{\n"
4442                 << "    idx_out = gl_PrimitiveID;\n" // all vertex generated from patch will have its id
4443                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "}\n";
4444             programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
4445         }
4446 
4447         return;
4448     }
4449 
4450     if (xfbBuiltinPipeline)
4451     {
4452         const std::string outputBuiltIn =
4453             (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE) ?
4454                 "float gl_PointSize;\n" :
4455             (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE) ?
4456                 (std::string("float gl_ClipDistance[") + (pointSizeWanted ? "7" : "8") + "];\n" +
4457                  (pointSizeWanted ? "float gl_PointSize;\n" : "")) :
4458             (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE) ?
4459                 (std::string("float gl_CullDistance[") + (pointSizeWanted ? "7" : "8") + "];\n" +
4460                  (pointSizeWanted ? "float gl_PointSize;\n" : "")) :
4461             (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ?
4462                 (std::string("float gl_CullDistance[") + (pointSizeWanted ? "4" : "5") +
4463                  "];\nfloat gl_ClipDistance[1];\n" + (pointSizeWanted ? "float gl_PointSize;\n" : "")) :
4464                 "";
4465         const std::string operationBuiltIn =
4466             (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE) ?
4467                 "gl_PointSize = float(gl_VertexIndex) / 32768.0f;\n" :
4468             (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE) ?
4469                 (pointSizeWanted ? "gl_PointSize = " + pointSizeStr + ".0;\n" : "") + std::string("for (int i=0; i<") +
4470                     (pointSizeWanted ? "7" : "8") +
4471                     "; i++) gl_ClipDistance[i] = float(8 * gl_VertexIndex + i) / 32768.0f;\n" :
4472             (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE) ?
4473                 (pointSizeWanted ? "gl_PointSize = " + pointSizeStr + ".0;\n" : "") + std::string("for (int i=0; i<") +
4474                     (pointSizeWanted ? "7" : "8") +
4475                     "; i++) gl_CullDistance[i] = float(8 * gl_VertexIndex + i) / 32768.0f;\n" :
4476             (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ?
4477                 (pointSizeWanted ? "gl_PointSize = " + pointSizeStr + ".0;\n" : "") + std::string("for (int i=0; i<") +
4478                     (pointSizeWanted ? "4" : "5") +
4479                     "; i++) gl_CullDistance[i] = float(6 * gl_VertexIndex + i) / 32768.0f;\n"
4480                     "gl_ClipDistance[0] = float(6 * gl_VertexIndex + " +
4481                     (pointSizeWanted ? "4" : "5") + ") / 32768.0f;\n" :
4482                 "";
4483 
4484         // Vertex shader
4485         {
4486             std::ostringstream src;
4487             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4488                 << "\n"
4489                 << "layout(xfb_buffer = " << m_parameters.partCount - 1 << ", xfb_offset = 0) out gl_PerVertex\n"
4490                 << "{\n"
4491                 << outputBuiltIn << "};\n"
4492                 << "\n"
4493                 << "void main(void)\n"
4494                 << "{\n"
4495                 << operationBuiltIn << "}\n";
4496 
4497             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4498         }
4499 
4500         return;
4501     }
4502 
4503     if (m_parameters.testType == TEST_TYPE_MULTISTREAMS)
4504     {
4505         // vertex shader
4506         {
4507             std::ostringstream src;
4508             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4509                 << "\n"
4510                 << "void main(void)\n"
4511                 << "{\n"
4512                 << "}\n";
4513 
4514             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4515         }
4516 
4517         // geometry shader
4518         {
4519             const uint32_t s = m_parameters.streamId;
4520             std::ostringstream src;
4521 
4522             DE_ASSERT(s != 0);
4523 
4524             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4525                 << "\n"
4526                 << "layout(points) in;\n"
4527                 << "\n"
4528                 << "layout(points, max_vertices = 32) out;\n"
4529                 << "layout(stream = " << 0
4530                 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
4531                 << "layout(stream = " << s
4532                 << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
4533                 << "\n"
4534                 << "const int counts[] = int[](1, 1, 2, 4, 8);\n"
4535                 << "\n"
4536                 << (pointSizeWanted ? "out gl_PerVertex { float gl_PointSize; };\n\n" : "") << "void main(void)\n"
4537                 << "{\n"
4538                 << "    int c0 = 0;\n"
4539                 << "    int c1 = 0;\n"
4540                 << "\n"
4541                 << "    // Start 1st buffer from point where 0th buffer ended\n"
4542                 << "    for (int i = 0; i < counts.length(); i++)\n"
4543                 << "        c1 = c1 + 4 * counts[i];\n"
4544                 << "\n"
4545                 << "    for (int i = 0; i < counts.length(); i++)\n"
4546                 << "    {\n"
4547                 << "        const int n0 = counts[i];\n"
4548                 << "        const int n1 = counts[counts.length() - 1 - i];\n"
4549                 << "\n"
4550                 << "        for (int j = 0; j < n0; j++)\n"
4551                 << "        {\n"
4552                 << "            out0 = vec4(ivec4(c0, c0 + 1, c0 + 2, c0 + 3));\n"
4553                 << "            c0 = c0 + 4;\n"
4554                 << (pointSizeWanted ? "            gl_PointSize = " + pointSizeStr + ".0;\n" : "")
4555                 << "            EmitStreamVertex(0);\n"
4556                 << "            EndStreamPrimitive(0);\n"
4557                 << "        }\n"
4558                 << "\n"
4559                 << "        for (int j = 0; j < n1; j++)\n"
4560                 << "        {\n"
4561                 << "            out1 = vec4(ivec4(c1, c1 + 1, c1 + 2, c1 + 3));\n"
4562                 << "            c1 = c1 + 4;\n"
4563                 << (pointSizeWanted ? "            gl_PointSize = " + pointSizeStr + ".0;\n" : "")
4564                 << "            EmitStreamVertex(" << s << ");\n"
4565                 << "            EndStreamPrimitive(" << s << ");\n"
4566                 << "        }\n"
4567                 << "    }\n"
4568                 << "}\n";
4569 
4570             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4571         }
4572 
4573         return;
4574     }
4575 
4576     if (m_parameters.testType == TEST_TYPE_MULTISTREAMS_SAME_LOCATION)
4577     {
4578         // vertex shader
4579         {
4580             std::ostringstream src;
4581             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4582                 << "\n"
4583                 << "layout(location=0) out uint id;"
4584                 << "void main(void)\n"
4585                 << "{\n"
4586                 << "  id = gl_VertexIndex;"
4587                 << "}\n";
4588 
4589             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4590         }
4591 
4592         // geometry shader
4593         {
4594             const uint32_t s = m_parameters.streamId;
4595             std::ostringstream src;
4596 
4597             DE_ASSERT(s != 0);
4598 
4599             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4600                 << "\n"
4601                 << "layout(points) in;\n"
4602                 << "\n"
4603                 << "layout(points, max_vertices = 2) out;\n"
4604                 << "\n"
4605                 << "layout(location=0) in uint id[1];"
4606                 << "layout(stream = " << 0
4607                 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0, component = 0) out uint out0;\n"
4608                 << "layout(stream = " << s
4609                 << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 4, location = 0, component = 1) out uint out1;\n"
4610                 << "\n"
4611                 << (pointSizeWanted ? "out gl_PerVertex { float gl_PointSize; };\n\n" : "") << "void main(void)\n"
4612                 << "{\n"
4613                 << "    out0 = id[0] * 2 + 0;\n"
4614                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "")
4615                 << "    EmitStreamVertex(0);\n"
4616                 << "    EndStreamPrimitive(0);\n"
4617                 << "\n"
4618                 << "    out1 = id[0] * 2 + 1;\n"
4619                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "    EmitStreamVertex("
4620                 << s << ");\n"
4621                 << "    EndStreamPrimitive(" << s << ");\n"
4622                 << "}\n";
4623 
4624             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4625         }
4626 
4627         return;
4628     }
4629 
4630     if (requiresFullPipeline)
4631     {
4632         // vertex shader
4633         {
4634             std::ostringstream src;
4635             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4636                 << "\n"
4637                 << "void main(void)\n"
4638                 << "{\n"
4639                 << "}\n";
4640 
4641             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4642         }
4643 
4644         // geometry shader
4645         {
4646             const uint32_t s                      = m_parameters.streamId;
4647             const bool requirePoints              = m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE;
4648             const std::string outputPrimitiveType = requirePoints ? "points" : "triangle_strip";
4649             const std::string pointSizeDecl       = "    float gl_PointSize;\n";
4650             const std::string extraDecl           = (pointSizeWanted ? pointSizeDecl : "");
4651             const std::string extraStmt           = (pointSizeWanted ? "gl_PointSize = " + pointSizeStr + ".0; " : "");
4652             const std::string outputBuiltIn       = (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE) ?
4653                                                         pointSizeDecl :
4654                                                     (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE) ?
4655                                                         "    float gl_ClipDistance[];\n" + extraDecl :
4656                                                     (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE) ?
4657                                                         "    float gl_CullDistance[];\n" + extraDecl :
4658                                                         extraDecl;
4659             std::ostringstream src;
4660 
4661             DE_ASSERT(s != 0);
4662 
4663             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4664                 << "\n"
4665                 << "layout(points) in;\n"
4666                 << "layout(" << outputPrimitiveType << ", max_vertices = 16) out;\n"
4667                 << "layout(stream = " << s << ") out;\n"
4668                 << "layout(location = 0) out vec4 color;\n"
4669                 << "\n"
4670                 << "layout(stream = " << s << ") out gl_PerVertex\n"
4671                 << "{\n"
4672                 << "    vec4 gl_Position;\n"
4673                 << outputBuiltIn << "};\n"
4674                 << "\n"
4675                 << "void main(void)\n"
4676                 << "{\n"
4677                 << "    // Color constants\n"
4678                 << "    vec4 g = vec4(0.0, 1.0, 0.0, 1.0);\n"
4679                 << "    vec4 m = vec4(1.0, 0.0, 1.0, 1.0);\n"
4680                 << "    // Coordinate constants: leftmost column\n"
4681                 << "    vec4 a = vec4(-1.0,-1.0, 0.0, 1.0);\n"
4682                 << "    vec4 b = vec4(-1.0, 0.0, 0.0, 1.0);\n"
4683                 << "    vec4 c = vec4(-1.0, 1.0, 0.0, 1.0);\n"
4684                 << "    // Coordinate constants: middle column\n"
4685                 << "    vec4 i = vec4( 0.0,-1.0, 0.0, 1.0);\n"
4686                 << "    vec4 j = vec4( 0.0, 0.0, 0.0, 1.0);\n"
4687                 << "    vec4 k = vec4( 0.0, 1.0, 0.0, 1.0);\n"
4688                 << "    // Coordinate constants: rightmost column\n"
4689                 << "    vec4 x = vec4( 1.0,-1.0, 0.0, 1.0);\n"
4690                 << "    vec4 y = vec4( 1.0, 0.0, 0.0, 1.0);\n"
4691                 << "    vec4 z = vec4( 1.0, 1.0, 0.0, 1.0);\n"
4692                 << "\n";
4693 
4694             if (m_parameters.testType == TEST_TYPE_STREAMS)
4695             {
4696                 src << "    if (gl_PrimitiveIDIn == 0)\n"
4697                     << "    {\n"
4698                     << "        color = m; gl_Position = b; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4699                     << "        color = m; gl_Position = y; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4700                     << "        color = m; gl_Position = c; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4701                     << "        EndStreamPrimitive(" << s << ");\n"
4702                     << "    }\n"
4703                     << "    else\n"
4704                     << "    {\n"
4705                     << "        color = m; gl_Position = y; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4706                     << "        color = m; gl_Position = c; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4707                     << "        color = m; gl_Position = z; " + extraStmt + "EmitStreamVertex(" << s << ");\n"
4708                     << "        EndStreamPrimitive(" << s << ");\n"
4709                     << "    }\n";
4710             }
4711 
4712             if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
4713             {
4714                 const std::string pointSize = "gl_PointSize = " + de::toString(m_parameters.pointSize) + ".0f";
4715 
4716                 src << "    if (gl_PrimitiveIDIn == 0)\n"
4717                     << "    {\n"
4718                     << "        color = g; gl_Position = (a + j) / 2.0f; gl_PointSize = 1.0f; EmitStreamVertex(0);\n"
4719                     << "        EndStreamPrimitive(0);\n"
4720                     << "        color = m; gl_Position = (b + k) / 2.0f; gl_PointSize = 1.0f; EmitStreamVertex(" << s
4721                     << ");\n"
4722                     << "        EndStreamPrimitive(" << s << ");\n"
4723                     << "    }\n"
4724                     << "    else\n"
4725                     << "    {\n"
4726                     << "        color = g; gl_Position = (j + x) / 2.0f; " << pointSize << "; EmitStreamVertex(0);\n"
4727                     << "        EndStreamPrimitive(0);\n"
4728                     << "        color = m; gl_Position = (k + y) / 2.0f; " << pointSize << "; EmitStreamVertex(" << s
4729                     << ");\n"
4730                     << "        EndStreamPrimitive(" << s << ");\n"
4731                     << "    }\n";
4732             }
4733 
4734             if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE)
4735             {
4736                 src << "    if (gl_PrimitiveIDIn == 0)\n"
4737                     << "    {\n"
4738                     << "        color = m; gl_Position = b; gl_ClipDistance[0] = -1.0; " + extraStmt +
4739                            "EmitStreamVertex("
4740                     << s << ");\n"
4741                     << "        color = m; gl_Position = c; gl_ClipDistance[0] = -1.0; " + extraStmt +
4742                            "EmitStreamVertex("
4743                     << s << ");\n"
4744                     << "        color = m; gl_Position = y; gl_ClipDistance[0] =  1.0; " + extraStmt +
4745                            "EmitStreamVertex("
4746                     << s << ");\n"
4747                     << "        EndStreamPrimitive(" << s << ");\n"
4748                     << "    }\n"
4749                     << "    else\n"
4750                     << "    {\n"
4751                     << "        color = m; gl_Position = y; gl_ClipDistance[0] =  1.0; " + extraStmt +
4752                            "EmitStreamVertex("
4753                     << s << ");\n"
4754                     << "        color = m; gl_Position = c; gl_ClipDistance[0] = -1.0; " + extraStmt +
4755                            "EmitStreamVertex("
4756                     << s << ");\n"
4757                     << "        color = m; gl_Position = z; gl_ClipDistance[0] =  1.0; " + extraStmt +
4758                            "EmitStreamVertex("
4759                     << s << ");\n"
4760                     << "        EndStreamPrimitive(" << s << ");\n"
4761                     << "    }\n";
4762             }
4763 
4764             if (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
4765             {
4766                 src << "    if (gl_PrimitiveIDIn == 0)\n"
4767                     << "    {\n"
4768                     << "        color = m; gl_Position = b; gl_CullDistance[0] = -1.0; " + extraStmt +
4769                            "EmitStreamVertex("
4770                     << s << ");\n"
4771                     << "        color = m; gl_Position = c; gl_CullDistance[0] = -1.0; " + extraStmt +
4772                            "EmitStreamVertex("
4773                     << s << ");\n"
4774                     << "        color = m; gl_Position = j; gl_CullDistance[0] = -1.0; " + extraStmt +
4775                            "EmitStreamVertex("
4776                     << s << ");\n"
4777                     << "        EndStreamPrimitive(" << s << ");\n"
4778                     << "        color = m; gl_Position = j; gl_CullDistance[0] = -1.0; " + extraStmt +
4779                            "EmitStreamVertex("
4780                     << s << ");\n"
4781                     << "        color = m; gl_Position = c; gl_CullDistance[0] = -1.0; " + extraStmt +
4782                            "EmitStreamVertex("
4783                     << s << ");\n"
4784                     << "        color = m; gl_Position = k; gl_CullDistance[0] = -1.0; " + extraStmt +
4785                            "EmitStreamVertex("
4786                     << s << ");\n"
4787                     << "        EndStreamPrimitive(" << s << ");\n"
4788                     << "    }\n"
4789                     << "    else\n"
4790                     << "    {\n"
4791                     << "        color = m; gl_Position = j; gl_CullDistance[0] =  1.0; " + extraStmt +
4792                            "EmitStreamVertex("
4793                     << s << ");\n"
4794                     << "        color = m; gl_Position = k; gl_CullDistance[0] =  1.0; " + extraStmt +
4795                            "EmitStreamVertex("
4796                     << s << ");\n"
4797                     << "        color = m; gl_Position = y; gl_CullDistance[0] =  1.0; " + extraStmt +
4798                            "EmitStreamVertex("
4799                     << s << ");\n"
4800                     << "        EndStreamPrimitive(" << s << ");\n"
4801                     << "        color = m; gl_Position = y; gl_CullDistance[0] =  1.0; " + extraStmt +
4802                            "EmitStreamVertex("
4803                     << s << ");\n"
4804                     << "        color = m; gl_Position = k; gl_CullDistance[0] =  1.0; " + extraStmt +
4805                            "EmitStreamVertex("
4806                     << s << ");\n"
4807                     << "        color = m; gl_Position = z; gl_CullDistance[0] =  1.0; " + extraStmt +
4808                            "EmitStreamVertex("
4809                     << s << ");\n"
4810                     << "        EndStreamPrimitive(" << s << ");\n"
4811                     << "    }\n";
4812             }
4813 
4814             src << "}\n";
4815 
4816             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4817         }
4818 
4819         // Fragment shader
4820         {
4821             std::ostringstream src;
4822             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4823                 << "\n"
4824                 << "layout(location = 0) in  vec4 i_color;\n"
4825                 << "layout(location = 0) out vec4 o_color;\n"
4826                 << "\n"
4827                 << "void main(void)\n"
4828                 << "{\n"
4829                 << "    o_color = i_color;\n"
4830                 << "}\n";
4831 
4832             programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
4833         }
4834 
4835         return;
4836     }
4837 
4838     if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT || m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
4839     {
4840         // vertex shader
4841         {
4842             std::ostringstream src;
4843             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4844                 << "\n"
4845                 << "layout(location = 0) in vec4 in_position;\n"
4846                 << "\n"
4847                 << "void main(void)\n"
4848                 << "{\n"
4849                 << "    gl_Position = in_position;\n"
4850                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "") << "}\n";
4851 
4852             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4853         }
4854 
4855         // Fragment shader
4856         {
4857             std::ostringstream src;
4858             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4859                 << "\n"
4860                 << "layout(location = 0) out vec4 o_color;\n"
4861                 << "\n"
4862                 << "void main(void)\n"
4863                 << "{\n"
4864                 << "    o_color = vec4(1.0, 1.0, 1.0, 1.0);\n"
4865                 << "}\n";
4866 
4867             programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
4868         }
4869 
4870         return;
4871     }
4872 
4873     if (m_parameters.testType == TEST_TYPE_QUERY_GET || m_parameters.testType == TEST_TYPE_QUERY_COPY ||
4874         m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO || m_parameters.testType == TEST_TYPE_QUERY_RESET)
4875     {
4876         struct TopologyShaderInfo
4877         {
4878             std::string glslIn;
4879             std::string glslOut;
4880             std::string spirvIn;
4881             std::string spirvOut;
4882         };
4883 
4884         const std::map<VkPrimitiveTopology, TopologyShaderInfo> primitiveNames = {
4885             {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, {"points", "points", "InputPoints", "OutputPoints"}},
4886             {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, {"lines", "line_strip", "InputLines", "OutputLineStrip"}},
4887             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, {"lines", "line_strip", "InputLines", "OutputLineStrip"}},
4888             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, {"triangles", "triangle_strip", "Triangles", "OutputTriangleStrip"}},
4889             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, {"triangles", "triangle_strip", "Triangles", "OutputTriangleStrip"}},
4890             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, {"triangles", "triangle_strip", "Triangles", "OutputTriangleStrip"}},
4891             {VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
4892              {"lines_adjacency", "line_strip", "InputLinesAdjacency", "OutputLineStrip"}},
4893             {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
4894              {"lines_adjacency", "line_strip", "InputLinesAdjacency", "OutputLineStrip"}},
4895             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
4896              {"triangles_adjacency", "triangle_strip", "InputTrianglesAdjacency", "OutputTriangleStrip"}},
4897             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
4898              {"triangles_adjacency", "triangle_strip", "InputTrianglesAdjacency", "OutputTriangleStrip"}}};
4899 
4900         // Vertex shader
4901         {
4902             std::ostringstream src;
4903             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4904                 << "\n"
4905                 << "layout(location = 0) out vec4 out0;\n"
4906                 << "\n"
4907                 << "out gl_PerVertex\n"
4908                 << "{\n"
4909                 << "    vec4  gl_Position;\n"
4910                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
4911                 << "\n"
4912                 << "void main(void)\n"
4913                 << "{\n"
4914                 << "    gl_Position  = vec4(0.0, 0.0, 0.0, 1.0);\n"
4915                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0;\n" : "")
4916                 << "    float n = 4.0 * float(gl_VertexIndex);\n"
4917                 << "    out0 = vec4(n + 0.0, n + 1.0, n + 2.0, n + 3.0);\n"
4918                 << "}\n";
4919 
4920             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4921         }
4922 
4923         // geometry shader
4924         if (m_parameters.streamId == 0)
4925         {
4926             std::ostringstream src;
4927 
4928             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4929                 << "\n"
4930                 << "layout(" << primitiveNames.at(m_parameters.primTopology).glslIn << ") in;\n"
4931                 << "layout(location = 0) in vec4 in0[];\n"
4932                 << "\n"
4933                 << "layout(" << primitiveNames.at(m_parameters.primTopology).glslOut
4934                 << ", max_vertices = " << topologyData.at(m_parameters.primTopology).primSize << ") out;\n"
4935                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
4936                 << "\n"
4937                 << "in gl_PerVertex\n"
4938                 << "{\n"
4939                 << "    vec4  gl_Position;\n"
4940                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "} gl_in[];\n"
4941                 << "out gl_PerVertex\n"
4942                 << "{\n"
4943                 << "    vec4  gl_Position;\n"
4944                 << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
4945                 << "\n"
4946                 << "void main(void)\n"
4947                 << "{\n"
4948                 << "    gl_Position  = gl_in[0].gl_Position;\n"
4949                 << (pointSizeWanted ? "    gl_PointSize = gl_in[0].gl_PointSize;\n" : "");
4950 
4951             for (uint32_t i = 0; i < topologyData.at(m_parameters.primTopology).primSize; i++)
4952             {
4953                 if (!m_parameters.omitShaderWrite)
4954                     src << "    out0 = in0[" << i << "];\n";
4955                 src << "    EmitVertex();\n";
4956             }
4957 
4958             src << "    EndPrimitive();\n"
4959                 << "}\n";
4960 
4961             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4962         }
4963         else
4964         {
4965             const uint32_t s = m_parameters.streamId;
4966             std::ostringstream src;
4967 
4968             if (m_parameters.testType == TEST_TYPE_QUERY_GET)
4969             {
4970                 // The SPIR-V program below is roughly equivalent to the following GLSL code:
4971                 //
4972                 // #version 450
4973                 // #extension GL_ARB_enhanced_layouts : require
4974                 //
4975                 // layout(points) in;
4976                 // layout(location = 0) in vec4 in0[];
4977                 //
4978                 // layout(points, max_vertices = 1) out;
4979                 // layout(location=0, stream=1, xfb_buffer=0, xfb_stride=16) out OutBlock {
4980                 //     layout(xfb_offset=0, location=0) vec4 out0;
4981                 // } outBlock;
4982                 //
4983                 // in gl_PerVertex
4984                 // {
4985                 //     vec4  gl_Position;
4986                 //     float gl_PointSize;
4987                 // } gl_in[];
4988                 // out gl_PerVertex
4989                 // {
4990                 //     vec4  gl_Position;
4991                 //     float gl_PointSize;
4992                 // };
4993                 //
4994                 // void main(void)
4995                 // {
4996                 //     gl_Position  = gl_in[0].gl_Position;
4997                 //     gl_PointSize = gl_in[0].gl_PointSize;
4998                 //     outBlock.out0 = in0[0];
4999                 //     EmitStreamVertex(1);
5000                 //     EndStreamPrimitive(1);
5001                 // }
5002                 //
5003                 // However, the stream number has been parametrized and the code generated by glslang has been tuned to move the
5004                 // Stream, XfbBuffer and XfbStride decorations to the structure member instead of the block. This allows us to test
5005                 // transform feedback decorations on structure members as part of these basic tests.
5006                 src << "; SPIR-V\n"
5007                     << "; Version: 1.0\n"
5008                     << "; Generator: Khronos Glslang Reference Front End; 10\n"
5009                     << "; Bound: 64\n"
5010                     << "; Schema: 0\n"
5011                     << "               OpCapability Geometry\n"
5012                     << "               OpCapability TransformFeedback\n"
5013                     << "               OpCapability GeometryStreams\n"
5014                     << "          %1 = OpExtInstImport \"GLSL.std.450\"\n"
5015                     << "               OpMemoryModel Logical GLSL450\n"
5016                     << "               OpEntryPoint Geometry %main \"main\" %outBlock %in0 %InputBuiltInArrayVar "
5017                        "%OutputBuiltInsVar\n"
5018                     << "               OpExecutionMode %main Xfb\n"
5019                     << "               OpExecutionMode %main " << primitiveNames.at(m_parameters.primTopology).spirvIn
5020                     << "\n"
5021                     << "               OpExecutionMode %main Invocations 1\n"
5022                     << "               OpExecutionMode %main " << primitiveNames.at(m_parameters.primTopology).spirvOut
5023                     << "\n"
5024                     << "               OpExecutionMode %main OutputVertices "
5025                     << topologyData.at(m_parameters.primTopology).primSize << "\n"
5026                     << "               OpSource GLSL 450\n"
5027                     << "               OpSourceExtension \"GL_ARB_enhanced_layouts\"\n"
5028                     << "               OpName %main \"main\"\n"
5029                     << "               OpName %OutBlock \"OutBlock\"\n"
5030                     << "               OpMemberName %OutBlock 0 \"out0\"\n"
5031                     << "               OpName %outBlock \"outBlock\"\n"
5032                     << "               OpName %in0 \"in0\"\n"
5033                     << "               OpMemberDecorate %OutBlock 0 Location 0\n"
5034                     << "               OpMemberDecorate %OutBlock 0 Offset 0\n"
5035                     // These Stream, XfbBuffer and XfbStride decorations have been moved to the struct member.
5036                     << "               OpMemberDecorate %OutBlock 0 Stream " << s << "\n"
5037                     << "               OpMemberDecorate %OutBlock 0 XfbBuffer 0\n"
5038                     << "               OpMemberDecorate %OutBlock 0 XfbStride 16\n"
5039                     << "               OpDecorate %OutBlock Block\n"
5040                     << "               OpMemberDecorate %BuiltIns 0 BuiltIn Position\n"
5041                     << (pointSizeWanted ? "               OpMemberDecorate %BuiltIns 1 BuiltIn PointSize\n" : "")
5042                     << "               OpDecorate %BuiltIns Block\n"
5043                     // The decorations mentioned above were using OpDecorate and assigned to %outBlock itself here.
5044                     << "               OpDecorate %in0 Location 0\n"
5045                     << "       %void = OpTypeVoid\n"
5046                     << "          %3 = OpTypeFunction %void\n"
5047                     << "      %float = OpTypeFloat 32\n"
5048                     << "    %v4float = OpTypeVector %float 4\n"
5049                     << "   %OutBlock = OpTypeStruct %v4float\n"
5050                     << "%_ptr_Output_OutBlock = OpTypePointer Output %OutBlock\n"
5051                     << "   %outBlock = OpVariable %_ptr_Output_OutBlock Output\n"
5052                     << "        %int = OpTypeInt 32 1\n"
5053                     << "      %int_0 = OpConstant %int 0\n";
5054 
5055                 for (uint32_t i = 1; i < topologyData.at(m_parameters.primTopology).primSize + 1; i++)
5056                 {
5057                     src << "%int_" << i << " = OpConstant %int " << i << "\n";
5058                 }
5059 
5060                 src << "       %uint = OpTypeInt 32 0\n"
5061                     << "     %uint_0 = OpConstant %uint " << topologyData.at(m_parameters.primTopology).primSize << "\n"
5062                     << "%_arr_v4float_uint_0 = OpTypeArray %v4float %uint_0\n"
5063                     << "%_ptr_Input__arr_v4float_uint_0 = OpTypePointer Input %_arr_v4float_uint_0\n"
5064                     << "        %in0 = OpVariable %_ptr_Input__arr_v4float_uint_0 Input\n"
5065                     << "%_ptr_Input_v4float = OpTypePointer Input %v4float\n"
5066                     << "%_ptr_Input_float = OpTypePointer Input %float\n"
5067                     << "%_ptr_Output_v4float = OpTypePointer Output %v4float\n"
5068                     << "%_ptr_Output_float = OpTypePointer Output %float\n"
5069                     << "  %streamNum = OpConstant %int " << s << "\n"
5070                     << "%BuiltIns = OpTypeStruct %v4float" << (pointSizeWanted ? " %float" : "") << "\n"
5071                     << "%InputBuiltInArray = OpTypeArray %BuiltIns %int_1\n"
5072                     << "%InputBuiltInArrayPtr = OpTypePointer Input %InputBuiltInArray\n"
5073                     << "%InputBuiltInArrayVar = OpVariable %InputBuiltInArrayPtr Input\n"
5074                     << "%OutputBuiltInsPtr = OpTypePointer Output %BuiltIns\n"
5075                     << "%OutputBuiltInsVar = OpVariable %OutputBuiltInsPtr Output\n"
5076                     << "       %main = OpFunction %void None %3\n"
5077                     << "          %5 = OpLabel\n"
5078                     << "%in_gl_Position_Ptr = OpAccessChain %_ptr_Input_v4float %InputBuiltInArrayVar %int_0 %int_0\n"
5079                     << "%in_gl_Position = OpLoad %v4float %in_gl_Position_Ptr\n"
5080                     << "%out_gl_Position_Ptr = OpAccessChain %_ptr_Output_v4float %OutputBuiltInsVar %int_0\n"
5081                     << (pointSizeWanted ? "%in_gl_PointSize_Ptr = OpAccessChain %_ptr_Input_float "
5082                                           "%InputBuiltInArrayVar %int_0 %int_1\n" :
5083                                           "")
5084                     << (pointSizeWanted ? "%in_gl_PointSize = OpLoad %float %in_gl_PointSize_Ptr\n" : "")
5085                     << (pointSizeWanted ?
5086                             "%out_gl_PointSize_Ptr = OpAccessChain %_ptr_Output_float %OutputBuiltInsVar %int_1\n" :
5087                             "");
5088 
5089                 for (uint32_t i = 1; i < topologyData.at(m_parameters.primTopology).primSize + 1; i++)
5090                 {
5091                     src << "%" << i << "1 = OpAccessChain %_ptr_Input_v4float %in0 %int_" << i << "\n"
5092                         << "          %" << i << "2 = OpLoad %v4float %" << i << "1\n"
5093                         << "          %" << i << "3 = OpAccessChain %_ptr_Output_v4float %outBlock %int_0\n"
5094                         << "               OpStore %" << i << "3 %" << i << "2\n"
5095                         << "               OpStore %out_gl_Position_Ptr %in_gl_Position\n"
5096                         << (pointSizeWanted ? "               OpStore %out_gl_PointSize_Ptr %in_gl_PointSize\n" : "")
5097                         << "               OpEmitStreamVertex %streamNum\n";
5098                 }
5099 
5100                 src << "               OpEndStreamPrimitive %streamNum\n"
5101                     << "               OpReturn\n"
5102                     << "               OpFunctionEnd\n";
5103 
5104                 programCollection.spirvAsmSources.add("geom") << src.str();
5105             }
5106             else
5107             {
5108                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5109                     << "\n"
5110                     << "layout(" << primitiveNames.at(m_parameters.primTopology).glslIn << ") in;\n"
5111                     << "layout(location = 0) in vec4 in0[];\n"
5112                     << "\n"
5113                     << "layout(" << primitiveNames.at(m_parameters.primTopology).glslOut
5114                     << ", max_vertices = " << topologyData.at(m_parameters.primTopology).primSize << ") out;\n"
5115                     << "layout(stream = " << s
5116                     << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
5117                     << "\n"
5118                     << "in gl_PerVertex\n"
5119                     << "{\n"
5120                     << "    vec4  gl_Position;\n"
5121                     << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "} gl_in[];\n"
5122                     << "out gl_PerVertex\n"
5123                     << "{\n"
5124                     << "    vec4  gl_Position;\n"
5125                     << (pointSizeWanted ? "    float gl_PointSize;\n" : "") << "};\n"
5126                     << "\n"
5127                     << "void main(void)\n"
5128                     << "{\n"
5129                     << "    gl_Position  = gl_in[0].gl_Position;\n"
5130                     << (pointSizeWanted ? "    gl_PointSize = gl_in[0].gl_PointSize;\n" : "");
5131 
5132                 for (uint32_t i = 0; i < topologyData.at(m_parameters.primTopology).primSize; i++)
5133                 {
5134                     src << "    out0 = in0[" << i << "];\n"
5135                         << "    EmitStreamVertex(" << s << ");\n";
5136                 }
5137 
5138                 src << "    EndStreamPrimitive(" << s << ");\n"
5139                     << "}\n";
5140 
5141                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
5142             }
5143         }
5144 
5145         return;
5146     }
5147 
5148     if (m_parameters.testType == TEST_TYPE_MULTIQUERY)
5149     {
5150         // vertex shader
5151         {
5152             std::ostringstream src;
5153             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5154                 << "\n"
5155                 << "layout(location = 0) out ivec4 out0;\n"
5156                 << "\n"
5157                 << "void main(void)\n"
5158                 << "{\n"
5159                 << "    out0 = ivec4(gl_VertexIndex);\n"
5160                 << "}\n";
5161 
5162             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
5163         }
5164 
5165         // geometry shader
5166         {
5167             const uint32_t s = m_parameters.streamId;
5168             std::ostringstream src;
5169 
5170             DE_ASSERT(s != 0);
5171 
5172             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5173                 << "\n"
5174                 << "layout(points) in;\n"
5175                 << "\n"
5176                 << "layout(points, max_vertices = 4) out;\n"
5177                 << "\n"
5178                 << "layout(stream = " << 0
5179                 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
5180                 << "layout(stream = " << s
5181                 << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
5182                 << "\n"
5183                 << (pointSizeWanted ? "out gl_PerVertex { float gl_PointSize; };\n\n" : "") << "void main(void)\n"
5184                 << "{\n"
5185                 << "    const int   n0 = 3;\n"
5186                 << "    const int   n1 = 1;\n"
5187                 << "    const float c0 = 0.5f;\n"
5188                 << "    const float c1 = 0.5f + float(" << s << ");\n"
5189                 << "\n"
5190                 << "    for (int j = 0; j < n0; j++)\n"
5191                 << "    {\n";
5192 
5193             if (!m_parameters.omitShaderWrite)
5194                 src << "        out0 = vec4(c0);\n";
5195 
5196             src << (pointSizeWanted ? "        gl_PointSize = " + pointSizeStr + ".0;\n" : "")
5197                 << "        EmitStreamVertex(0);\n"
5198                 << "        EndStreamPrimitive(0);\n"
5199                 << "    }\n"
5200                 << "\n"
5201                 << "    for (int j = 0; j < n1; j++)\n"
5202                 << "    {\n"
5203                 << "        out1 = vec4(c1);\n"
5204                 << (pointSizeWanted ? "        gl_PointSize = " + pointSizeStr + ".0;\n" : "")
5205                 << "        EmitStreamVertex(" << s << ");\n"
5206                 << "        EndStreamPrimitive(" << s << ");\n"
5207                 << "    }\n"
5208                 << "}\n";
5209 
5210             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
5211         }
5212 
5213         return;
5214     }
5215 
5216     if (m_parameters.testType == TEST_TYPE_LINES_TRIANGLES)
5217     {
5218         // vertex shader
5219         {
5220             std::ostringstream src;
5221             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5222                 << "\n"
5223                 << "void main(void)\n"
5224                 << "{\n"
5225                 << "}\n";
5226 
5227             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
5228         }
5229 
5230         // geometry shader
5231         {
5232             const uint32_t s              = m_parameters.streamId;
5233             const bool line               = isPrimitiveTopologyLine(m_parameters.primTopology);
5234             const bool tri                = isPrimitiveTopologyTriangle(m_parameters.primTopology);
5235             const std::string p           = line ? std::string("line_strip") :
5236                                             tri  ? std::string("triangle_strip") :
5237                                                    std::string("");
5238             const std::string vertexCount = line ? vectorToString(LINES_LIST) :
5239                                             tri  ? vectorToString(TRIANGLES_LIST) :
5240                                                    std::string("");
5241             std::ostringstream src;
5242 
5243             DE_ASSERT(s != 0);
5244 
5245             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5246                 << "\n"
5247                 << "layout(points) in;\n"
5248                 << "\n"
5249                 << "layout(" << p << ", max_vertices = 256) out;\n"
5250                 << "layout(stream = " << 0
5251                 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
5252                 << "layout(stream = " << s
5253                 << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
5254                 << "\n"
5255                 << "const int vertices_in_primitive[] = int[](" << vertexCount << ");\n"
5256                 << "\n"
5257                 << "int num_vertices_in_primitives()\n"
5258                 << "{\n"
5259                 << "    int c = 0;\n"
5260                 << "\n"
5261                 << "    for (int i = 0; i < vertices_in_primitive.length(); i++)\n"
5262                 << "        c = c + vertices_in_primitive[i];\n"
5263                 << "\n"
5264                 << "    return c;\n"
5265                 << "}\n"
5266                 << "\n"
5267                 << (pointSizeWanted ? "out gl_PerVertex { float gl_PointSize; };\n\n" : "") << "void main(void)\n"
5268                 << "{\n"
5269                 << "    int vc = num_vertices_in_primitives();\n"
5270                 << "    int c0 = vc * gl_PrimitiveIDIn;\n"
5271                 << "    int c1 = vc * (" << INVOCATION_COUNT << " + gl_PrimitiveIDIn);\n"
5272                 << "\n"
5273                 << "    for (int i = 0; i < vertices_in_primitive.length(); i++)\n"
5274                 << "    {\n"
5275                 << "        const int n = vertices_in_primitive[i];\n"
5276                 << "\n"
5277                 << "        for (int j = 0; j < n; j++)\n"
5278                 << "        {\n"
5279                 << "            out0 = vec4(ivec4(c0, gl_PrimitiveIDIn, i, j));\n"
5280                 << "            c0 = c0 + 1;\n"
5281                 << (pointSizeWanted ? "            gl_PointSize = " + pointSizeStr + ".0;\n" : "")
5282                 << "            EmitStreamVertex(0);\n"
5283                 << "\n"
5284                 << "            out1 = vec4(ivec4(c1, gl_PrimitiveIDIn, i, j));\n"
5285                 << "            c1 = c1 + 1;\n"
5286                 << (pointSizeWanted ? "            gl_PointSize = " + pointSizeStr + ".0;\n" : "")
5287                 << "            EmitStreamVertex(" << s << ");\n"
5288                 << "        }\n"
5289                 << "\n"
5290                 << "        EndStreamPrimitive(0);\n"
5291                 << "        EndStreamPrimitive(" << s << ");\n"
5292                 << "    }\n"
5293                 << "}\n";
5294 
5295             programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
5296         }
5297 
5298         return;
5299     }
5300 
5301     if (m_parameters.testType == TEST_TYPE_DRAW_OUTSIDE)
5302     {
5303         // Vertex shader
5304         {
5305             std::ostringstream src;
5306             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5307                 << "\n"
5308                 << "layout(push_constant) uniform pushConstants\n"
5309                 << "{\n"
5310                 << "    uint start;\n"
5311                 << "} uInput;\n"
5312                 << "\n"
5313                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
5314                 << "\n"
5315                 << "void main(void)\n"
5316                 << "{\n"
5317                 << "    idx_out = uInput.start + gl_VertexIndex;\n"
5318                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0f;\n" : "") << "}\n";
5319 
5320             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
5321         }
5322 
5323         {
5324             std::ostringstream src;
5325             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
5326                 << "\n"
5327                 << "layout(push_constant) uniform pushConstants\n"
5328                 << "{\n"
5329                 << "    uint start;\n"
5330                 << "} uInput;\n"
5331                 << "\n"
5332                 << "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
5333                 << "\n"
5334                 << "void main(void)\n"
5335                 << "{\n"
5336                 << "    idx_out = uInput.start + gl_VertexIndex * 2u;\n"
5337                 << (pointSizeWanted ? "    gl_PointSize = " + pointSizeStr + ".0f;\n" : "") << "}\n";
5338 
5339             programCollection.glslSources.add("vert2") << glu::VertexSource(src.str());
5340         }
5341 
5342         return;
5343     }
5344 
5345     if (m_parameters.testType == TEST_TYPE_HOLES_VERTEX || m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
5346     {
5347         // The fragment shader is the same in both variants.
5348         {
5349             std::ostringstream frag;
5350             frag << "#version 460\n"
5351                  << "layout (location=0) out vec4 outColor;\n"
5352                  << "\n"
5353                  << "layout (location = 0) in float goku;\n"
5354                  << "layout (location = 0, component = 1) in float trunks;\n"
5355                  << "layout (location = 0, component = 2) in float vegeta;\n"
5356                  << "\n"
5357                  << "void main ()\n"
5358                  << "{\n"
5359                  << "    outColor = ((goku == 10.0 && trunks == 20.0 && vegeta == 30.0)\n"
5360                  << "             ? vec4(0.0, 0.0, 1.0, 1.0)\n"
5361                  << "             : vec4(0.0, 0.0, 0.0, 1.0));\n"
5362                  << "}\n";
5363             programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
5364         }
5365 
5366         const std::string pcDecl = "layout (push_constant, std430) uniform PushConstantBlock {\n"
5367                                    "    vec3 values;\n"
5368                                    "} pc;\n";
5369 
5370         const std::string dbChars =
5371             "layout (location = 0, xfb_buffer = 0, xfb_stride = 12, xfb_offset = 0) flat out float goku;\n"
5372             "layout (location = 0, component = 1) flat out float trunks;\n"
5373             "layout (location = 0, xfb_buffer = 0, xfb_stride = 12, xfb_offset = 8, component = 2) flat out float "
5374             "vegeta;\n";
5375 
5376         const std::string assignments = "    goku   = pc.values.x;\n"
5377                                         "    trunks = pc.values.y;\n"
5378                                         "    vegeta = pc.values.z;\n";
5379 
5380         if (m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
5381         {
5382             std::ostringstream geom;
5383             geom << "#version 460\n"
5384                  << "layout (points) in;\n"
5385                  << "layout (max_vertices=1, points) out;\n"
5386                  << "\n"
5387                  << dbChars << "\n"
5388                  << pcDecl << "\n"
5389                  << "void main ()\n"
5390                  << "{\n"
5391                  << "    gl_Position  = gl_in[0].gl_Position;\n"
5392                  << "    gl_PointSize = gl_in[0].gl_PointSize;\n"
5393                  << "\n"
5394                  << assignments << "\n"
5395                  << "    EmitVertex();\n"
5396                  << "}\n";
5397             programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
5398         }
5399 
5400         const bool vertOnly = (m_parameters.testType == TEST_TYPE_HOLES_VERTEX);
5401         std::ostringstream vert;
5402         vert << "#version 460\n"
5403              << "layout (location = 0) in vec4 inPos;\n"
5404              << "\n"
5405              << (vertOnly ? dbChars : "") << "\n"
5406              << (vertOnly ? pcDecl : "") << "\n"
5407              << "void main ()\n"
5408              << "{\n"
5409              << "    gl_Position  = inPos;\n"
5410              << "    gl_PointSize = 1.0;\n"
5411              << "\n"
5412              << (vertOnly ? assignments : "") << "}\n";
5413         programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
5414 
5415         return;
5416     }
5417 
5418     if (m_parameters.testType == TEST_TYPE_MAX_OUTPUT_COMPONENTS)
5419     {
5420         // For these tests, we reuse the partCount parameter to specify the number of custom outputs to use in the vertex shader.
5421         std::ostringstream vert;
5422         vert << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_460) << "\n"
5423              << "\n"
5424              << "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
5425              << "{\n"
5426              << "    vec4 gl_Position;\n"
5427              << "};\n"
5428              << "layout (location=0) in vec4 inPos;\n";
5429 
5430         const auto partSize = static_cast<uint32_t>(sizeof(tcu::Vec4));
5431         const auto compSize = static_cast<uint32_t>(sizeof(float));
5432 
5433         for (uint32_t partIdx = 0u; partIdx < m_parameters.partCount; ++partIdx)
5434             for (uint32_t compIdx = 0u; compIdx < kVec4Components; ++compIdx)
5435             {
5436                 const auto partOffset =
5437                     (partIdx + 1u) * partSize; // +1 to take into account gl_Position at the buffer start.
5438                 const auto compOffset = partOffset + (kVec4Components - 1u - compIdx) *
5439                                                          compSize; // Reverse component order to prevent vectorization.
5440                 vert << "layout (location=" << partIdx << ", component=" << compIdx
5441                      << ", xfb_buffer=0, xfb_offset=" << compOffset << ") out float part" << partIdx << "_" << compIdx
5442                      << ";\n";
5443             }
5444 
5445         const auto getPartValue = [](uint32_t partIdx, uint32_t component) -> std::string
5446         { return "baseValue + " + std::to_string(partIdx) + " * 10.0 + " + std::to_string(component) + ".0"; };
5447 
5448         vert << "\n"
5449              << "void main (void)\n"
5450              << "{\n"
5451              << "    const float baseValue = (gl_VertexIndex + 1) * 10000.0;\n"
5452              << "    gl_Position = inPos;\n";
5453 
5454         for (uint32_t partIdx = 0u; partIdx < m_parameters.partCount; ++partIdx)
5455             for (uint32_t compIdx = 0u; compIdx < kVec4Components; ++compIdx)
5456                 vert << "    part" << partIdx << "_" << compIdx << " = " << getPartValue(partIdx + 1u, compIdx)
5457                      << ";\n";
5458 
5459         vert << "}\n";
5460 
5461         programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
5462 
5463         return;
5464     }
5465 
5466     DE_ASSERT(0 && "Unknown test");
5467 }
5468 
5469 // Some tests use point lists, others do not. Sometimes we want to test
5470 // using the point size either because we know it caused issues in some
5471 // implementations or because the point size will be stored in the transform
5472 // feedback buffer. Other times it's mandatory to write to the point size.
5473 //
5474 // * TestParameters::primTopology controls the topology type.
5475 // * TestParameters::pointSize controls if we want to write to PointSize or not.
5476 // * TestParameters::usingTessGeom() can be used to check if we use Geometry or
5477 //   Tessellation shaders, and it must match what initPrograms() does.
5478 // * "Feature", in the table below, represents
5479 //   shaderTessellationAndGeometryPointSize.
5480 // * Most variants are OK, but some variants cannot be run.
5481 //   * In some cases, we detect those at checkSupport() time and avoid running
5482 //     them.
5483 //   * In some cases, the variants are simply illegal in theory, and we must
5484 //     avoid generating them.
5485 //   * In some cases, we must switch to using a custom device when running the
5486 //     test.
5487 //
5488 //  Point List        PointSize Wanted    Using Tess/Geom        Feature Available    Outcome
5489 //  -------------------------------------------------------------------------------------------
5490 //  0                0                    0                    0                    OK
5491 //  0                0                    0                    1                    OK
5492 //  0                0                    1                    0                    OK
5493 //  0                0                    1                    1                    OK
5494 //  0                1                    0                    0                    OK, In Vertex Shader
5495 //  0                1                    0                    1                    OK, In Vertex Shader
5496 //  0                1                    1                    0                    Nope, cannot use PointSize (checkSupport)
5497 //  0                1                    1                    1                    OK
5498 //  1                0                    0                    0                    Nope, must write to it In Vertex Shader (avoid generating these variants)
5499 //  1                0                    0                    1                    Nope, must write to it In Vertex Shader (avoid generating these variants)
5500 //  1                0                    1                    0                    OK, implicit 1.0 in Tess/Geom
5501 //  1                0                    1                    1                    OK, but we must disable the feature with a Custom Device (test runtime)
5502 //  1                1                    0                    0                    OK
5503 //  1                1                    0                    1                    OK
5504 //  1                1                    1                    0                    Nope, cannot use PointSize (checkSupport)
5505 //  1                1                    1                    1                    OK
5506 //
addTransformFeedbackTestCaseVariants(tcu::TestCaseGroup * group,const std::string & name,const TestParameters & parameters)5507 void addTransformFeedbackTestCaseVariants(tcu::TestCaseGroup *group, const std::string &name,
5508                                           const TestParameters &parameters)
5509 {
5510     std::vector<uint32_t> pointSizes(1u, parameters.pointSize);
5511 
5512     if (parameters.pointSize == 0u)
5513         pointSizes.push_back(1u);
5514 
5515     int caseCount = 0;
5516     for (const auto &pointSize : pointSizes)
5517     {
5518         const auto testName =
5519             name + ((caseCount > 0) ? "_ptsz" : ""); // Only add suffix if we're adding more than one case.
5520         TestParameters params(parameters);
5521         params.pointSize = pointSize;
5522 
5523         // There are some test variants which are illegal.
5524         if (params.isPoints() && !params.pointSizeWanted() && !params.usingTessGeom())
5525             continue; // We need to emit the point size in the vertex shader.
5526 
5527         group->addChild(new TransformFeedbackTestCase(group->getTestContext(), testName.c_str(), params));
5528         ++caseCount;
5529     }
5530 }
5531 
createTransformFeedbackSimpleTests(tcu::TestCaseGroup * group,vk::PipelineConstructionType constructionType)5532 void createTransformFeedbackSimpleTests(tcu::TestCaseGroup *group, vk::PipelineConstructionType constructionType)
5533 {
5534     {
5535         const uint32_t bufferCounts[]     = {1u, 2u, 4u, 8u};
5536         const uint32_t bufferSizes[]      = {256u, 512u, 128u * 1024u};
5537         const TestType testTypes[]        = {TEST_TYPE_BASIC,
5538                                              TEST_TYPE_RESUME,
5539                                              TEST_TYPE_XFB_POINTSIZE,
5540                                              TEST_TYPE_XFB_CLIPDISTANCE,
5541                                              TEST_TYPE_XFB_CULLDISTANCE,
5542                                              TEST_TYPE_XFB_CLIP_AND_CULL,
5543                                              TEST_TYPE_DRAW_OUTSIDE};
5544         const std::string testTypeNames[] = {
5545             "basic",       "resume", "xfb_pointsize", "xfb_clipdistance", "xfb_culldistance", "xfb_clip_and_cull",
5546             "draw_outside"};
5547 
5548         for (uint32_t testTypesNdx = 0; testTypesNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypesNdx)
5549         {
5550             const TestType testType    = testTypes[testTypesNdx];
5551             const std::string testName = testTypeNames[testTypesNdx];
5552 
5553             for (uint32_t bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(bufferCounts); ++bufferCountsNdx)
5554             {
5555                 const uint32_t partCount = bufferCounts[bufferCountsNdx];
5556 
5557                 for (uint32_t bufferSizesNdx = 0; bufferSizesNdx < DE_LENGTH_OF_ARRAY(bufferSizes); ++bufferSizesNdx)
5558                 {
5559                     const uint32_t bufferSize = bufferSizes[bufferSizesNdx];
5560                     TestParameters parameters = {constructionType,
5561                                                  testType,
5562                                                  bufferSize,
5563                                                  partCount,
5564                                                  0u,
5565                                                  0u,
5566                                                  0u,
5567                                                  STREAM_ID_0_NORMAL,
5568                                                  false,
5569                                                  false,
5570                                                  true,
5571                                                  false,
5572                                                  false,
5573                                                  VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
5574                                                  false};
5575 
5576                     // Simple Transform Feedback test
5577                     addTransformFeedbackTestCaseVariants(
5578                         group, (testName + "_" + de::toString(partCount) + "_" + de::toString(bufferSize)), parameters);
5579 
5580                     parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
5581                     addTransformFeedbackTestCaseVariants(group,
5582                                                          (testName + "_beginqueryindexed_streamid_0_" +
5583                                                           de::toString(partCount) + "_" + de::toString(bufferSize)),
5584                                                          parameters);
5585 
5586                     parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
5587                     addTransformFeedbackTestCaseVariants(group,
5588                                                          (testName + "_endqueryindexed_streamid_0_" +
5589                                                           de::toString(partCount) + "_" + de::toString(bufferSize)),
5590                                                          parameters);
5591                 }
5592             }
5593         }
5594     }
5595 
5596     {
5597         const uint32_t bufferCounts[] = {6u, 8u, 10u, 12u};
5598         const TestType testType       = TEST_TYPE_WINDING;
5599         const std::string testName    = "winding";
5600 
5601         for (const auto &topology : topologyData)
5602         {
5603             // Note: no need to test POINT_LIST as is tested in many tests.
5604             if (topology.first == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
5605                 continue;
5606 
5607             for (uint32_t bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(bufferCounts); ++bufferCountsNdx)
5608             {
5609                 const uint32_t vertexCount = bufferCounts[bufferCountsNdx];
5610 
5611                 TestParameters parameters = {constructionType,
5612                                              testType,
5613                                              0u,
5614                                              vertexCount,
5615                                              0u,
5616                                              0u,
5617                                              0u,
5618                                              STREAM_ID_0_NORMAL,
5619                                              false,
5620                                              false,
5621                                              false,
5622                                              false,
5623                                              false,
5624                                              topology.first,
5625                                              false};
5626 
5627                 // Topology winding test
5628                 addTransformFeedbackTestCaseVariants(
5629                     group, (testName + "_" + topology.second.topologyName + de::toString(vertexCount)), parameters);
5630             }
5631         }
5632     }
5633 
5634     {
5635         for (int i = 0; i < 2; ++i)
5636         {
5637             const bool multiview           = (i > 0);
5638             const uint32_t vertexStrides[] = {4u, 61u, 127u, 251u, 509u};
5639             const TestType testType        = (multiview ? TEST_TYPE_DRAW_INDIRECT_MULTIVIEW : TEST_TYPE_DRAW_INDIRECT);
5640             const std::string testName     = std::string("draw_indirect") + (multiview ? "_multiview" : "");
5641 
5642             for (uint32_t vertexStridesNdx = 0; vertexStridesNdx < DE_LENGTH_OF_ARRAY(vertexStrides);
5643                  ++vertexStridesNdx)
5644             {
5645                 const uint32_t vertexStrideBytes =
5646                     static_cast<uint32_t>(sizeof(uint32_t) * vertexStrides[vertexStridesNdx]);
5647                 TestParameters parameters = {constructionType,
5648                                              testType,
5649                                              0u,
5650                                              0u,
5651                                              0u,
5652                                              0u,
5653                                              vertexStrideBytes,
5654                                              STREAM_ID_0_NORMAL,
5655                                              false,
5656                                              false,
5657                                              false,
5658                                              false,
5659                                              false,
5660                                              VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
5661                                              false};
5662 
5663                 // Rendering tests with various strides
5664                 addTransformFeedbackTestCaseVariants(group, (testName + "_" + de::toString(vertexStrideBytes)),
5665                                                      parameters);
5666 
5667                 parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
5668                 addTransformFeedbackTestCaseVariants(
5669                     group, (testName + "_beginqueryindexed_streamid_0_" + de::toString(vertexStrideBytes)), parameters);
5670 
5671                 parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
5672                 addTransformFeedbackTestCaseVariants(
5673                     group, (testName + "_endqueryindexed_streamid_0_" + de::toString(vertexStrideBytes)), parameters);
5674             }
5675         }
5676     }
5677 
5678     {
5679         const struct
5680         {
5681             TestType testType;
5682             const char *testName;
5683         } testCases[] = {
5684             {TEST_TYPE_BACKWARD_DEPENDENCY, "backward_dependency"},
5685             {TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT, "backward_dependency_indirect"},
5686         };
5687 
5688         for (const auto &testCase : testCases)
5689         {
5690             const auto &testType       = testCase.testType;
5691             const std::string testName = testCase.testName;
5692             TestParameters parameters  = {constructionType,
5693                                           testType,
5694                                           512u,
5695                                           2u,
5696                                           0u,
5697                                           0u,
5698                                           0u,
5699                                           STREAM_ID_0_NORMAL,
5700                                           false,
5701                                           false,
5702                                           false,
5703                                           false,
5704                                           false,
5705                                           VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
5706                                           false};
5707 
5708             // Rendering test checks backward pipeline dependency
5709             addTransformFeedbackTestCaseVariants(group, testName, parameters);
5710 
5711             parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
5712             addTransformFeedbackTestCaseVariants(group, (testName + "_beginqueryindexed_streamid_0"), parameters);
5713 
5714             parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
5715             addTransformFeedbackTestCaseVariants(group, (testName + "_endqueryindexed_streamid_0"), parameters);
5716 
5717             // Rendering test checks backward pipeline dependency (using NULL for offset array)
5718             parameters.noOffsetArray = true;
5719             addTransformFeedbackTestCaseVariants(group, (testName + "_no_offset_array"), parameters);
5720         }
5721     }
5722 
5723     {
5724         const uint32_t usedStreamId[] = {0u, 1u, 3u, 6u, 14u};
5725         const uint32_t vertexCounts[] = {
5726             6u, 61u, 127u, 251u,
5727             509u}; // Lowest value has to be at least 6. Otherwise the triangles with adjacency can't be generated.
5728         const TestType testType                  = TEST_TYPE_QUERY_GET;
5729         const std::string testName               = "query";
5730         const TestType testTypeCopy[]            = {TEST_TYPE_QUERY_COPY, TEST_TYPE_QUERY_COPY_STRIDE_ZERO};
5731         const std::string testNameCopy[]         = {"query_copy", "query_copy_stride_zero"};
5732         const TestType testTypeHostQueryReset    = TEST_TYPE_QUERY_RESET;
5733         const std::string testNameHostQueryReset = "host_query_reset";
5734 
5735         for (const auto &topology : topologyData)
5736         {
5737             // Currently, we don't test tessellation here.
5738             if (topology.first == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
5739                 continue;
5740 
5741             for (const auto &streamCounts : usedStreamId)
5742             {
5743                 const uint32_t streamId = streamCounts;
5744 
5745                 for (const auto &numVertices : vertexCounts)
5746                 {
5747                     for (uint32_t i = 0; i < 2; ++i)
5748                     {
5749                         const bool query64Bits     = (i == 1);
5750                         const std::string widthStr = (query64Bits ? "_64bits" : "_32bits");
5751 
5752                         uint32_t vertCount = numVertices;
5753 
5754                         // The number of vertices in original test was 4.
5755                         if (topology.first == VK_PRIMITIVE_TOPOLOGY_POINT_LIST && vertCount == 6)
5756                             vertCount -= 2;
5757 
5758                         // Round the number of vertices to match the used primitive topology - if necessary.
5759                         const uint32_t primitiveCount = (uint32_t)topology.second.getNumPrimitives(vertCount);
5760                         const uint32_t vertexCount    = (uint32_t)topology.second.getNumVertices(primitiveCount);
5761 
5762                         DE_ASSERT(vertexCount > 0);
5763 
5764                         const uint32_t bytesPerVertex  = static_cast<uint32_t>(4 * sizeof(float));
5765                         const uint32_t bufferSize      = bytesPerVertex * vertexCount;
5766                         TestParameters parameters      = {constructionType,
5767                                                           testType,
5768                                                           bufferSize,
5769                                                           0u,
5770                                                           streamId,
5771                                                           0u,
5772                                                           0u,
5773                                                           STREAM_ID_0_NORMAL,
5774                                                           query64Bits,
5775                                                           false,
5776                                                           true,
5777                                                           false,
5778                                                           false,
5779                                                           topology.first,
5780                                                           false};
5781                         const std::string fullTestName = testName + "_" + topology.second.topologyName +
5782                                                          de::toString(streamId) + "_" + de::toString(vertexCount) +
5783                                                          widthStr;
5784                         // Written primitives query test
5785                         addTransformFeedbackTestCaseVariants(group, fullTestName, parameters);
5786 
5787                         TestParameters omitParameters  = {constructionType,
5788                                                           testType,
5789                                                           bufferSize,
5790                                                           0u,
5791                                                           streamId,
5792                                                           0u,
5793                                                           0u,
5794                                                           STREAM_ID_0_NORMAL,
5795                                                           query64Bits,
5796                                                           false,
5797                                                           true,
5798                                                           true,
5799                                                           false,
5800                                                           topology.first,
5801                                                           false};
5802                         const std::string omitTestName = testName + "_omit_write_" + topology.second.topologyName +
5803                                                          de::toString(streamId) + "_" + de::toString(vertexCount) +
5804                                                          widthStr;
5805                         addTransformFeedbackTestCaseVariants(group, omitTestName, omitParameters);
5806 
5807                         for (uint32_t testTypeCopyNdx = 0; testTypeCopyNdx < DE_LENGTH_OF_ARRAY(testTypeCopy);
5808                              testTypeCopyNdx++)
5809                         {
5810                             TestParameters parametersCopy      = {constructionType,
5811                                                                   testTypeCopy[testTypeCopyNdx],
5812                                                                   bufferSize,
5813                                                                   0u,
5814                                                                   streamId,
5815                                                                   0u,
5816                                                                   0u,
5817                                                                   STREAM_ID_0_NORMAL,
5818                                                                   query64Bits,
5819                                                                   false,
5820                                                                   true,
5821                                                                   false,
5822                                                                   false,
5823                                                                   topology.first,
5824                                                                   false};
5825                             const std::string fullTestNameCopy = testNameCopy[testTypeCopyNdx] + "_" +
5826                                                                  topology.second.topologyName + de::toString(streamId) +
5827                                                                  "_" + de::toString(vertexCount) + widthStr;
5828                             addTransformFeedbackTestCaseVariants(group, fullTestNameCopy, parametersCopy);
5829 
5830                             parametersCopy.queryResultWithAvailability = true;
5831                             const std::string fullTestNameQueryWithAvailability =
5832                                 testNameCopy[testTypeCopyNdx] + "_" + topology.second.topologyName +
5833                                 de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr +
5834                                 "_query_with_availability";
5835                             addTransformFeedbackTestCaseVariants(group, fullTestNameQueryWithAvailability,
5836                                                                  parametersCopy);
5837                         }
5838 
5839                         const TestParameters parametersHostQueryReset = {constructionType,
5840                                                                          testTypeHostQueryReset,
5841                                                                          bufferSize,
5842                                                                          0u,
5843                                                                          streamId,
5844                                                                          0u,
5845                                                                          0u,
5846                                                                          STREAM_ID_0_NORMAL,
5847                                                                          query64Bits,
5848                                                                          false,
5849                                                                          true,
5850                                                                          false,
5851                                                                          false,
5852                                                                          topology.first,
5853                                                                          false};
5854                         const std::string fullTestNameHostQueryReset =
5855                             testNameHostQueryReset + "_" + topology.second.topologyName + de::toString(streamId) + "_" +
5856                             de::toString(vertexCount) + widthStr;
5857                         addTransformFeedbackTestCaseVariants(group, fullTestNameHostQueryReset,
5858                                                              parametersHostQueryReset);
5859 
5860                         if (streamId == 0)
5861                         {
5862                             std::string testNameStream0 = fullTestName;
5863                             testNameStream0 += "_beginqueryindexed_streamid_0";
5864                             parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
5865                             addTransformFeedbackTestCaseVariants(group, testNameStream0, parameters);
5866 
5867                             testNameStream0 = fullTestName;
5868                             testNameStream0 += "_endqueryindexed_streamid_0";
5869                             parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
5870                             addTransformFeedbackTestCaseVariants(group, testNameStream0, parameters);
5871                         }
5872                     }
5873                 }
5874             }
5875         }
5876     }
5877 
5878     // Depth clip control tests.
5879     {
5880         TestParameters parameters = {constructionType,
5881                                      TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX,
5882                                      96,
5883                                      1u,
5884                                      0u,
5885                                      0u,
5886                                      0u,
5887                                      STREAM_ID_0_NORMAL,
5888                                      false,
5889                                      false,
5890                                      true,
5891                                      false,
5892                                      false,
5893                                      VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
5894                                      false};
5895 
5896         addTransformFeedbackTestCaseVariants(group, "depth_clip_control_vertex", parameters);
5897     }
5898     {
5899         TestParameters parameters = {constructionType,
5900                                      TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY,
5901                                      96,
5902                                      1u,
5903                                      0u,
5904                                      0u,
5905                                      0u,
5906                                      STREAM_ID_0_NORMAL,
5907                                      false,
5908                                      false,
5909                                      true,
5910                                      false,
5911                                      false,
5912                                      VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
5913                                      false};
5914 
5915         addTransformFeedbackTestCaseVariants(group, "depth_clip_control_geometry", parameters);
5916     }
5917     {
5918         TestParameters parameters = {constructionType,
5919                                      TEST_TYPE_DEPTH_CLIP_CONTROL_TESE,
5920                                      96,
5921                                      1u,
5922                                      0u,
5923                                      0u,
5924                                      0u,
5925                                      STREAM_ID_0_NORMAL,
5926                                      false,
5927                                      false,
5928                                      true,
5929                                      false,
5930                                      false,
5931                                      VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
5932                                      false};
5933 
5934         addTransformFeedbackTestCaseVariants(group, "depth_clip_control_tese", parameters);
5935     }
5936 
5937     {
5938         const uint32_t usedStreamId[] = {1u, 3u, 6u, 14u};
5939         const TestType testType       = TEST_TYPE_LINES_TRIANGLES;
5940         const std::string testName    = "lines_or_triangles";
5941 
5942         for (const auto &topology : topologyData)
5943         {
5944             const uint32_t outputVertexCount =
5945                 (topology.first == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)     ? 2 * destripedLineCount(LINES_LIST) :
5946                 (topology.first == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) ? 3 * destripedTriangleCount(TRIANGLES_LIST) :
5947                                                                            0;
5948 
5949             if (outputVertexCount == 0)
5950                 continue;
5951 
5952             for (const auto &streamId : usedStreamId)
5953             {
5954                 const uint32_t partCount       = 2u;
5955                 const uint32_t bytesPerVertex  = static_cast<uint32_t>(sizeof(tcu::Vec4));
5956                 const uint32_t bufferSize      = partCount * INVOCATION_COUNT * outputVertexCount * bytesPerVertex;
5957                 const std::string fullTestName = testName + "_" + topology.second.topologyName + de::toString(streamId);
5958                 const TestParameters parameters = {
5959                     constructionType,
5960                     testType,           //  TestType testType;
5961                     bufferSize,         //  uint32_t bufferSize;
5962                     partCount,          //  uint32_t partCount;
5963                     streamId,           //  uint32_t streamId;
5964                     0u,                 //  uint32_t pointSize;
5965                     0u,                 //  uint32_t vertexStride;
5966                     STREAM_ID_0_NORMAL, //  StreamId0Mode streamId0Mode;
5967                     false,              //  bool query64bits;
5968                     false,              //  bool noOffsetArray;
5969                     true,               //  bool requireRastStreamSelect;
5970                     false,              //  bool omitShaderWrite;
5971                     false,              //  bool useMaintenance5;
5972                     topology.first,     //  VkPrimitiveTopology primTopology;
5973                     false               //  bool queryResultWithAvailability;
5974                 };
5975 
5976                 addTransformFeedbackTestCaseVariants(group, fullTestName, parameters);
5977             }
5978         }
5979     }
5980 
5981 #ifndef CTS_USES_VULKANSC
5982     {
5983         const TestParameters parameters{
5984             constructionType,
5985             TEST_TYPE_RESUME,                     //  TestType testType;
5986             96u,                                  //  uint32_t bufferSize;
5987             2u,                                   //  uint32_t partCount;
5988             1u,                                   //  uint32_t streamId;
5989             0u,                                   //  uint32_t pointSize;
5990             0u,                                   //  uint32_t vertexStride;
5991             STREAM_ID_0_NORMAL,                   //  StreamId0Mode streamId0Mode;
5992             false,                                //  bool query64bits;
5993             false,                                //  bool noOffsetArray;
5994             true,                                 //  bool requireRastStreamSelect;
5995             false,                                //  bool omitShaderWrite;
5996             true,                                 //  bool useMaintenance5;
5997             VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, //  VkPrimitiveTopology primTopology;
5998             false                                 //  bool                queryResultWithAvailability
5999         };
6000         group->addChild(new TransformFeedbackTestCase(group->getTestContext(), "maintenance5", parameters));
6001     }
6002 #endif // CTS_USES_VULKANSC
6003 }
6004 
createTransformFeedbackStreamsSimpleTests(tcu::TestCaseGroup * group,vk::PipelineConstructionType constructionType)6005 void createTransformFeedbackStreamsSimpleTests(tcu::TestCaseGroup *group, vk::PipelineConstructionType constructionType)
6006 {
6007     const uint32_t usedStreamId[]     = {1u, 3u, 6u, 14u};
6008     const TestType testTypes[]        = {TEST_TYPE_STREAMS, TEST_TYPE_STREAMS_POINTSIZE, TEST_TYPE_STREAMS_CLIPDISTANCE,
6009                                          TEST_TYPE_STREAMS_CULLDISTANCE};
6010     const std::string testTypeNames[] = {"streams", "streams_pointsize", "streams_clipdistance",
6011                                          "streams_culldistance"};
6012 
6013     for (uint32_t testTypesNdx = 0; testTypesNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypesNdx)
6014     {
6015         const TestType testType    = testTypes[testTypesNdx];
6016         const std::string testName = testTypeNames[testTypesNdx];
6017         const uint32_t pointSize   = (testType == TEST_TYPE_STREAMS_POINTSIZE) ? 2u : 0u;
6018 
6019         for (uint32_t streamCountsNdx = 0; streamCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++streamCountsNdx)
6020         {
6021             const uint32_t streamId   = usedStreamId[streamCountsNdx];
6022             TestParameters parameters = {constructionType,
6023                                          testType,
6024                                          0u,
6025                                          0u,
6026                                          streamId,
6027                                          pointSize,
6028                                          0u,
6029                                          STREAM_ID_0_NORMAL,
6030                                          false,
6031                                          false,
6032                                          true,
6033                                          false,
6034                                          false,
6035                                          VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6036                                          false};
6037 
6038             // Streams usage test
6039             addTransformFeedbackTestCaseVariants(group, (testName + "_" + de::toString(streamId)), parameters);
6040         }
6041     }
6042 
6043     {
6044         const TestType testType    = TEST_TYPE_MULTISTREAMS;
6045         const std::string testName = "multistreams";
6046 
6047         for (uint32_t bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++bufferCountsNdx)
6048         {
6049             const uint32_t streamId          = usedStreamId[bufferCountsNdx];
6050             const uint32_t streamsUsed       = 2u;
6051             const uint32_t maxBytesPerVertex = 256u;
6052             const TestParameters parameters  = {constructionType,
6053                                                 testType,
6054                                                 maxBytesPerVertex * streamsUsed,
6055                                                 streamsUsed,
6056                                                 streamId,
6057                                                 0u,
6058                                                 0u,
6059                                                 STREAM_ID_0_NORMAL,
6060                                                 false,
6061                                                 false,
6062                                                 false,
6063                                                 false,
6064                                                 false,
6065                                                 VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6066                                                 false};
6067 
6068             // Simultaneous multiple streams usage test
6069             addTransformFeedbackTestCaseVariants(group, (testName + "_" + de::toString(streamId)), parameters);
6070         }
6071     }
6072 
6073     {
6074         const TestType testType    = TEST_TYPE_MULTISTREAMS_SAME_LOCATION;
6075         const std::string testName = "multistreams_same_location";
6076         for (const auto streamId : usedStreamId)
6077         {
6078             const uint32_t streamsUsed      = 2u;
6079             const TestParameters parameters = {constructionType,
6080                                                testType,
6081                                                32 * 4,
6082                                                streamsUsed,
6083                                                streamId,
6084                                                0u,
6085                                                0u,
6086                                                STREAM_ID_0_NORMAL,
6087                                                false,
6088                                                false,
6089                                                false,
6090                                                false,
6091                                                false,
6092                                                VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6093                                                false};
6094 
6095             // Simultaneous multiple streams to the same location usage test
6096             addTransformFeedbackTestCaseVariants(group, (testName + "_" + de::toString(streamId)), parameters);
6097         }
6098     }
6099 
6100     {
6101         const TestType testType    = TEST_TYPE_MULTIQUERY;
6102         const std::string testName = "multiquery";
6103 
6104         for (uint32_t bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++bufferCountsNdx)
6105         {
6106             const uint32_t streamId                  = usedStreamId[bufferCountsNdx];
6107             const uint32_t streamsUsed               = 2u;
6108             const uint32_t maxBytesPerVertex         = 256u;
6109             const TestParameters parameters          = {constructionType,
6110                                                         testType,
6111                                                         maxBytesPerVertex * streamsUsed,
6112                                                         streamsUsed,
6113                                                         streamId,
6114                                                         0u,
6115                                                         0u,
6116                                                         STREAM_ID_0_NORMAL,
6117                                                         false,
6118                                                         false,
6119                                                         false,
6120                                                         false,
6121                                                         false,
6122                                                         VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6123                                                         false};
6124             const TestParameters writeOmitParameters = {constructionType,
6125                                                         testType,
6126                                                         maxBytesPerVertex * streamsUsed,
6127                                                         streamsUsed,
6128                                                         streamId,
6129                                                         0u,
6130                                                         0u,
6131                                                         STREAM_ID_0_NORMAL,
6132                                                         false,
6133                                                         false,
6134                                                         false,
6135                                                         true,
6136                                                         false,
6137                                                         VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6138                                                         false};
6139 
6140             // Simultaneous multiple queries usage test
6141             addTransformFeedbackTestCaseVariants(group, (testName + "_" + de::toString(streamId)), parameters);
6142             addTransformFeedbackTestCaseVariants(group, (testName + "_omit_write_" + de::toString(streamId)),
6143                                                  writeOmitParameters);
6144         }
6145     }
6146 
6147     {
6148         struct
6149         {
6150             TestType testType;
6151             const char *suffix;
6152         } holeCases[] = {
6153             {TEST_TYPE_HOLES_VERTEX, "_vert"},
6154             {TEST_TYPE_HOLES_GEOMETRY, "_geom"},
6155         };
6156         const std::string testNameBase = "holes";
6157 
6158         for (const auto &holeCase : holeCases)
6159             for (const auto &extraDraw : {false, true})
6160             {
6161                 const auto partCount = (extraDraw ? 2u : 1u);
6162                 const auto testName  = testNameBase + (extraDraw ? "_extra_draw" : "");
6163                 const TestParameters parameters{constructionType,
6164                                                 holeCase.testType,
6165                                                 0u,
6166                                                 partCount,
6167                                                 0u,
6168                                                 1u,
6169                                                 0u,
6170                                                 STREAM_ID_0_NORMAL,
6171                                                 false,
6172                                                 false,
6173                                                 false,
6174                                                 false,
6175                                                 false,
6176                                                 VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
6177                                                 false};
6178                 ;
6179 
6180                 // Test skipping components in the XFB buffer
6181                 group->addChild(new TransformFeedbackTestCase(group->getTestContext(),
6182                                                               (testName + holeCase.suffix).c_str(), parameters));
6183             }
6184     }
6185 
6186     {
6187         const TestType testType    = TEST_TYPE_MAX_OUTPUT_COMPONENTS;
6188         const std::string testName = "max_output_components";
6189 
6190         // For these tests, we reuse the partCount parameter to specify the number of custom outputs to use in the vertex shader.
6191         for (const auto &compCount : {64u, 128u})
6192         {
6193             const auto partCount = compCount / kVec4Components - 1u /*gl_Position*/;
6194             const TestParameters parameters{constructionType,
6195                                             testType,
6196                                             0u,
6197                                             partCount,
6198                                             0u,
6199                                             0u,
6200                                             0u,
6201                                             STREAM_ID_0_NORMAL,
6202                                             false,
6203                                             false,
6204                                             false,
6205                                             false,
6206                                             false,
6207                                             VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
6208                                             false};
6209 
6210             // Save a large number of components to the transform feedback buffer
6211             group->addChild(new TransformFeedbackTestCase(
6212                 group->getTestContext(), (testName + "_" + std::to_string(compCount)).c_str(), parameters));
6213         }
6214     }
6215 }
6216 
createTransformFeedbackAndStreamsSimpleTests(tcu::TestCaseGroup * group,vk::PipelineConstructionType constructionType)6217 void createTransformFeedbackAndStreamsSimpleTests(tcu::TestCaseGroup *group,
6218                                                   vk::PipelineConstructionType constructionType)
6219 {
6220     createTransformFeedbackSimpleTests(group, constructionType);
6221     createTransformFeedbackStreamsSimpleTests(group, constructionType);
6222 }
6223 
6224 class TestGroupWithClean : public tcu::TestCaseGroup
6225 {
6226 public:
TestGroupWithClean(tcu::TestContext & testCtx,const std::string & name)6227     TestGroupWithClean(tcu::TestContext &testCtx, const std::string &name) : tcu::TestCaseGroup(testCtx, name.c_str())
6228     {
6229     }
6230 
~TestGroupWithClean(void)6231     virtual ~TestGroupWithClean(void)
6232     {
6233         cleanupDevices();
6234     }
6235 };
6236 
6237 } // namespace
6238 
createTransformFeedbackSimpleTests(tcu::TestContext & testCtx,vk::PipelineConstructionType constructionType)6239 tcu::TestCaseGroup *createTransformFeedbackSimpleTests(tcu::TestContext &testCtx,
6240                                                        vk::PipelineConstructionType constructionType)
6241 {
6242     static const std::map<vk::PipelineConstructionType, std::string> groupNameSuffix{
6243         std::make_pair(PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC, ""),
6244         std::make_pair(PIPELINE_CONSTRUCTION_TYPE_FAST_LINKED_LIBRARY, "_fast_gpl"),
6245         std::make_pair(PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY, "_optimized_gpl"),
6246     };
6247 
6248     de::MovePtr<tcu::TestCaseGroup> mainGroup(
6249         new TestGroupWithClean(testCtx, "simple" + groupNameSuffix.at(constructionType)));
6250     createTransformFeedbackAndStreamsSimpleTests(mainGroup.get(), constructionType);
6251     return mainGroup.release();
6252 }
6253 
6254 } // namespace TransformFeedback
6255 } // namespace vkt
6256