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