1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 * Copyright (c) 2023 Google Inc.
7 * Copyright (c) 2023 LunarG, Inc.
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 Dynamic vertex attribute tests
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktPipelineDynamicVertexAttributeTests.hpp"
27 #include "vktPipelineClearUtil.hpp"
28 #include "vktPipelineExtendedDynamicStateTests.hpp"
29
30 #include "vktCustomInstancesDevices.hpp"
31 #include "vktTestCase.hpp"
32
33 #include "vkImageUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38
39 #include "tcuCommandLine.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuTextureUtil.hpp"
43
44 #include <array>
45 #include <set>
46
47 namespace vkt
48 {
49 namespace pipeline
50 {
51
52 namespace
53 {
54
makeVertexInputAttributeDescription2EXT(uint32_t location,uint32_t binding,vk::VkFormat format,uint32_t offset)55 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT(uint32_t location, uint32_t binding,
56 vk::VkFormat format, uint32_t offset)
57 {
58 vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
59
60 desc.location = location;
61 desc.binding = binding;
62 desc.format = format;
63 desc.offset = offset;
64
65 return desc;
66 }
67
makeVertexInputBindingDescription2EXT(uint32_t binding,uint32_t stride,vk::VkVertexInputRate inputRate)68 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT(uint32_t binding, uint32_t stride,
69 vk::VkVertexInputRate inputRate)
70 {
71 vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
72
73 desc.binding = binding;
74 desc.stride = stride;
75 desc.inputRate = inputRate;
76 desc.divisor = 1u;
77
78 return desc;
79 }
80
makeImageCreateInfo(const tcu::IVec2 & size,const vk::VkFormat format,const vk::VkImageUsageFlags usage)81 vk::VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const vk::VkFormat format,
82 const vk::VkImageUsageFlags usage)
83 {
84 const vk::VkImageCreateInfo imageParams = {
85 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
86 DE_NULL, // const void* pNext;
87 (vk::VkImageCreateFlags)0u, // VkImageCreateFlags flags;
88 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
89 format, // VkFormat format;
90 vk::makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
91 1u, // uint32_t mipLevels;
92 1u, // uint32_t arrayLayers;
93 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
94 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
95 usage, // VkImageUsageFlags usage;
96 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
97 0u, // uint32_t queueFamilyIndexCount;
98 DE_NULL, // const uint32_t* pQueueFamilyIndices;
99 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
100 };
101
102 return imageParams;
103 }
104
removeExtensions(const std::vector<std::string> & a,const std::vector<const char * > & b)105 static std::vector<std::string> removeExtensions(const std::vector<std::string> &a, const std::vector<const char *> &b)
106 {
107 std::vector<std::string> res;
108 std::set<std::string> removeExts(b.begin(), b.end());
109
110 for (std::vector<std::string>::const_iterator aIter = a.begin(); aIter != a.end(); ++aIter)
111 {
112 if (!de::contains(removeExts, *aIter))
113 res.push_back(*aIter);
114 }
115
116 return res;
117 }
118
createDynamicVertexStateDevice(Context & context,const uint32_t testQueueFamilyIndex,const vk::PipelineConstructionType pipelineConstructionType)119 vk::Move<vk::VkDevice> createDynamicVertexStateDevice(Context &context, const uint32_t testQueueFamilyIndex,
120 const vk::PipelineConstructionType pipelineConstructionType)
121 {
122 DE_UNREF(pipelineConstructionType);
123
124 void *pNext = DE_NULL;
125
126 #ifndef CTS_USES_VULKANSC
127 vk::VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT graphicsPipelineFeatures{
128 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, // VkStructureType sType;
129 pNext, // void* pNext;
130 VK_TRUE, // VkBool32 graphicsPipelineLibrary;
131 };
132
133 if (vk::isConstructionTypeLibrary(pipelineConstructionType))
134 pNext = &graphicsPipelineFeatures;
135 vk::VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeatures{
136 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, // VkStructureType sType;
137 pNext, // void* pNext;
138 VK_TRUE, // VkBool32 dynamicRendering;
139 };
140 vk::VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures{
141 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, // VkStructureType sType;
142 &dynamicRenderingFeatures, // void* pNext;
143 VK_TRUE, // VkBool32 shaderObject;
144 };
145
146 if (vk::isConstructionTypeShaderObject(pipelineConstructionType))
147 pNext = &shaderObjectFeatures;
148 #endif
149
150 vk::VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT dynamicVertexState{
151 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT, // VkStructureType sType;
152 pNext, // void* pNext;
153 VK_TRUE, // VkBool32 vertexInputDynamicState;
154 };
155
156 vk::VkPhysicalDeviceFeatures2 physDeviceFeats2 = context.getDeviceFeatures2();
157
158 physDeviceFeats2.features = context.getDeviceFeatures();
159 physDeviceFeats2.pNext = &dynamicVertexState;
160
161 const float queuePriority = 1.0f;
162
163 const vk::VkDeviceQueueCreateInfo queueParams = {
164 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
165 DE_NULL, // const void* pNext;
166 0u, // VkDeviceQueueCreateFlags flags;
167 testQueueFamilyIndex, // uint32_t queueFamilyIndex;
168 1u, // uint32_t queueCount;
169 &queuePriority // const float* pQueuePriorities;
170 };
171
172 std::vector<const char *> extensionPtrs;
173 std::vector<const char *> coreExtensions;
174
175 vk::getCoreDeviceExtensions(context.getUsedApiVersion(), coreExtensions);
176
177 std::vector<std::string> nonCoreExtensions(removeExtensions(context.getDeviceExtensions(), coreExtensions));
178
179 extensionPtrs.resize(nonCoreExtensions.size());
180
181 for (size_t ndx = 0; ndx < nonCoreExtensions.size(); ++ndx)
182 extensionPtrs[ndx] = nonCoreExtensions[ndx].c_str();
183
184 const vk::VkDeviceCreateInfo deviceInfo = {
185 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
186 &physDeviceFeats2, // const void* pNext;
187 0u, // VkDeviceCreateFlags flags;
188 1u, // uint32_t queueCreateInfoCount;
189 &queueParams, // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
190 0u, // uint32_t enabledLayerCount;
191 DE_NULL, // const char* const* ppEnabledLayerNames;
192 (uint32_t)extensionPtrs.size(), // uint32_t enabledExtensionCount;
193 extensionPtrs.data(), // const char* const* ppEnabledExtensionNames;
194 NULL // const VkPhysicalDeviceFeatures* pEnabledFeatures;
195 };
196
197 return createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
198 context.getPlatformInterface(), context.getInstance(), context.getInstanceInterface(),
199 context.getPhysicalDevice(), &deviceInfo);
200 }
201
202 class NonSequentialInstance : public TestInstance
203 {
204 public:
NonSequentialInstance(Context & context,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)205 NonSequentialInstance(Context &context, const vk::PipelineConstructionType pipelineConstructionType,
206 const uint32_t numInstances, const std::vector<uint32_t> attributeLocations)
207 : TestInstance(context)
208 , m_pipelineConstructionType(pipelineConstructionType)
209 , m_numInstances(numInstances)
210 , m_attributeLocations(attributeLocations)
211 {
212 }
213
~NonSequentialInstance()214 ~NonSequentialInstance()
215 {
216 }
217
218 virtual tcu::TestStatus iterate(void);
219
220 private:
221 struct VertexInfo
222 {
223 tcu::Vec4 position;
224 tcu::Vec4 color;
225 };
226
227 const vk::PipelineConstructionType m_pipelineConstructionType;
228 const uint32_t m_numInstances;
229 const std::vector<uint32_t> m_attributeLocations;
230 };
231
iterate(void)232 tcu::TestStatus NonSequentialInstance::iterate(void)
233 {
234 tcu::TestLog &log = m_context.getTestContext().getLog();
235 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
236 const vk::PlatformInterface &vkp = m_context.getPlatformInterface();
237 const vk::VkInstance vki = m_context.getInstance();
238 const vk::InstanceInterface &instanceInterface = m_context.getInstanceInterface();
239 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
240 const vk::VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
241 const vk::Move<vk::VkDevice> device =
242 createDynamicVertexStateDevice(m_context, queueFamilyIndex, m_pipelineConstructionType);
243 vk::SimpleAllocator allocator(
244 vk, *device,
245 getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
246 const vk::DeviceDriver deviceDriver(vkp, vki, *device, m_context.getUsedApiVersion(),
247 m_context.getTestContext().getCommandLine());
248 const vk::VkQueue queue = getDeviceQueue(deviceDriver, *device, queueFamilyIndex, 0u);
249 const auto &deviceExtensions = m_context.getDeviceExtensions();
250
251 // Create shaders
252 const std::array<vk::ShaderWrapper, 2> vertexShaderModules = {
253 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_0")),
254 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_1"))};
255
256 const vk::ShaderWrapper fragmentShaderModule =
257 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("frag"));
258
259 const uint32_t vertexBufferBindIndex = 0u;
260
261 // Vertex input state and binding
262 const vk::VkVertexInputBindingDescription2EXT bindingDescription2EXT = makeVertexInputBindingDescription2EXT(
263 vertexBufferBindIndex, sizeof(VertexInfo), vk::VK_VERTEX_INPUT_RATE_VERTEX);
264
265 const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXTGreens{
266 makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
267 makeVertexInputAttributeDescription2EXT(m_attributeLocations[0], vertexBufferBindIndex,
268 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
269
270 const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXT2Reds{
271 makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
272 makeVertexInputAttributeDescription2EXT(m_attributeLocations[1], vertexBufferBindIndex,
273 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
274
275 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
276 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
277 DE_NULL, // const void* pNext;
278 (vk::VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags;
279 0u, // uint32_t vertexBindingDescriptionCount;
280 DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
281 0u, // uint32_t vertexAttributeDescriptionCount;
282 DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
283 };
284
285 vk::Move<vk::VkImage> colorImage =
286 (makeImage(vk, *device,
287 makeImageCreateInfo(tcu::IVec2(32, 32), vk::VK_FORMAT_R8G8B8A8_UNORM,
288 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
289
290 // Allocate and bind color image memory
291 const vk::VkImageSubresourceRange colorSubresourceRange =
292 vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
293 const de::UniquePtr<vk::Allocation> colorImageAlloc(
294 bindImage(vk, *device, allocator, *colorImage, vk::MemoryRequirement::Any));
295 vk::Move<vk::VkImageView> colorImageView = (makeImageView(vk, *device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D,
296 vk::VK_FORMAT_R8G8B8A8_UNORM, colorSubresourceRange));
297
298 // Create renderpass
299 const vk::VkAttachmentDescription attachmentDescription = {
300 (vk::VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags
301 vk::VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
302 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
303 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
304 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
305 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
306 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
307 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
308 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
309 };
310
311 const vk::VkAttachmentReference attachmentReference = {
312 0u, // uint32_t attachment
313 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
314 };
315
316 const vk::VkSubpassDescription subpassDescription = {
317 (vk::VkSubpassDescriptionFlags)0u, // VkSubpassDescriptionFlags flags
318 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
319 0u, // uint32_t inputAttachmentCount
320 DE_NULL, // const VkAttachmentReference* pInputAttachments
321 1u, // uint32_t colorAttachmentCount
322 &attachmentReference, // const VkAttachmentReference* pColorAttachments
323 DE_NULL, // const VkAttachmentReference* pResolveAttachments
324 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
325 0u, // uint32_t preserveAttachmentCount
326 DE_NULL // const uint32_t* pPreserveAttachments
327 };
328
329 const vk::VkRenderPassCreateInfo renderPassInfo = {
330 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei sType
331 DE_NULL, // const void* pNext
332 (vk::VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags
333 1u, // uint32_t attachmentCount
334 &attachmentDescription, // const VkAttachmentDescription* pAttachments
335 1u, // uint32_t subpassCount
336 &subpassDescription, // const VkSubpassDescription* pSubpasses
337 0u, // uint32_t dependencyCount
338 DE_NULL // const VkSubpassDependency* pDependencies
339 };
340
341 vk::RenderPassWrapper renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, vk, *device, &renderPassInfo);
342
343 // Create framebuffer
344 const vk::VkImageView attachmentBindInfos[] = {*colorImageView};
345
346 const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
347 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
348 DE_NULL, // const void* pNext;
349 vk::VkFramebufferCreateFlags(0), // VkFramebufferCreateFlags flags;
350 *renderPass, // VkRenderPass renderPass;
351 1u, // uint32_t attachmentCount;
352 attachmentBindInfos, // const VkImageView* pAttachments;
353 32u, // uint32_t width;
354 32u, // uint32_t height;
355 1u // uint32_t layers;
356 };
357
358 renderPass.createFramebuffer(vk, *device, &framebufferCreateInfo, {*colorImage});
359
360 std::array<vk::VkDynamicState, 1> dynamicStates{
361 vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT,
362 };
363
364 vk::VkPipelineDynamicStateCreateInfo pipelineDynamicStateNfo{
365 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
366 DE_NULL, // const void* pNext;
367 (vk::VkPipelineDynamicStateCreateFlags)0u, // VkPipelineDynamicStateCreateFlags flags;
368 static_cast<uint32_t>(dynamicStates.size()), // uint32_t dynamicStateCount;
369 dynamicStates.data() // const VkDynamicState* pDynamicStates;
370 };
371
372 // Create pipeline layout
373 const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
374 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
375 DE_NULL, // const void* pNext;
376 0u, // VkPipelineLayoutCreateFlags flags;
377 0u, // uint32_t descriptorSetCount;
378 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
379 0u, // uint32_t pushConstantRangeCount;
380 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
381 };
382
383 vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, *device, &pipelineLayoutInfo);
384
385 // Create graphics pipeline
386 vk::GraphicsPipelineWrapper graphicsPipelines[2]{
387 {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType},
388 {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType}};
389
390 const vk::VkExtent2D extent = {32, 32};
391 const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(extent));
392 const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(extent));
393
394 for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
395 {
396 graphicsPipelines[i]
397 .setDefaultDepthStencilState()
398 .setDefaultColorBlendState()
399 .setMonolithicPipelineLayout(pipelineLayout)
400 .setDynamicState(&pipelineDynamicStateNfo)
401 .setDefaultMultisampleState()
402 .setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
403 .setDefaultRasterizationState()
404 .setupVertexInputState(&vertexInputStateCreateInfo)
405 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u,
406 vertexShaderModules[i])
407 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentShaderModule, DE_NULL, DE_NULL)
408 .setupFragmentOutputState(*renderPass)
409 .setMonolithicPipelineLayout(pipelineLayout)
410 .buildPipeline();
411 }
412
413 // Create vertex buffer
414 const uint32_t numVertices = 6;
415 const vk::VkDeviceSize vertexBufferSizeBytes = 256;
416
417 const std::array<vk::Move<vk::VkBuffer>, 2> vertexBuffers = {
418 (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)),
419 (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))};
420
421 const std::array<de::MovePtr<vk::Allocation>, 2> vertexBufferAllocs = {
422 (bindBuffer(vk, *device, allocator, *vertexBuffers[0], vk::MemoryRequirement::HostVisible)),
423 (bindBuffer(vk, *device, allocator, *vertexBuffers[1], vk::MemoryRequirement::HostVisible))};
424
425 const uint32_t instanceSize = (uint32_t)sqrt(m_numInstances);
426 const float posIncrement = 1.0f / (float)m_numInstances * (float)instanceSize;
427
428 for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
429 {
430 tcu::Vec4 vertexColor = (i == 0u ? tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f) : tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f));
431 VertexInfo *const pVertices = static_cast<VertexInfo *>(vertexBufferAllocs[i]->getHostPtr());
432
433 pVertices[0] = {tcu::Vec4(posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
434 pVertices[1] = {tcu::Vec4(-posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
435 pVertices[2] = {tcu::Vec4(-posIncrement, posIncrement, 0.0f, 1.0f), vertexColor};
436 pVertices[3] = {tcu::Vec4(-posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
437 pVertices[4] = {tcu::Vec4(posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
438 pVertices[5] = {tcu::Vec4(posIncrement, -posIncrement, 1.0f, 1.0f), vertexColor};
439
440 flushAlloc(vk, *device, *vertexBufferAllocs[i]);
441 }
442
443 // Command buffer
444 const vk::Unique<vk::VkCommandPool> cmdPool(
445 createCommandPool(vk, *device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
446 const vk::Unique<vk::VkCommandBuffer> cmdBuffer(
447 allocateCommandBuffer(vk, *device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
448
449 const vk::VkDeviceSize vertexBufferOffset = 0u;
450
451 // Render result buffer
452 const vk::VkDeviceSize colorBufferSizeBytes =
453 static_cast<vk::VkDeviceSize>(tcu::getPixelSize(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)) * 32 * 32);
454 const vk::Unique<vk::VkBuffer> colorBuffer(
455 makeBuffer(vk, *device, colorBufferSizeBytes, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
456 const de::UniquePtr<vk::Allocation> colorBufferAlloc(
457 bindBuffer(vk, *device, allocator, *colorBuffer, vk::MemoryRequirement::HostVisible));
458
459 const vk::VkClearValue clearColorValue = defaultClearValue(vk::VK_FORMAT_R8G8B8A8_UNORM);
460
461 beginCommandBuffer(vk, *cmdBuffer);
462
463 renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, 32u, 32u), clearColorValue);
464
465 graphicsPipelines[0].bind(*cmdBuffer);
466 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[0].get(), &vertexBufferOffset);
467 vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
468 static_cast<uint32_t>(vertexInputAttributeDesc2EXTGreens.size()),
469 vertexInputAttributeDesc2EXTGreens.data());
470 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
471
472 graphicsPipelines[1].bind(*cmdBuffer);
473 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[1].get(), &vertexBufferOffset);
474 vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
475 static_cast<uint32_t>(vertexInputAttributeDesc2EXT2Reds.size()),
476 vertexInputAttributeDesc2EXT2Reds.data());
477 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
478
479 renderPass.end(vk, *cmdBuffer);
480 copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, tcu::IVec2(32, 32),
481 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
482
483 endCommandBuffer(vk, *cmdBuffer);
484
485 submitCommandsAndWait(vk, *device, queue, *cmdBuffer);
486
487 // Check result image
488 {
489 tcu::TextureLevel referenceTexture(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM), 32, 32);
490 const tcu::PixelBufferAccess referenceAccess = referenceTexture.getAccess();
491 const int segmentSize = static_cast<int32_t>(32u / instanceSize);
492 const int segmentLoc = (32 - segmentSize) / 2;
493
494 tcu::clear(referenceTexture.getAccess(), clearColorValue.color.float32);
495
496 // Create reference image
497 for (int y = 0; y < segmentSize; ++y)
498 {
499 for (int x = 0; x < segmentSize; ++x)
500 {
501 // While running test for all offsets, we create a nice gradient-like color for the pixels.
502 referenceAccess.setPixel(tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), segmentLoc + x, segmentLoc + y);
503 }
504 }
505
506 invalidateAlloc(vk, *device, *colorBufferAlloc);
507
508 const tcu::ConstPixelBufferAccess resultPixelAccess(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM),
509 (int)extent.width, (int)extent.height, 1,
510 colorBufferAlloc->getHostPtr());
511
512 if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceAccess, resultPixelAccess,
513 tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT))
514 return tcu::TestStatus::fail("Rendered image is not correct");
515 }
516
517 return tcu::TestStatus::pass("Success");
518 }
519
520 class NonSequentialCase : public vkt::TestCase
521 {
522 public:
NonSequentialCase(tcu::TestContext & testContext,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)523 NonSequentialCase(tcu::TestContext &testContext, const std::string &name,
524 const vk::PipelineConstructionType pipelineConstructionType, const uint32_t numInstances,
525 const std::vector<uint32_t> attributeLocations)
526 : vkt::TestCase(testContext, name)
527 , m_pipelineConstructionType(pipelineConstructionType)
528 , m_numInstances(numInstances)
529 , m_attributeLocations(attributeLocations)
530 {
531 }
532
~NonSequentialCase(void)533 ~NonSequentialCase(void)
534 {
535 }
536
537 virtual void checkSupport(Context &context) const override;
538 virtual void initPrograms(vk::SourceCollections &sourceCollections) const override;
539 virtual TestInstance *createInstance(Context &context) const override;
540
541 private:
542 const vk::PipelineConstructionType m_pipelineConstructionType;
543 const uint32_t m_numInstances;
544 const std::vector<uint32_t> m_attributeLocations;
545 };
546
checkSupport(Context & context) const547 void NonSequentialCase::checkSupport(Context &context) const
548 {
549 const vk::InstanceInterface &vki = context.getInstanceInterface();
550 const vk::VkPhysicalDevice physDevice = context.getPhysicalDevice();
551
552 std::array<std::string, 3> extensions = {"VK_EXT_extended_dynamic_state", "VK_EXT_vertex_input_dynamic_state",
553 "VK_EXT_extended_dynamic_state2"};
554
555 // Check extension support.
556 for (const auto &extension : extensions)
557 context.requireDeviceFunctionality(extension);
558
559 vk::checkPipelineConstructionRequirements(vki, physDevice, m_pipelineConstructionType);
560 }
561
initPrograms(vk::SourceCollections & sourceCollections) const562 void NonSequentialCase::initPrograms(vk::SourceCollections &sourceCollections) const
563 {
564 // Vertex
565 {
566 for (size_t i = 0; i < m_attributeLocations.size(); ++i)
567 {
568 std::ostringstream src;
569
570 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
571 << "\n"
572 << "layout(location = 0) in vec4 inPosition;\n"
573 << "layout(location = " << m_attributeLocations[i] << ") in vec4 inColor;\n"
574 << "layout(location = 0) out vec4 outColor;\n"
575 << "\n"
576 << "void main (void)\n"
577 << "{\n"
578 << " gl_Position = inPosition;\n"
579 << " outColor = inColor;\n"
580 << "}\n";
581
582 sourceCollections.glslSources.add("vert_" + std::to_string(i)) << glu::VertexSource(src.str());
583 }
584 }
585
586 // Fragment
587 {
588 std::ostringstream src;
589
590 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
591 << "\n"
592 << "layout(location = 0) in vec4 inColor;\n"
593 << "layout(location = 0) out vec4 outColor;\n"
594 << "\n"
595 << "void main (void)\n"
596 << "{\n"
597 << " outColor = inColor;\n"
598 << "}\n";
599
600 sourceCollections.glslSources.add("frag") << glu::FragmentSource(src.str());
601 }
602 }
603
createInstance(Context & context) const604 TestInstance *NonSequentialCase::createInstance(Context &context) const
605 {
606 return new NonSequentialInstance(context, m_pipelineConstructionType, m_numInstances, m_attributeLocations);
607 }
608
609 } // namespace
610
createDynamicVertexAttributeTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)611 tcu::TestCaseGroup *createDynamicVertexAttributeTests(tcu::TestContext &testCtx,
612 vk::PipelineConstructionType pipelineConstructionType)
613 {
614 de::MovePtr<tcu::TestCaseGroup> nonSequentialTestsGroup(
615 new tcu::TestCaseGroup(testCtx, "dynamic_vertex_attribute"));
616
617 nonSequentialTestsGroup->addChild(
618 new NonSequentialCase(testCtx, "nonsequential", pipelineConstructionType, 16u, {1u, 7u}));
619
620 return nonSequentialTestsGroup.release();
621 }
622
623 } // namespace pipeline
624 } // namespace vkt
625