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