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 ¶ms,
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 ¶ms,
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