1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Google LLC
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*
22  * \file
23  * \brief Extended dynamic state tests
24 *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineBindVertexBuffers2Tests.hpp"
27 #include "deUniquePtr.hpp"
28 #include "tcuTestCase.hpp"
29 #include "vktTestCase.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vktPipelineClearUtil.hpp"
38 #include "vkBufferWithMemory.hpp"
39 #include "vkSafetyCriticalUtil.hpp"
40 #include "vktCustomInstancesDevices.hpp"
41 #include "vkDeviceUtil.hpp"
42 #include "tcuCommandLine.hpp"
43 #include "deRandom.hpp"
44 
45 namespace vkt
46 {
47 namespace pipeline
48 {
49 
50 struct TestParams
51 {
52     uint32_t colorStride;
53     uint32_t vertexStride;
54     uint32_t colorOffset;
55     uint32_t vertexOffset;
56 };
57 
makeImageCreateInfo(const vk::VkExtent2D extent,const vk::VkFormat format,const vk::VkImageUsageFlags usage)58 vk::VkImageCreateInfo makeImageCreateInfo(const vk::VkExtent2D extent, const vk::VkFormat format,
59                                           const vk::VkImageUsageFlags usage)
60 {
61     const vk::VkImageCreateInfo imageParams = {
62         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,          // VkStructureType sType;
63         DE_NULL,                                          // const void* pNext;
64         (vk::VkImageCreateFlags)0u,                       // VkImageCreateFlags flags;
65         vk::VK_IMAGE_TYPE_2D,                             // VkImageType imageType;
66         format,                                           // VkFormat format;
67         vk::makeExtent3D(extent.width, extent.height, 1), // VkExtent3D extent;
68         1u,                                               // uint32_t mipLevels;
69         1u,                                               // uint32_t arrayLayers;
70         vk::VK_SAMPLE_COUNT_1_BIT,                        // VkSampleCountFlagBits samples;
71         vk::VK_IMAGE_TILING_OPTIMAL,                      // VkImageTiling tiling;
72         usage,                                            // VkImageUsageFlags usage;
73         vk::VK_SHARING_MODE_EXCLUSIVE,                    // VkSharingMode sharingMode;
74         0u,                                               // uint32_t queueFamilyIndexCount;
75         DE_NULL,                                          // const uint32_t* pQueueFamilyIndices;
76         vk::VK_IMAGE_LAYOUT_UNDEFINED,                    // VkImageLayout initialLayout;
77     };
78     return imageParams;
79 }
80 
81 //make a buffer to read an image back after rendering
makeBufferForImage(const vk::DeviceInterface & vkd,const vk::VkDevice device,vk::Allocator & allocator,tcu::TextureFormat tcuFormat,vk::VkExtent2D imageExtent)82 std::unique_ptr<vk::BufferWithMemory> makeBufferForImage(const vk::DeviceInterface &vkd, const vk::VkDevice device,
83                                                          vk::Allocator &allocator, tcu::TextureFormat tcuFormat,
84                                                          vk::VkExtent2D imageExtent)
85 {
86     const auto outBufferSize  = static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) *
87                                                              imageExtent.width * imageExtent.height);
88     const auto outBufferUsage = vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT;
89     const auto outBufferInfo  = makeBufferCreateInfo(outBufferSize, outBufferUsage);
90     auto outBuffer            = std::unique_ptr<vk::BufferWithMemory>(
91         new vk::BufferWithMemory(vkd, device, allocator, outBufferInfo, vk::MemoryRequirement::HostVisible));
92 
93     return outBuffer;
94 }
95 
makeBindingDescription(uint32_t binding,uint32_t stride,vk::VkVertexInputRate inputRate)96 vk::VkVertexInputBindingDescription makeBindingDescription(uint32_t binding, uint32_t stride,
97                                                            vk::VkVertexInputRate inputRate)
98 {
99     vk::VkVertexInputBindingDescription bindingDescription;
100 
101     bindingDescription.binding   = binding;
102     bindingDescription.stride    = stride;
103     bindingDescription.inputRate = inputRate;
104 
105     return bindingDescription;
106 }
107 
makeAttributeDescription(uint32_t location,uint32_t binding,vk::VkFormat format,uint32_t offset)108 vk::VkVertexInputAttributeDescription makeAttributeDescription(uint32_t location, uint32_t binding, vk::VkFormat format,
109                                                                uint32_t offset)
110 {
111     vk::VkVertexInputAttributeDescription attributeDescription;
112 
113     attributeDescription.location = location;
114     attributeDescription.binding  = binding;
115     attributeDescription.format   = format;
116     attributeDescription.offset   = offset;
117 
118     return attributeDescription;
119 }
120 
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)121 void copyAndFlush(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::BufferWithMemory &buffer, size_t offset,
122                   const void *src, size_t size)
123 {
124     auto &alloc = buffer.getAllocation();
125     auto dst    = reinterpret_cast<char *>(alloc.getHostPtr());
126 
127     deMemcpy(dst + offset, src, size);
128     vk::flushAlloc(vkd, device, alloc);
129 }
130 
131 #ifndef CTS_USES_VULKANSC
132 typedef de::MovePtr<vk::DeviceDriver> DeviceDriverPtr;
133 #else
134 typedef de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> DeviceDriverPtr;
135 #endif // CTS_USES_VULKANSC
136 
137 typedef vk::Move<vk::VkDevice> DevicePtr;
138 
createRobustBufferAccessDevice(Context & context,const vk::VkPhysicalDeviceFeatures2 * enabledFeatures2)139 vk::Move<vk::VkDevice> createRobustBufferAccessDevice(Context &context,
140                                                       const vk::VkPhysicalDeviceFeatures2 *enabledFeatures2)
141 {
142     const float queuePriority = 1.0f;
143 
144     // Create a universal queue that supports graphics and compute
145     const vk::VkDeviceQueueCreateInfo queueParams = {
146         vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
147         DE_NULL,                                        // const void* pNext;
148         0u,                                             // VkDeviceQueueCreateFlags flags;
149         context.getUniversalQueueFamilyIndex(),         // uint32_t queueFamilyIndex;
150         1u,                                             // uint32_t queueCount;
151         &queuePriority                                  // const float* pQueuePriorities;
152     };
153 
154     vk::VkPhysicalDeviceFeatures enabledFeatures1 = context.getDeviceFeatures();
155     enabledFeatures1.robustBufferAccess           = true;
156 
157     // \note Extensions in core are not explicitly enabled even though
158     //         they are in the extension list advertised to tests.
159     const auto &extensionPtrs = context.getDeviceCreationExtensions();
160 
161     void *pNext = (void *)enabledFeatures2;
162 #ifdef CTS_USES_VULKANSC
163     VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ?
164                                                                  context.getResourceInterface()->getStatMax() :
165                                                                  resetDeviceObjectReservationCreateInfo();
166     memReservationInfo.pNext                               = pNext;
167     pNext                                                  = &memReservationInfo;
168 
169     VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
170     sc10Features.pNext                              = pNext;
171     pNext                                           = &sc10Features;
172 
173     VkPipelineCacheCreateInfo pcCI;
174     std::vector<VkPipelinePoolSize> poolSizes;
175     if (context.getTestContext().getCommandLine().isSubProcess())
176     {
177         if (context.getResourceInterface()->getCacheDataSize() > 0)
178         {
179             pcCI = {
180                 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
181                 DE_NULL,                                      // const void* pNext;
182                 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
183                     VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
184                 context.getResourceInterface()->getCacheDataSize(),       // uintptr_t initialDataSize;
185                 context.getResourceInterface()->getCacheData()            // const void* pInitialData;
186             };
187             memReservationInfo.pipelineCacheCreateInfoCount = 1;
188             memReservationInfo.pPipelineCacheCreateInfos    = &pcCI;
189         }
190 
191         poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
192         if (!poolSizes.empty())
193         {
194             memReservationInfo.pipelinePoolSizeCount = uint32_t(poolSizes.size());
195             memReservationInfo.pPipelinePoolSizes    = poolSizes.data();
196         }
197     }
198 #endif
199 
200     const vk::VkDeviceCreateInfo deviceParams = {
201         vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,      // VkStructureType sType;
202         pNext,                                         // const void* pNext;
203         0u,                                            // VkDeviceCreateFlags flags;
204         1u,                                            // uint32_t queueCreateInfoCount;
205         &queueParams,                                  // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
206         0u,                                            // uint32_t enabledLayerCount;
207         nullptr,                                       // const char* const* ppEnabledLayerNames;
208         de::sizeU32(extensionPtrs),                    // uint32_t enabledExtensionCount;
209         de::dataOrNull(extensionPtrs),                 // const char* const* ppEnabledExtensionNames;
210         enabledFeatures2 ? nullptr : &enabledFeatures1 // const VkPhysicalDeviceFeatures* pEnabledFeatures;
211     };
212 
213     // We are creating a custom device with a potentially large amount of extensions and features enabled, using the default device
214     // as a reference. Some implementations may only enable certain device extensions if some instance extensions are enabled, so in
215     // this case it's important to reuse the context instance when creating the device.
216     const auto &vki           = context.getInstanceInterface();
217     const auto instance       = context.getInstance();
218     const auto physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
219 
220     return createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
221                               context.getPlatformInterface(), instance, vki, physicalDevice, &deviceParams);
222 }
223 
224 enum BeyondType
225 {
226     BUFFER,
227     SIZE
228 };
229 
230 struct TestParamsMaint5
231 {
232     vk::VkPrimitiveTopology topology;
233     uint32_t width;
234     uint32_t height;
235     uint32_t bufferCount;
236     uint32_t rndSeed;
237     bool wholeSize;
238     BeyondType beyondType;
239 };
240 
241 class BindBuffers2Instance : public vkt::TestInstance
242 {
243 public:
BindBuffers2Instance(Context & context,const vk::PipelineConstructionType pipelineConstructionType,const TestParams params,const bool singleBind,const uint32_t count)244     BindBuffers2Instance(Context &context, const vk::PipelineConstructionType pipelineConstructionType,
245                          const TestParams params, const bool singleBind, const uint32_t count)
246         : vkt::TestInstance(context)
247         , m_pipelineConstructionType(pipelineConstructionType)
248         , m_params(params)
249         , m_singleBind(singleBind)
250         , m_count(count)
251     {
252     }
~BindBuffers2Instance(void)253     virtual ~BindBuffers2Instance(void)
254     {
255     }
256 
257     tcu::TestStatus iterate(void) override;
258 
259 private:
260     const vk::PipelineConstructionType m_pipelineConstructionType;
261     const TestParams m_params;
262     const bool m_singleBind;
263     const uint32_t m_count;
264 };
265 
iterate(void)266 tcu::TestStatus BindBuffers2Instance::iterate(void)
267 {
268     const vk::VkInstance instance = m_context.getInstance();
269     const vk::InstanceDriver instanceDriver(m_context.getPlatformInterface(), instance);
270     const vk::InstanceInterface &vki          = m_context.getInstanceInterface();
271     const vk::DeviceInterface &vk             = m_context.getDeviceInterface();
272     const vk::VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
273     const vk::VkDevice device                 = m_context.getDevice();
274     const vk::VkQueue queue                   = m_context.getUniversalQueue();
275     const uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
276     vk::Allocator &allocator                  = m_context.getDefaultAllocator();
277     const auto &deviceExtensions              = m_context.getDeviceExtensions();
278     tcu::TestLog &log                         = m_context.getTestContext().getLog();
279 
280     vk::VkExtent2D extent = {32u, 32u};
281 
282     const std::vector<vk::VkViewport> viewports{vk::makeViewport(extent)};
283     const std::vector<vk::VkRect2D> scissors{vk::makeRect2D(extent)};
284 
285     const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
286         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
287         DE_NULL,                                           // const void* pNext;
288         0u,                                                // VkPipelineLayoutCreateFlags flags;
289         0u,                                                // uint32_t descriptorSetCount;
290         DE_NULL,                                           // const VkDescriptorSetLayout* pSetLayouts;
291         0u,                                                // uint32_t pushConstantRangeCount;
292         DE_NULL                                            // const VkPushDescriptorRange* pPushDescriptorRanges;
293     };
294 
295     const vk::VkImageSubresourceRange colorSubresourceRange =
296         vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
297     const vk::Move<vk::VkImage> colorImage(
298         makeImage(vk, device,
299                   makeImageCreateInfo(extent, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
300                                       vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
301     const de::MovePtr<vk::Allocation> colorImageAlloc(
302         bindImage(vk, device, allocator, *colorImage, vk::MemoryRequirement::Any));
303     const vk::Move<vk::VkImageView> colorImageView(makeImageView(
304         vk, device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D, vk::VK_FORMAT_R32G32B32A32_SFLOAT, colorSubresourceRange));
305 
306     const vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, device, &pipelineLayoutInfo);
307     vk::RenderPassWrapper renderPass(m_pipelineConstructionType, vk, device, vk::VK_FORMAT_R32G32B32A32_SFLOAT);
308     renderPass.createFramebuffer(vk, device, *colorImage, *colorImageView, extent.width, extent.height);
309     const vk::ShaderWrapper vertShaderModule =
310         vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"));
311     const vk::ShaderWrapper fragShaderModule =
312         vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"));
313 
314     //buffer to read the output image
315     auto outBuffer = makeBufferForImage(vk, device, allocator, mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT), extent);
316     auto &outBufferAlloc = outBuffer->getAllocation();
317 
318     std::vector<vk::VkVertexInputAttributeDescription> attributes;
319     if (m_count == 2)
320     {
321         attributes = {
322             makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32_SFLOAT, 0),
323             makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0),
324             makeAttributeDescription(2, 2, vk::VK_FORMAT_R32G32_SFLOAT, 0),
325             makeAttributeDescription(3, 3, vk::VK_FORMAT_R32G32_SFLOAT, 0),
326         };
327     }
328     else if (m_count == 3)
329     {
330         attributes = {
331             makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32_SFLOAT, 0),
332             makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0),
333             makeAttributeDescription(2, 2, vk::VK_FORMAT_R32_SFLOAT, 0),
334             makeAttributeDescription(3, 3, vk::VK_FORMAT_R32_SFLOAT, 0),
335             makeAttributeDescription(4, 4, vk::VK_FORMAT_R32_SFLOAT, 0),
336             makeAttributeDescription(5, 5, vk::VK_FORMAT_R32_SFLOAT, 0),
337         };
338     }
339     else if (m_count == 4)
340     {
341         attributes = {
342             makeAttributeDescription(0, 0, vk::VK_FORMAT_R32_SFLOAT, 0),
343             makeAttributeDescription(1, 1, vk::VK_FORMAT_R32_SFLOAT, 0),
344             makeAttributeDescription(2, 2, vk::VK_FORMAT_R32_SFLOAT, 0),
345             makeAttributeDescription(3, 3, vk::VK_FORMAT_R32_SFLOAT, 0),
346             makeAttributeDescription(4, 4, vk::VK_FORMAT_R32_SFLOAT, 0),
347             makeAttributeDescription(5, 5, vk::VK_FORMAT_R32_SFLOAT, 0),
348             makeAttributeDescription(6, 6, vk::VK_FORMAT_R32_SFLOAT, 0),
349             makeAttributeDescription(7, 7, vk::VK_FORMAT_R32_SFLOAT, 0),
350         };
351     }
352     else
353     {
354         attributes = {
355             makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0),
356             makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0),
357         };
358     }
359 
360     log << tcu::TestLog::Message << "VkVertexInputAttributeDescription:" << tcu::TestLog::EndMessage;
361     for (const auto &attrib : attributes)
362     {
363         log << tcu::TestLog::Message << "location " << attrib.location << ", binding " << attrib.binding << ", format "
364             << attrib.format << tcu::TestLog::EndMessage;
365     }
366 
367     std::vector<vk::VkVertexInputBindingDescription> bindings;
368     for (uint32_t i = 0; i < m_count; ++i)
369     {
370         bindings.push_back(makeBindingDescription(i * 2, 99 /*ignored*/, vk::VK_VERTEX_INPUT_RATE_INSTANCE));
371         bindings.push_back(makeBindingDescription(i * 2 + 1, 99 /*ignored*/, vk::VK_VERTEX_INPUT_RATE_VERTEX));
372     };
373     log << tcu::TestLog::Message << "VkVertexInputBindingDescription:\n" << tcu::TestLog::EndMessage;
374     for (const auto &binding : bindings)
375     {
376         log << tcu::TestLog::Message << "binding " << binding.binding << ", stride " << binding.stride << ", inputRate "
377             << binding.inputRate << tcu::TestLog::EndMessage;
378     }
379 
380     vk::VkPipelineVertexInputStateCreateInfo vertexInputState = vk::initVulkanStructure();
381     vertexInputState.vertexBindingDescriptionCount            = (uint32_t)bindings.size();
382     vertexInputState.pVertexBindingDescriptions               = bindings.data();
383     vertexInputState.vertexAttributeDescriptionCount          = (uint32_t)attributes.size();
384     vertexInputState.pVertexAttributeDescriptions             = attributes.data();
385 
386     vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vk::initVulkanStructure();
387     inputAssemblyState.topology                                   = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
388 
389     const vk::VkDynamicState dynamicState = vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
390 
391     const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
392         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
393         nullptr,                                                  // const void* pNext;
394         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
395         1u,                                                       // uint32_t dynamicStateCount;
396         &dynamicState,                                            // const VkDynamicState* pDynamicStates;
397     };
398 
399     vk::GraphicsPipelineWrapper graphicsPipelineWrapper{
400         vki, vk, physicalDevice, device, deviceExtensions, m_pipelineConstructionType};
401     graphicsPipelineWrapper.setDefaultDepthStencilState()
402         .setDefaultColorBlendState()
403         .setDefaultRasterizationState()
404         .setDefaultMultisampleState()
405         .setDynamicState(&dynamicStateInfo)
406         .setupVertexInputState(&vertexInputState, &inputAssemblyState)
407         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass.get(), 0u, vertShaderModule)
408         .setupFragmentShaderState(pipelineLayout, renderPass.get(), 0u, fragShaderModule)
409         .setupFragmentOutputState(renderPass.get())
410         .setMonolithicPipelineLayout(pipelineLayout)
411         .buildPipeline();
412 
413     const vk::Move<vk::VkCommandPool> cmdPool(
414         createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
415     const vk::Move<vk::VkCommandBuffer> cmdBuffer(
416         allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
417 
418     uint32_t instanceCount        = 4u;
419     vk::VkDeviceSize colorStride  = m_params.colorStride * sizeof(float);
420     vk::VkDeviceSize colorOffset  = m_params.colorOffset * sizeof(float);
421     vk::VkDeviceSize vertexStride = m_params.vertexStride * sizeof(float);
422     vk::VkDeviceSize vertexOffset = m_params.vertexOffset * sizeof(float);
423 
424     tcu::Vec4 colors[] = {
425         tcu::Vec4(0.21f, 0.41f, 0.61f, 0.81f),
426         tcu::Vec4(0.22f, 0.42f, 0.62f, 0.82f),
427         tcu::Vec4(0.23f, 0.43f, 0.63f, 0.83f),
428         tcu::Vec4(0.24f, 0.44f, 0.64f, 0.84f),
429     };
430 
431     tcu::Vec4 vertices[] = {
432         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
433         tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f),
434         tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
435         tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
436     };
437 
438     std::vector<float> colorData;
439     for (uint32_t i = 0; i < colorOffset / sizeof(float); ++i)
440         colorData.push_back(0);
441 
442     for (uint32_t i = 0; i < 4; ++i)
443     {
444         colorData.push_back(colors[i].x());
445         colorData.push_back(colors[i].y());
446         colorData.push_back(colors[i].z());
447         colorData.push_back(colors[i].w());
448         for (uint32_t j = 4; j < colorStride / sizeof(float); ++j)
449             colorData.push_back(0.0f);
450     }
451 
452     std::vector<float> vertexData;
453     for (uint32_t i = 0; i < vertexOffset / sizeof(float); ++i)
454         vertexData.push_back(0);
455 
456     for (uint32_t i = 0; i < 4; ++i)
457     {
458         vertexData.push_back(vertices[i].x());
459         vertexData.push_back(vertices[i].y());
460         vertexData.push_back(vertices[i].z());
461         vertexData.push_back(vertices[i].w());
462         for (uint32_t j = 4; j < vertexStride / sizeof(float); ++j)
463             vertexData.push_back(0.0f);
464     }
465 
466     vk::VkClearValue clearColorValue = defaultClearValue(vk::VK_FORMAT_R32G32B32A32_SFLOAT);
467     vk::VkDeviceSize colorDataSize   = colorData.size() * sizeof(float);
468     vk::VkDeviceSize vertexDataSize  = vertexData.size() * sizeof(float);
469 
470     std::vector<vk::VkDeviceSize> offsets = {colorOffset, vertexOffset};
471     if (m_count == 2)
472     {
473         offsets.push_back(colorOffset + sizeof(float) * 2);
474         offsets.push_back(vertexOffset + sizeof(float) * 2);
475     }
476     else if (m_count == 3)
477     {
478         offsets.push_back(colorOffset + sizeof(float) * 2);
479         offsets.push_back(vertexOffset + sizeof(float) * 2);
480         offsets.push_back(colorOffset + sizeof(float) * 3);
481         offsets.push_back(vertexOffset + sizeof(float) * 3);
482     }
483     else if (m_count == 4)
484     {
485         offsets.push_back(colorOffset + sizeof(float));
486         offsets.push_back(vertexOffset + sizeof(float));
487         offsets.push_back(colorOffset + sizeof(float) * 2);
488         offsets.push_back(vertexOffset + sizeof(float) * 2);
489         offsets.push_back(colorOffset + sizeof(float) * 3);
490         offsets.push_back(vertexOffset + sizeof(float) * 3);
491     }
492 
493     std::vector<de::MovePtr<vk::BufferWithMemory>> colorBuffers;
494     std::vector<de::MovePtr<vk::BufferWithMemory>> vertexBuffers;
495     std::vector<vk::VkBuffer> buffers;
496     for (uint32_t i = 0; i < m_count; ++i)
497     {
498         const auto colorCreateInfo =
499             vk::makeBufferCreateInfo((colorDataSize + offsets[i * 2]), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
500         colorBuffers.emplace_back(de::MovePtr<vk::BufferWithMemory>(
501             new vk::BufferWithMemory(vk, device, allocator, colorCreateInfo, vk::MemoryRequirement::HostVisible)));
502         copyAndFlush(vk, device, *colorBuffers[i], 0, colorData.data(), colorData.size() * sizeof(float));
503         buffers.push_back(**colorBuffers[i]);
504 
505         const auto vertexCreateInfo =
506             vk::makeBufferCreateInfo((vertexDataSize + offsets[i * 2 + 1]), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
507         vertexBuffers.emplace_back(de::MovePtr<vk::BufferWithMemory>(
508             new vk::BufferWithMemory(vk, device, allocator, vertexCreateInfo, vk::MemoryRequirement::HostVisible)));
509         copyAndFlush(vk, device, *vertexBuffers[i], 0, vertexData.data(), vertexData.size() * sizeof(float));
510         buffers.push_back(**vertexBuffers[i]);
511     }
512 
513     beginCommandBuffer(vk, *cmdBuffer);
514     renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, extent.width, extent.height), clearColorValue);
515     graphicsPipelineWrapper.bind(*cmdBuffer);
516 
517     std::vector<vk::VkDeviceSize> sizes;
518     for (uint32_t i = 0; i < m_count; ++i)
519     {
520         sizes.push_back(colorDataSize);
521         sizes.push_back(vertexDataSize);
522     }
523     vk::VkDeviceSize strides[] = {colorStride, vertexStride, colorStride, vertexStride,
524                                   colorStride, vertexStride, colorStride, vertexStride};
525     if (m_singleBind)
526     {
527 #ifndef CTS_USES_VULKANSC
528         vk.cmdBindVertexBuffers2(*cmdBuffer, 0, 2 * m_count, buffers.data(), offsets.data(), sizes.data(), strides);
529 #else
530         vk.cmdBindVertexBuffers2EXT(*cmdBuffer, 0, 2 * m_count, buffers.data(), offsets.data(), sizes.data(), strides);
531 #endif
532     }
533     else
534     {
535         for (uint32_t i = 0; i < m_count * 2; ++i)
536         {
537 #ifndef CTS_USES_VULKANSC
538             vk.cmdBindVertexBuffers2(*cmdBuffer, i, 1, &buffers[i], &offsets[i], &sizes[i], &strides[i]);
539 #else
540             vk.cmdBindVertexBuffers2EXT(*cmdBuffer, i, 1, &buffers[i], &offsets[i], &sizes[i], &strides[i]);
541 #endif
542         }
543     }
544     log << tcu::TestLog::Message << "vkCmdBindVertexBuffers2" << tcu::TestLog::EndMessage;
545     for (uint32_t i = 0; i < m_count * 2; ++i)
546     {
547         log << tcu::TestLog::Message << "binding " << i << ", buffer " << buffers[i] << ", offset " << offsets[i]
548             << ", size " << sizes[i] << ", stride " << strides[i] << tcu::TestLog::EndMessage;
549     }
550 
551     vk.cmdDraw(*cmdBuffer, 4, instanceCount, 0, 0);
552     renderPass.end(vk, *cmdBuffer);
553 
554     vk::copyImageToBuffer(vk, *cmdBuffer, *colorImage, (*outBuffer).get(), tcu::IVec2(extent.width, extent.height));
555     endCommandBuffer(vk, *cmdBuffer);
556 
557     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
558 
559     invalidateAlloc(vk, device, outBufferAlloc);
560     const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT),
561                                              tcu::IVec3(extent.width, extent.height, 1),
562                                              (const char *)outBufferAlloc.getHostPtr());
563 
564     const uint32_t h = result.getHeight();
565     const uint32_t w = result.getWidth();
566     for (uint32_t y = 0; y < h; y++)
567     {
568         for (uint32_t x = 0; x < w; x++)
569         {
570             tcu::Vec4 pix = result.getPixel(x, y);
571 
572             if (x >= w / 2 && y >= h / 2 && pix != colors[0])
573             {
574                 log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix
575                     << ", but expected color was " << colors[0] << tcu::TestLog::EndMessage;
576                 return tcu::TestStatus::fail("Fail");
577             }
578             if (x < w / 2 && y >= h / 2 && pix != colors[colorStride == 0 ? 0 : 1])
579             {
580                 log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix
581                     << ", but expected color was " << colors[colorStride == 0 ? 0 : 1] << tcu::TestLog::EndMessage;
582                 return tcu::TestStatus::fail("Fail");
583             }
584             if (x >= w / 2 && y < h / 2 && pix != colors[colorStride == 0 ? 0 : 2])
585             {
586                 log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix
587                     << ", but expected color was " << colors[colorStride == 0 ? 0 : 2] << tcu::TestLog::EndMessage;
588                 return tcu::TestStatus::fail("Fail");
589             }
590             if (x < w / 2 && y < h / 2 && pix != colors[colorStride == 0 ? 0 : 3])
591             {
592                 log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix
593                     << ", but expected color was " << colors[colorStride == 0 ? 0 : 3] << tcu::TestLog::EndMessage;
594                 return tcu::TestStatus::fail("Fail");
595             }
596         }
597     }
598 
599     return tcu::TestStatus::pass("Pass");
600 }
601 
602 class BindVertexBuffers2Instance : public vkt::TestInstance
603 {
604 public:
BindVertexBuffers2Instance(Context & context,DeviceDriverPtr driver,DevicePtr device,vk::PipelineConstructionType pipelineConstructionType,const TestParamsMaint5 & params,bool robustness2)605     BindVertexBuffers2Instance(Context &context, DeviceDriverPtr driver, DevicePtr device,
606                                vk::PipelineConstructionType pipelineConstructionType, const TestParamsMaint5 &params,
607                                bool robustness2)
608         : vkt::TestInstance(context)
609         , m_pipelineConstructionType(pipelineConstructionType)
610         , m_params(params)
611         , m_robustness2(robustness2)
612         , m_deviceDriver(driver)
613         , m_device(device)
614         , m_physicalDevice(chooseDevice(context.getInstanceInterface(), context.getInstance(),
615                                         context.getTestContext().getCommandLine()))
616         , m_allocator(getDeviceInterface(), getDevice(),
617                       getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), m_physicalDevice))
618         , m_pipelineWrapper(context.getInstanceInterface(), getDeviceInterface(), m_physicalDevice, getDevice(),
619                             m_context.getDeviceExtensions(), m_pipelineConstructionType, 0u)
620         , m_vertShaderModule(getDeviceInterface(), getDevice(), m_context.getBinaryCollection().get("vert"))
621         , m_fragShaderModule(getDeviceInterface(), getDevice(), m_context.getBinaryCollection().get("frag"))
622     {
623     }
624     virtual ~BindVertexBuffers2Instance(void) = default;
625 
626     tcu::TestStatus iterate(void) override;
627 
628 protected:
629     typedef std::vector<vk::VkDeviceSize> Sizes;
630     typedef std::vector<de::SharedPtr<vk::BufferWithMemory>> Buffers;
631     const vk::DeviceInterface &getDeviceInterface() const;
632     vk::VkDevice getDevice() const;
633     vk::VkQueue getQueue() const;
634     vk::Allocator &getAllocator();
635     void createPipeline(const vk::PipelineLayoutWrapper &layout, vk::VkRenderPass renderPass);
636     Buffers createBuffers(Sizes &offsets, Sizes &strides, Sizes &sizes);
637 
638 private:
639     const vk::PipelineConstructionType m_pipelineConstructionType;
640     const TestParamsMaint5 m_params;
641     const bool m_robustness2;
642     DeviceDriverPtr m_deviceDriver;
643     DevicePtr m_device;
644     const vk::VkPhysicalDevice m_physicalDevice;
645     vk::SimpleAllocator m_allocator;
646     vk::GraphicsPipelineWrapper m_pipelineWrapper;
647     const vk::ShaderWrapper m_vertShaderModule;
648     const vk::ShaderWrapper m_fragShaderModule;
649 };
650 
getDeviceInterface() const651 const vk::DeviceInterface &BindVertexBuffers2Instance::getDeviceInterface() const
652 {
653     return m_robustness2 ? *m_deviceDriver : m_context.getDeviceInterface();
654 }
655 
getDevice() const656 vk::VkDevice BindVertexBuffers2Instance::getDevice() const
657 {
658     return m_robustness2 ? *m_device : m_context.getDevice();
659 }
660 
getQueue() const661 vk::VkQueue BindVertexBuffers2Instance::getQueue() const
662 {
663     vk::VkQueue queue = DE_NULL;
664     if (m_robustness2)
665     {
666         const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
667         m_deviceDriver->getDeviceQueue(getDevice(), queueFamilyIndex, 0, &queue);
668     }
669     else
670     {
671         queue = m_context.getUniversalQueue();
672     }
673     return queue;
674 }
675 
getAllocator()676 vk::Allocator &BindVertexBuffers2Instance::getAllocator()
677 {
678     return m_allocator;
679 }
680 
createPipeline(const vk::PipelineLayoutWrapper & layout,vk::VkRenderPass renderPass)681 void BindVertexBuffers2Instance::createPipeline(const vk::PipelineLayoutWrapper &layout, vk::VkRenderPass renderPass)
682 {
683     vk::VkPhysicalDeviceProperties dp{};
684     m_context.getInstanceInterface().getPhysicalDeviceProperties(m_physicalDevice, &dp);
685 
686     const std::vector<vk::VkViewport> viewports{vk::makeViewport(m_params.width, m_params.height)};
687     const std::vector<vk::VkRect2D> scissors{vk::makeRect2D(m_params.width, m_params.height)};
688 
689     std::vector<vk::VkVertexInputBindingDescription> bindings{
690         // color buffer binding
691         makeBindingDescription(0, dp.limits.maxVertexInputBindingStride /* ignored */,
692                                vk::VK_VERTEX_INPUT_RATE_VERTEX)};
693     for (uint32_t b = 1; b < m_params.bufferCount; ++b)
694     {
695         // vertex buffer binding
696         bindings.push_back(makeBindingDescription(b, dp.limits.maxVertexInputBindingStride /* ignored */,
697                                                   vk::VK_VERTEX_INPUT_RATE_VERTEX));
698     }
699 
700     std::vector<vk::VkVertexInputAttributeDescription> attributes{
701         // color attribute layout information
702         makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32B32_SFLOAT, 0)};
703     for (uint32_t lb = 1; lb < m_params.bufferCount; ++lb)
704     {
705         attributes.push_back(makeAttributeDescription(lb, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0));
706     }
707 
708     vk::VkPipelineVertexInputStateCreateInfo vertexInputState = vk::initVulkanStructure();
709     vertexInputState.vertexBindingDescriptionCount            = (uint32_t)bindings.size();
710     vertexInputState.pVertexBindingDescriptions               = bindings.data();
711     vertexInputState.vertexAttributeDescriptionCount          = (uint32_t)attributes.size();
712     vertexInputState.pVertexAttributeDescriptions             = attributes.data();
713 
714     vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vk::initVulkanStructure();
715     inputAssemblyState.topology                                   = m_params.topology;
716 
717     const vk::VkDynamicState dynamicState = vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
718 
719     const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo{
720         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
721         nullptr,                                                  // const void* pNext;
722         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
723         1u,                                                       // uint32_t dynamicStateCount;
724         &dynamicState,                                            // const VkDynamicState* pDynamicStates;
725     };
726 
727     const vk::VkPipelineRasterizationStateCreateInfo rasterizationCreateInfo{
728         vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType                                sType
729         DE_NULL,                     // const void*                                    pNext
730         0u,                          // VkPipelineRasterizationStateCreateFlags        flags
731         VK_FALSE,                    // VkBool32                                        depthClampEnable
732         VK_FALSE,                    // VkBool32                                        rasterizerDiscardEnable
733         vk::VK_POLYGON_MODE_FILL,    // VkPolygonMode                                polygonMode
734         vk::VK_CULL_MODE_NONE,       // VkCullModeFlags                                cullMode
735         vk::VK_FRONT_FACE_CLOCKWISE, // VkFrontFace                                    frontFace
736         VK_FALSE,                    // VkBool32                                        depthBiasEnable
737         0.0f,                        // float                                        depthBiasConstantFactor
738         0.0f,                        // float                                        depthBiasClamp
739         0.0f,                        // float                                        depthBiasSlopeFactor
740         1.0f                         // float                                        lineWidth
741     };
742 
743     m_pipelineWrapper.setDefaultDepthStencilState()
744         .setDefaultColorBlendState()
745         //.setDefaultRasterizationState()
746         .setDefaultMultisampleState()
747         .setDynamicState(&dynamicStateInfo)
748         .setupVertexInputState(&vertexInputState, &inputAssemblyState)
749         .setupPreRasterizationShaderState(viewports, scissors, layout, renderPass, 0u, m_vertShaderModule,
750                                           &rasterizationCreateInfo)
751         .setupFragmentShaderState(layout, renderPass, 0u, m_fragShaderModule)
752         .setupFragmentOutputState(renderPass)
753         .setMonolithicPipelineLayout(layout)
754         .buildPipeline();
755 }
756 
createBuffers(Sizes & offsets,Sizes & strides,Sizes & sizes)757 BindVertexBuffers2Instance::Buffers BindVertexBuffers2Instance::createBuffers(Sizes &offsets, Sizes &strides,
758                                                                               Sizes &sizes)
759 {
760     Buffers buffers;
761     vk::Allocator &allocator      = getAllocator();
762     const vk::DeviceInterface &vk = getDeviceInterface();
763     const vk::VkDevice device     = getDevice();
764     de::Random rnd(m_params.rndSeed);
765     const float p = 1.0f / float(m_params.bufferCount - 1);
766     DE_ASSERT(m_params.bufferCount >= 2);
767     const uint32_t compCount = uint32_t(sizeof(tcu::Vec2) / sizeof(float));
768 
769     std::vector<float> pointTemplate;
770     uint32_t returnSize = 0;
771     uint32_t sourceSize = 0;
772     uint32_t allocSize  = 0;
773 
774     if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
775     {
776         //-1 / -1 / 0 / -1 / -1 / 0
777         pointTemplate.push_back(-p);
778         pointTemplate.push_back(-p);
779         pointTemplate.push_back(0.0f);
780         pointTemplate.push_back(-p);
781         pointTemplate.push_back(-p);
782         pointTemplate.push_back(0.0f);
783         if (!m_robustness2)
784         {
785             pointTemplate.push_back(0.0f);
786             pointTemplate.push_back(0.0f);
787             // Beyonds do not matter
788             sourceSize = 4;
789             allocSize  = 4;
790             returnSize = 4; // or WHOLE_SIZE
791         }
792         else
793         {
794             pointTemplate.push_back(+p); // those should be read as (0,0)
795             pointTemplate.push_back(+p);
796 
797             switch (m_params.beyondType)
798             {
799             case BeyondType::BUFFER:
800                 sourceSize = 3;
801                 allocSize  = 3;
802                 returnSize = 3;
803                 break;
804             case BeyondType::SIZE:
805                 DE_ASSERT(m_params.wholeSize == false);
806                 sourceSize = 4;
807                 allocSize  = 4;
808                 returnSize = 3;
809                 break;
810             }
811         }
812     }
813     else if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
814     {
815         // -1/0/ -1/-1 /0/-1 /-1/0 /0/-1
816         pointTemplate.push_back(-p);
817         pointTemplate.push_back(0.0f);
818         pointTemplate.push_back(-p);
819         pointTemplate.push_back(-p);
820         pointTemplate.push_back(0.0);
821         pointTemplate.push_back(-p);
822         pointTemplate.push_back(-p);
823         pointTemplate.push_back(0.0f);
824         pointTemplate.push_back(0.0f);
825         pointTemplate.push_back(-p);
826         if (!m_robustness2)
827         {
828             pointTemplate.push_back(0.0f);
829             pointTemplate.push_back(0.0f);
830             // Beyonds do not matter
831             sourceSize = 6;
832             allocSize  = 6;
833             returnSize = 6; // or WHOLE_SIZE
834         }
835         else
836         {
837             // those should be read as (0,0)
838             pointTemplate.push_back(+p);
839             pointTemplate.push_back(+p);
840 
841             switch (m_params.beyondType)
842             {
843             case BeyondType::BUFFER:
844                 sourceSize = 5;
845                 allocSize  = 5;
846                 returnSize = 5;
847                 break;
848             case BeyondType::SIZE:
849                 sourceSize = 6;
850                 allocSize  = 6;
851                 returnSize = 5;
852                 break;
853             }
854         }
855     }
856     else
857     {
858         DE_ASSERT(0);
859     }
860     DE_ASSERT((allocSize != 0) && (allocSize >= sourceSize));
861 
862     const std::vector<float> &source = pointTemplate;
863 
864     std::vector<tcu::Vec3> colorTemplate(7);
865     for (int i = 1; i <= 7; ++i)
866     {
867         colorTemplate[i - 1] = {i & 0x1 ? 1.0f : 0.6f, i & 0x2 ? 1.0f : 0.6f, i & 0x4 ? 1.0f : 0.6f};
868     }
869     std::vector<float> colors(sourceSize * 3);
870     for (uint32_t i = 0; i < sourceSize; ++i)
871     {
872         const tcu::Vec3 &c = colorTemplate[i % colorTemplate.size()];
873         colors[3 * i + 0]  = c.x();
874         colors[3 * i + 1]  = c.y();
875         colors[3 * i + 2]  = c.z();
876     }
877     vk::VkDeviceSize clrSize = allocSize * 3 * sizeof(float);
878     const vk::VkBufferCreateInfo clrCreateInfo =
879         vk::makeBufferCreateInfo(clrSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
880     de::SharedPtr<vk::BufferWithMemory> clrBuffer(
881         new vk::BufferWithMemory(vk, device, allocator, clrCreateInfo, vk::MemoryRequirement::HostVisible));
882     copyAndFlush(vk, device, *clrBuffer, 0, colors.data(), uint32_t(colors.size() * sizeof(float)));
883     buffers.push_back(clrBuffer);
884 
885     sizes.resize(m_params.bufferCount);
886     sizes[0] = m_params.wholeSize ? VK_WHOLE_SIZE : (returnSize * 3 * sizeof(float));
887 
888     offsets.resize(m_params.bufferCount);
889     strides.resize(m_params.bufferCount);
890 
891     // random offsets multiplyied later by 4, special value 0 for no-offset
892     offsets[0] = 0;
893     for (uint32_t i = 1; i < m_params.bufferCount; ++i)
894     {
895         auto nextOffset = [&]()
896         {
897             vk::VkDeviceSize offset = rnd.getUint64() % 30;
898             while (offset == 0)
899                 offset = rnd.getUint64() % 30;
900             return offset;
901         };
902         offsets[i] = (m_params.rndSeed == 0) ? vk::VkDeviceSize(0) : nextOffset();
903     }
904 
905     // random strides multiplyied later by 4, special value for atributes stride
906     strides[0] = {sizeof(tcu::Vec3)};
907     for (uint32_t i = 1; i < m_params.bufferCount; ++i)
908     {
909         auto nextStride = [&]()
910         {
911             vk::VkDeviceSize stride = rnd.getUint64() % 30;
912             while (stride == 0)
913                 stride = rnd.getUint64() % 30;
914             return stride;
915         };
916         strides[i] = (m_params.rndSeed == 0) ? vk::VkDeviceSize(0) : nextStride();
917     }
918 
919     for (uint32_t i = 1; i < m_params.bufferCount; ++i)
920     {
921         const uint32_t stride = uint32_t(strides[i]);
922         const uint32_t offset = uint32_t(offsets[i]);
923         std::vector<float> points(offset + sourceSize * (compCount + stride));
924 
925         for (uint32_t j = 0; j < offset; ++j)
926         {
927             points[j] = float(i * 13) + 0.234f;
928         }
929         for (uint32_t j = 0; j < sourceSize; ++j)
930         {
931             auto k        = offset + j * (compCount + stride);
932             points[k + 0] = source[j * compCount + 0];
933             points[k + 1] = source[j * compCount + 1];
934             for (uint32_t s = 0; s < stride; ++s)
935             {
936                 points[k + compCount + s] = float(i * 19) + 0.543f;
937             }
938         }
939 
940         vk::VkDeviceSize size                   = (offset + allocSize * (compCount + stride)) * sizeof(float);
941         const vk::VkBufferCreateInfo createInfo = vk::makeBufferCreateInfo(size, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
942         de::SharedPtr<vk::BufferWithMemory> buffer(
943             new vk::BufferWithMemory(vk, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
944         copyAndFlush(vk, device, *buffer, 0, points.data(), uint32_t(points.size() * sizeof(float)));
945 
946         sizes[i]   = m_params.wholeSize ? VK_WHOLE_SIZE : ((compCount + stride) * returnSize * sizeof(float));
947         strides[i] = (compCount + stride) * sizeof(float);
948         offsets[i] = offset * sizeof(float);
949         buffers.push_back(buffer);
950     }
951 
952     return buffers;
953 }
954 
955 template <class X>
956 struct collection_element
957 {
958 };
959 template <template <class, class...> class coll__, class X, class... Y>
960 struct collection_element<coll__<X, Y...>>
961 {
962     typedef X type;
963 };
964 template <class coll__>
965 using collection_element_t = typename collection_element<coll__>::type;
966 
iterate(void)967 tcu::TestStatus BindVertexBuffers2Instance::iterate(void)
968 {
969     const vk::DeviceInterface &vk   = getDeviceInterface();
970     const vk::VkDevice device       = getDevice();
971     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
972     const vk::VkQueue queue         = getQueue();
973     vk::Allocator &allocator        = getAllocator();
974     tcu::TestLog &log               = m_context.getTestContext().getLog();
975 
976     const vk::VkExtent2D extent{m_params.width, m_params.height};
977     const vk::VkImageSubresourceRange colorSubresRange =
978         vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
979     const vk::VkFormat colorFormat = vk::VK_FORMAT_R32G32B32A32_SFLOAT;
980     const vk::Move<vk::VkImage> colorImage =
981         makeImage(vk, device,
982                   makeImageCreateInfo(extent, colorFormat,
983                                       vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
984     const de::MovePtr<vk::Allocation> colorImageAlloc =
985         bindImage(vk, device, allocator, *colorImage, vk::MemoryRequirement::Any);
986     const vk::Move<vk::VkImageView> colorImageView =
987         makeImageView(vk, device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresRange);
988     vk::RenderPassWrapper renderPass(m_pipelineConstructionType, vk, device, colorFormat);
989     renderPass.createFramebuffer(vk, device, colorImage.get(), colorImageView.get(), extent.width, extent.height);
990     const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = vk::initVulkanStructure();
991     const vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, device, &pipelineLayoutInfo,
992                                                    nullptr);
993 
994     const vk::VkClearValue clearColorValue = vk::makeClearValueColor(tcu::Vec4(0.5f));
995     const vk::Move<vk::VkCommandPool> cmdPool =
996         createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
997     const vk::Move<vk::VkCommandBuffer> cmdBuffer =
998         allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
999 
1000     Sizes offsets;
1001     Sizes strides;
1002     Sizes sizes;
1003     Buffers buffers = createBuffers(offsets, strides, sizes);
1004     std::vector<vk::VkBuffer> vkBuffers(buffers.size());
1005     std::transform(buffers.begin(), buffers.end(), vkBuffers.begin(),
1006                    [](collection_element_t<decltype(buffers)> buffer) { return **buffer; });
1007 
1008     uint32_t vertexCount = 0;
1009     switch (m_params.topology)
1010     {
1011     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1012         vertexCount = 4;
1013         break;
1014     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1015         vertexCount = 6;
1016         break;
1017     default:
1018         DE_ASSERT(0);
1019         break;
1020     };
1021 
1022     std::unique_ptr<vk::BufferWithMemory> outBuffer =
1023         makeBufferForImage(vk, device, allocator, mapVkFormat(colorFormat), extent);
1024     vk::Allocation &outBufferAlloc = outBuffer->getAllocation();
1025 
1026     createPipeline(pipelineLayout, *renderPass);
1027 
1028     beginCommandBuffer(vk, *cmdBuffer);
1029     renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, extent.width, extent.height), 1u, &clearColorValue);
1030     m_pipelineWrapper.bind(*cmdBuffer);
1031 #ifndef CTS_USES_VULKANSC
1032     vk.cmdBindVertexBuffers2(*cmdBuffer, 0, m_params.bufferCount, vkBuffers.data(), offsets.data(), sizes.data(),
1033                              strides.data());
1034 #else
1035     vk.cmdBindVertexBuffers2EXT(*cmdBuffer, 0, m_params.bufferCount, vkBuffers.data(), offsets.data(), sizes.data(),
1036                                 strides.data());
1037 #endif
1038     vk.cmdDraw(*cmdBuffer, vertexCount, 1, 0, 0);
1039     renderPass.end(vk, *cmdBuffer);
1040     vk::copyImageToBuffer(vk, *cmdBuffer, *colorImage, **outBuffer, tcu::IVec2(extent.width, extent.height));
1041     endCommandBuffer(vk, *cmdBuffer);
1042 
1043     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1044 
1045     invalidateAlloc(vk, device, outBufferAlloc);
1046     const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(colorFormat), extent.width, extent.height, 1,
1047                                              outBufferAlloc.getHostPtr());
1048 
1049     bool testPasses          = false;
1050     uint32_t equalClearCount = 0;
1051     uint32_t halfWidth       = m_params.width / 2;
1052     uint32_t halfHeight      = m_params.height / 2;
1053 
1054     for (uint32_t Y = 0; (Y < halfHeight); ++Y)
1055         for (uint32_t X = 0; (X < halfWidth); ++X)
1056         {
1057             const tcu::Vec4 px = result.getPixel(X, Y);
1058             if (px.x() == clearColorValue.color.float32[0] && px.y() == clearColorValue.color.float32[1] &&
1059                 px.z() == clearColorValue.color.float32[2])
1060             {
1061                 equalClearCount = equalClearCount + 1;
1062             }
1063         }
1064     const double mismatch          = double(equalClearCount) / double(halfWidth * halfHeight);
1065     const std::string mismatchText = "Mismatch: " + std::to_string(uint32_t(mismatch * 100.9)) + '%';
1066 
1067     const float eps = 0.2f;
1068     const tcu::Vec3 threshold(eps, eps, eps);
1069     const tcu::UVec2 middle(halfWidth - 1u, halfHeight - 1u);
1070     const tcu::Vec4 rgba      = result.getPixel(middle.x(), middle.y());
1071     const tcu::Vec3 rgb       = rgba.swizzle(0, 1, 2);
1072     const bool belowThreshold = tcu::boolAll(tcu::lessThan(rgb, threshold));
1073 
1074     if (!m_robustness2)
1075     {
1076         const auto expectedMismatch = 0.0;
1077         testPasses                  = (belowThreshold == false) && (mismatch == expectedMismatch);
1078         if (!testPasses)
1079         {
1080             std::ostringstream msg;
1081             msg << "FAILURE: no robustness; pixel at " << middle << " is " << rgb << " (should be >= " << threshold
1082                 << "); mismatch in upper left quarter " << mismatch << " (should be " << expectedMismatch << ")";
1083             log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1084         }
1085     }
1086     else
1087     {
1088         const auto mismatchLimit = 0.25;
1089         testPasses               = (belowThreshold == true) && (mismatch < mismatchLimit);
1090         if (!testPasses)
1091         {
1092             std::ostringstream msg;
1093             msg << "FAILURE: robustness2; pixel at " << middle << " is " << rgb << " (should be < " << threshold
1094                 << "); mismatch in upper left quarter " << mismatch << " (should be below " << mismatchLimit << ")";
1095             log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1096         }
1097     }
1098 
1099     auto logOffsets = (log << tcu::TestLog::Message << "Offsets: ");
1100     for (uint32_t k = 0; k < m_params.bufferCount; ++k)
1101     {
1102         if (k)
1103             logOffsets << ", ";
1104         logOffsets << offsets[k];
1105     }
1106     logOffsets << tcu::TestLog::EndMessage;
1107 
1108     auto logSizes = (log << tcu::TestLog::Message << "Sizes: ");
1109     for (uint32_t k = 0; k < m_params.bufferCount; ++k)
1110     {
1111         if (k)
1112             logSizes << ", ";
1113         logSizes << ((sizes[k] == VK_WHOLE_SIZE) ? "WHOLE_SIZE" : std::to_string(sizes[k]).c_str());
1114     }
1115     logSizes << tcu::TestLog::EndMessage;
1116 
1117     auto logStrides = (log << tcu::TestLog::Message << "Strides: ");
1118     for (uint32_t k = 0; k < m_params.bufferCount; ++k)
1119     {
1120         if (k)
1121             logStrides << ", ";
1122         logStrides << strides[k];
1123     }
1124     logStrides << tcu::TestLog::EndMessage;
1125 
1126     if (!testPasses)
1127     {
1128         std::ostringstream os;
1129         os << (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ? "list" : "strip");
1130         os << ".buffs" << m_params.bufferCount;
1131         os << (m_params.wholeSize ? ".whole_size" : ".true_size");
1132         if (m_robustness2)
1133         {
1134             os << ".robust";
1135             os << (m_params.beyondType == BeyondType::BUFFER ? ".over_buff" : ".over_size");
1136         }
1137         os.flush();
1138 
1139         log << tcu::TestLog::ImageSet("Result", "") << tcu::TestLog::Image(os.str(), "", result)
1140             << tcu::TestLog::EndImageSet;
1141     }
1142 
1143     if (!testPasses)
1144         return tcu::TestStatus::fail(mismatchText + "; check log for details");
1145     return tcu::TestStatus::pass(mismatchText);
1146 }
1147 
1148 class BindBuffers2Case : public vkt::TestCase
1149 {
1150 public:
BindBuffers2Case(tcu::TestContext & testCtx,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const TestParams params,const bool singleBind,const uint32_t count)1151     BindBuffers2Case(tcu::TestContext &testCtx, const std::string &name,
1152                      const vk::PipelineConstructionType pipelineConstructionType, const TestParams params,
1153                      const bool singleBind, const uint32_t count)
1154         : vkt::TestCase(testCtx, name)
1155         , m_pipelineConstructionType(pipelineConstructionType)
1156         , m_params(params)
1157         , m_singleBind(singleBind)
1158         , m_count(count)
1159     {
1160     }
~BindBuffers2Case(void)1161     virtual ~BindBuffers2Case(void)
1162     {
1163     }
1164 
1165     void checkSupport(vkt::Context &context) const override;
1166     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const1167     TestInstance *createInstance(Context &context) const override
1168     {
1169         return new BindBuffers2Instance(context, m_pipelineConstructionType, m_params, m_singleBind, m_count);
1170     }
1171 
1172 private:
1173     const vk::PipelineConstructionType m_pipelineConstructionType;
1174     const TestParams m_params;
1175     const bool m_singleBind;
1176     const uint32_t m_count;
1177 };
1178 
checkSupport(Context & context) const1179 void BindBuffers2Case::checkSupport(Context &context) const
1180 {
1181     context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
1182 
1183     vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1184                                               m_pipelineConstructionType);
1185 }
1186 
initPrograms(vk::SourceCollections & programCollection) const1187 void BindBuffers2Case::initPrograms(vk::SourceCollections &programCollection) const
1188 {
1189     std::stringstream vert;
1190     std::stringstream frag;
1191 
1192     std::string inputs;
1193     std::string combined;
1194     if (m_count == 2)
1195     {
1196         inputs   = "layout (location=0) in vec2 rg;\n"
1197                    "layout (location=1) in vec2 xy;\n"
1198                    "layout (location=2) in vec2 ba;\n"
1199                    "layout (location=3) in vec2 zw;\n";
1200         combined = "    vec4 vertex = vec4(xy, zw);\n"
1201                    "    vec4 color = vec4(rg, ba);\n";
1202     }
1203     else if (m_count == 3)
1204     {
1205         inputs   = "layout (location=0) in vec2 rg;\n"
1206                    "layout (location=1) in vec2 xy;\n"
1207                    "layout (location=2) in float b;\n"
1208                    "layout (location=3) in float z;\n"
1209                    "layout (location=4) in float a;\n"
1210                    "layout (location=5) in float w;\n";
1211         combined = "    vec4 vertex = vec4(xy, z, w);\n"
1212                    "    vec4 color = vec4(rg, b, a);\n";
1213     }
1214     else if (m_count == 4)
1215     {
1216         inputs   = "layout (location=0) in float r;\n"
1217                    "layout (location=1) in float x;\n"
1218                    "layout (location=2) in float g;\n"
1219                    "layout (location=3) in float y;\n"
1220                    "layout (location=4) in float b;\n"
1221                    "layout (location=5) in float z;\n"
1222                    "layout (location=6) in float a;\n"
1223                    "layout (location=7) in float w;\n";
1224         combined = "    vec4 vertex = vec4(x, y, z, w);\n"
1225                    "    vec4 color = vec4(r, g, b, a);\n";
1226     }
1227     else
1228     {
1229         inputs   = "layout (location=0) in vec4 rgba;\n"
1230                    "layout (location=1) in vec4 xyzw;\n";
1231         combined = "    vec4 vertex = vec4(xyzw);\n"
1232                    "    vec4 color = vec4(rgba);\n";
1233     }
1234 
1235     vert << "#version 450\n"
1236          << inputs << "layout (location=0) out vec4 outColor;\n"
1237          << "void main() {\n"
1238          << "    vec2 pos = vec2(-float(gl_InstanceIndex & 1), -float((gl_InstanceIndex >> 1) & 1));\n"
1239          << combined << "    gl_Position = vertex + vec4(pos, 0.0f, 1.0f);\n"
1240          << "    outColor = color;\n"
1241          << "}\n";
1242 
1243     frag << "#version 450\n"
1244          << "layout (location=0) in vec4 inColor;\n"
1245          << "layout (location=0) out vec4 outColor;\n"
1246          << "void main() {\n"
1247          << "    outColor = inColor;\n"
1248          << "}\n";
1249 
1250     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1251     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1252 }
1253 
1254 class BindVertexBuffers2Case : public vkt::TestCase
1255 {
1256 public:
BindVertexBuffers2Case(tcu::TestContext & testCtx,const std::string & name,vk::PipelineConstructionType pipelineConstructionType,const TestParamsMaint5 & params,bool robustness2)1257     BindVertexBuffers2Case(tcu::TestContext &testCtx, const std::string &name,
1258                            vk::PipelineConstructionType pipelineConstructionType, const TestParamsMaint5 &params,
1259                            bool robustness2)
1260         : vkt::TestCase(testCtx, name)
1261         , m_pipelineConstructionType(pipelineConstructionType)
1262         , m_params(params)
1263         , m_robustness2(robustness2)
1264     {
1265     }
1266     virtual ~BindVertexBuffers2Case(void) = default;
1267 
1268     void checkSupport(vkt::Context &context) const override;
1269     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
1270     TestInstance *createInstance(Context &context) const override;
1271 
1272 private:
1273     const vk::PipelineConstructionType m_pipelineConstructionType;
1274     const TestParamsMaint5 m_params;
1275     const bool m_robustness2;
1276 };
1277 
checkSupport(Context & context) const1278 void BindVertexBuffers2Case::checkSupport(Context &context) const
1279 {
1280     context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
1281 
1282 #ifndef CTS_USES_VULKANSC
1283     context.requireDeviceFunctionality(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
1284 #endif // CTS_USES_VULKANSC
1285 
1286     if (m_robustness2)
1287     {
1288         vk::VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = vk::initVulkanStructure();
1289         vk::VkPhysicalDeviceFeatures2 features2                        = vk::initVulkanStructure(&robustness2Features);
1290 
1291         context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
1292         if (!features2.features.robustBufferAccess)
1293             TCU_THROW(NotSupportedError, "robustBufferAccess not supported by this implementation");
1294 
1295         context.requireDeviceFunctionality("VK_EXT_robustness2");
1296         if (!robustness2Features.robustBufferAccess2)
1297             TCU_THROW(NotSupportedError, "robustBufferAccess2 not supported by this implementation");
1298     }
1299 
1300     vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1301                                               m_pipelineConstructionType);
1302 }
1303 
initPrograms(vk::SourceCollections & programCollection) const1304 void BindVertexBuffers2Case::initPrograms(vk::SourceCollections &programCollection) const
1305 {
1306     std::ostringstream vert;
1307     vert << "#version 450\n";
1308     vert << "layout(location = 0) in vec3 in_color;\n";
1309     for (uint32_t i = 1; i < m_params.bufferCount; ++i)
1310         vert << "layout(location = " << i << ") in vec2 pos" << i << ";\n";
1311     vert << "layout(location = 0) out vec3 out_color;\n";
1312     vert << "void main() {\n";
1313     vert << "  gl_Position = vec4(";
1314     for (uint32_t i = 1; i < m_params.bufferCount; ++i)
1315     {
1316         if (i > 1)
1317             vert << '+';
1318         vert << "pos" << i;
1319     }
1320     vert << ", 0.0, 1.0);\n";
1321     vert << "  out_color = in_color;\n";
1322     vert << "}\n";
1323     vert.flush();
1324 
1325     const std::string frag("#version 450\n"
1326                            "layout (location = 0) in  vec3 in_color;\n"
1327                            "layout (location = 0) out vec4 out_color;\n"
1328                            "void main() {\n"
1329                            "    out_color = vec4(in_color, 1.0);\n"
1330                            "}\n");
1331 
1332     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1333     programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1334 }
1335 
createInstance(Context & context) const1336 TestInstance *BindVertexBuffers2Case::createInstance(Context &context) const
1337 {
1338     DevicePtr device;
1339     DeviceDriverPtr driver;
1340 
1341     if (m_robustness2)
1342     {
1343         vk::VkPhysicalDeviceFeatures2 features2                        = vk::initVulkanStructure();
1344         vk::VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = vk::initVulkanStructure();
1345 #ifndef CTS_USES_VULKANSC
1346         vk::VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5Features      = vk::initVulkanStructure();
1347         vk::VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT gplFeatures    = vk::initVulkanStructure();
1348         vk::VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures = vk::initVulkanStructure();
1349         vk::VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures      = vk::initVulkanStructure();
1350 #endif // CTS_USES_VULKANSC
1351 
1352         features2.features.robustBufferAccess   = VK_TRUE;
1353         robustness2Features.robustBufferAccess2 = VK_TRUE;
1354 #ifndef CTS_USES_VULKANSC
1355         maintenance5Features.maintenance5         = VK_TRUE;
1356         gplFeatures.graphicsPipelineLibrary       = VK_TRUE;
1357         dynamicRenderingFeatures.dynamicRendering = VK_TRUE;
1358         shaderObjectFeatures.shaderObject         = VK_TRUE;
1359 #endif // CTS_USES_VULKANSC
1360 
1361         const auto addFeatures = vk::makeStructChainAdder(&features2);
1362         addFeatures(&robustness2Features);
1363 
1364 #ifndef CTS_USES_VULKANSC
1365         addFeatures(&maintenance5Features);
1366         if (vk::isConstructionTypeLibrary(m_pipelineConstructionType))
1367             addFeatures(&gplFeatures);
1368         else if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
1369         {
1370             addFeatures(&dynamicRenderingFeatures);
1371             addFeatures(&shaderObjectFeatures);
1372         }
1373 #else
1374         TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_graphics_pipeline_library");
1375 #endif // CTS_USES_VULKANSC
1376 
1377         device = createRobustBufferAccessDevice(context, &features2);
1378         driver =
1379 #ifndef CTS_USES_VULKANSC
1380             DeviceDriverPtr(new vk::DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device,
1381                                                  context.getUsedApiVersion(),
1382                                                  context.getTestContext().getCommandLine()));
1383 #else
1384             DeviceDriverPtr(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device,
1385                                                context.getTestContext().getCommandLine(),
1386                                                context.getResourceInterface(), context.getDeviceVulkanSC10Properties(),
1387                                                context.getDeviceProperties(), context.getUsedApiVersion()),
1388                             vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
1389 #endif // CTS_USES_VULKANSC
1390     }
1391 
1392     return (
1393         new BindVertexBuffers2Instance(context, driver, device, m_pipelineConstructionType, m_params, m_robustness2));
1394 }
1395 
1396 tcu::TestCaseGroup *createCmdBindVertexBuffers2Tests(tcu::TestContext &testCtx,
1397                                                      vk::PipelineConstructionType pipelineConstructionType);
createCmdBindBuffers2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1398 tcu::TestCaseGroup *createCmdBindBuffers2Tests(tcu::TestContext &testCtx,
1399                                                vk::PipelineConstructionType pipelineConstructionType)
1400 {
1401     de::MovePtr<tcu::TestCaseGroup> cmdBindBuffers2Group(new tcu::TestCaseGroup(testCtx, "bind_buffers_2"));
1402 
1403     const struct
1404     {
1405         TestParams params;
1406         const char *name;
1407     } strideTests[] = {
1408         // Values are multiplied by sizeof(float) in the test
1409         {{
1410              0u,
1411              4u,
1412              0u,
1413              0u,
1414          },
1415          "stride_0_4_offset_0_0"},
1416         {{
1417              0u,
1418              4u,
1419              1u,
1420              0u,
1421          },
1422          "stride_0_4_offset_1_0"},
1423         {{
1424              4u,
1425              4u,
1426              0u,
1427              0u,
1428          },
1429          "stride_4_4_offset_0_0"},
1430         {{
1431              5u,
1432              5u,
1433              0u,
1434              7u,
1435          },
1436          "stride_5_5_offset_0_7"},
1437         {{
1438              5u,
1439              8u,
1440              15u,
1441              22u,
1442          },
1443          "stride_5_8_offset_15_22"},
1444         {{
1445              7u,
1446              22u,
1447              100u,
1448              0u,
1449          },
1450          "stride_7_22_offset_100_0"},
1451         {{
1452              40u,
1453              28u,
1454              0u,
1455              0u,
1456          },
1457          "stride_40_28_offset_0_0"},
1458     };
1459 
1460     const struct
1461     {
1462         bool singleBind;
1463         const char *name;
1464     } bindTests[] = {
1465         // Values are multiplied by sizeof(float) in the test
1466         {true, "single"},
1467         {false, "separate"},
1468     };
1469 
1470     const struct
1471     {
1472         uint32_t count;
1473         const char *name;
1474     } countTests[] = {
1475         {1, "count_1"},
1476         {2, "count_2"},
1477         {3, "count_3"},
1478         {4, "count_4"},
1479     };
1480 
1481     for (const auto bindTest : bindTests)
1482     {
1483         de::MovePtr<tcu::TestCaseGroup> bindGroup(new tcu::TestCaseGroup(testCtx, bindTest.name));
1484         for (const auto &strideTest : strideTests)
1485         {
1486             de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, strideTest.name));
1487             for (const auto &countTest : countTests)
1488             {
1489                 typeGroup->addChild(new BindBuffers2Case(testCtx, countTest.name, pipelineConstructionType,
1490                                                          strideTest.params, bindTest.singleBind, countTest.count));
1491             }
1492             bindGroup->addChild(typeGroup.release());
1493         }
1494         cmdBindBuffers2Group->addChild(bindGroup.release());
1495     }
1496 
1497 #ifndef CTS_USES_VULKANSC
1498     cmdBindBuffers2Group->addChild(createCmdBindVertexBuffers2Tests(testCtx, pipelineConstructionType));
1499 #endif // CTS_USES_VULKANSC
1500 
1501     return cmdBindBuffers2Group.release();
1502 }
1503 
createCmdBindVertexBuffers2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1504 tcu::TestCaseGroup *createCmdBindVertexBuffers2Tests(tcu::TestContext &testCtx,
1505                                                      vk::PipelineConstructionType pipelineConstructionType)
1506 {
1507     const uint32_t counts[]{5, 9};
1508     const uint32_t randoms[]{321, 432};
1509     const uint32_t robustRandoms[]{543, 654};
1510     const std::pair<bool, const char *> sizes[]{{true, "whole_size"}, {false, "true_size"}};
1511     const std::pair<BeyondType, const char *> beyondTypes[]{{BeyondType::BUFFER, "beyond_buffer"},
1512                                                             {BeyondType::SIZE, "beyond_size"}};
1513     const std::pair<vk::VkPrimitiveTopology, const char *> topos[]{
1514         {vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangle_list"},
1515         {vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip"},
1516     };
1517 
1518     std::string name;
1519     const uint32_t defaultWidth  = 32;
1520     const uint32_t defaultHeight = 32;
1521 
1522     de::MovePtr<tcu::TestCaseGroup> rootGroup(new tcu::TestCaseGroup(testCtx, "maintenance5"));
1523 
1524     for (const auto &topo : topos)
1525     {
1526         de::MovePtr<tcu::TestCaseGroup> topoGroup(new tcu::TestCaseGroup(testCtx, topo.second));
1527 
1528         for (uint32_t count : counts)
1529         {
1530             name = "buffers" + std::to_string(count);
1531             de::MovePtr<tcu::TestCaseGroup> countGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1532 
1533             for (uint32_t random : randoms)
1534             {
1535                 name = "stride_offset_rnd" + std::to_string(random);
1536                 de::MovePtr<tcu::TestCaseGroup> randomGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1537 
1538                 for (const auto &size : sizes)
1539                 {
1540                     TestParamsMaint5 p;
1541                     p.width       = defaultWidth;
1542                     p.height      = defaultHeight;
1543                     p.topology    = topo.first;
1544                     p.wholeSize   = size.first;
1545                     p.rndSeed     = random;
1546                     p.bufferCount = count;
1547                     p.beyondType  = BeyondType::BUFFER;
1548 
1549                     randomGroup->addChild(
1550                         new BindVertexBuffers2Case(testCtx, size.second, pipelineConstructionType, p, false));
1551                 }
1552                 countGroup->addChild(randomGroup.release());
1553             }
1554             topoGroup->addChild(countGroup.release());
1555         }
1556         rootGroup->addChild(topoGroup.release());
1557     }
1558 
1559     de::MovePtr<tcu::TestCaseGroup> robustGroup(new tcu::TestCaseGroup(testCtx, "robustness2"));
1560     for (const auto &topo : topos)
1561     {
1562         de::MovePtr<tcu::TestCaseGroup> topoGroup(new tcu::TestCaseGroup(testCtx, topo.second));
1563 
1564         for (uint32_t count : counts)
1565         {
1566             name = "buffers" + std::to_string(count);
1567             de::MovePtr<tcu::TestCaseGroup> countGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1568 
1569             for (uint32_t random : robustRandoms)
1570             {
1571                 name = "stride_offset_rnd" + std::to_string(random);
1572                 de::MovePtr<tcu::TestCaseGroup> randomGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1573 
1574                 for (const auto &size : sizes)
1575                 {
1576                     de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, size.second));
1577 
1578                     TestParamsMaint5 p;
1579                     p.width       = defaultWidth;
1580                     p.height      = defaultHeight;
1581                     p.topology    = topo.first;
1582                     p.wholeSize   = size.first;
1583                     p.rndSeed     = random;
1584                     p.bufferCount = count;
1585 
1586                     if (p.wholeSize)
1587                     {
1588                         p.beyondType    = BeyondType::BUFFER;
1589                         auto beyondType = std::find_if(std::begin(beyondTypes), std::end(beyondTypes),
1590                                                        [&](const std::pair<BeyondType, const char *> &b)
1591                                                        { return b.first == p.beyondType; });
1592                         sizeGroup->addChild(
1593                             new BindVertexBuffers2Case(testCtx, beyondType->second, pipelineConstructionType, p, true));
1594                     }
1595                     else
1596                     {
1597                         for (const auto &beyondType : beyondTypes)
1598                         {
1599                             p.beyondType = beyondType.first;
1600                             sizeGroup->addChild(new BindVertexBuffers2Case(testCtx, beyondType.second,
1601                                                                            pipelineConstructionType, p, true));
1602                         }
1603                     }
1604                     randomGroup->addChild(sizeGroup.release());
1605                 }
1606                 countGroup->addChild(randomGroup.release());
1607             }
1608             topoGroup->addChild(countGroup.release());
1609         }
1610         robustGroup->addChild(topoGroup.release());
1611     }
1612     rootGroup->addChild(robustGroup.release());
1613 
1614     return rootGroup.release();
1615 }
1616 
1617 } // namespace pipeline
1618 } // namespace vkt
1619