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