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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
957
958 protected:
959 tcu::TestStatus iterate(void);
960 };
961
TransformFeedbackBasicTestInstance(Context & context,const TestParameters & parameters)962 TransformFeedbackBasicTestInstance::TransformFeedbackBasicTestInstance(Context &context,
963 const TestParameters ¶meters)
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 ¶meters);
1048
1049 protected:
1050 tcu::TestStatus iterate(void);
1051 };
1052
TransformFeedbackResumeTestInstance(Context & context,const TestParameters & parameters)1053 TransformFeedbackResumeTestInstance::TransformFeedbackResumeTestInstance(Context &context,
1054 const TestParameters ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ®ion);
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 ¶meters, 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 ¶meters,
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 ®ion);
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 ¶meters);
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 ¶meters)
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 ¶meters);
2799
2800 protected:
2801 tcu::TestStatus iterate(void);
2802 };
2803
TransformFeedbackQueryTestInstance(Context & context,const TestParameters & parameters)2804 TransformFeedbackQueryTestInstance::TransformFeedbackQueryTestInstance(Context &context,
2805 const TestParameters ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
3585
3586 protected:
3587 tcu::TestStatus iterate(void);
3588 };
3589
TransformFeedbackDrawOutsideTestInstance(Context & context,const TestParameters & parameters)3590 TransformFeedbackDrawOutsideTestInstance::TransformFeedbackDrawOutsideTestInstance(Context &context,
3591 const TestParameters ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters);
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 ¶meters)
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 ¶meters)
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