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::PlatformInterface &vkp = m_context.getPlatformInterface();
236 const vk::VkInstance vki = m_context.getInstance();
237 const vk::InstanceInterface &instanceInterface = m_context.getInstanceInterface();
238 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
239 const vk::VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
240 const vk::Move<vk::VkDevice> device =
241 createDynamicVertexStateDevice(m_context, queueFamilyIndex, m_pipelineConstructionType);
242 const vk::DeviceDriver vk(vkp, vki, *device, m_context.getUsedApiVersion(),
243 m_context.getTestContext().getCommandLine());
244 vk::SimpleAllocator allocator(
245 vk, *device,
246 getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
247 const vk::VkQueue queue = getDeviceQueue(vk, *device, queueFamilyIndex, 0u);
248 const auto &deviceExtensions = m_context.getDeviceExtensions();
249
250 // Create shaders
251 const std::array<vk::ShaderWrapper, 2> vertexShaderModules = {
252 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_0")),
253 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_1"))};
254
255 const vk::ShaderWrapper fragmentShaderModule =
256 vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("frag"));
257
258 const uint32_t vertexBufferBindIndex = 0u;
259
260 // Vertex input state and binding
261 const vk::VkVertexInputBindingDescription2EXT bindingDescription2EXT = makeVertexInputBindingDescription2EXT(
262 vertexBufferBindIndex, sizeof(VertexInfo), vk::VK_VERTEX_INPUT_RATE_VERTEX);
263
264 const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXTGreens{
265 makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
266 makeVertexInputAttributeDescription2EXT(m_attributeLocations[0], vertexBufferBindIndex,
267 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
268
269 const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXT2Reds{
270 makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
271 makeVertexInputAttributeDescription2EXT(m_attributeLocations[1], vertexBufferBindIndex,
272 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
273
274 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
275 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
276 DE_NULL, // const void* pNext;
277 (vk::VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags;
278 0u, // uint32_t vertexBindingDescriptionCount;
279 DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
280 0u, // uint32_t vertexAttributeDescriptionCount;
281 DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
282 };
283
284 vk::Move<vk::VkImage> colorImage =
285 (makeImage(vk, *device,
286 makeImageCreateInfo(tcu::IVec2(32, 32), vk::VK_FORMAT_R8G8B8A8_UNORM,
287 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
288
289 // Allocate and bind color image memory
290 const vk::VkImageSubresourceRange colorSubresourceRange =
291 vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
292 const de::UniquePtr<vk::Allocation> colorImageAlloc(
293 bindImage(vk, *device, allocator, *colorImage, vk::MemoryRequirement::Any));
294 vk::Move<vk::VkImageView> colorImageView = (makeImageView(vk, *device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D,
295 vk::VK_FORMAT_R8G8B8A8_UNORM, colorSubresourceRange));
296
297 // Create renderpass
298 const vk::VkAttachmentDescription attachmentDescription = {
299 (vk::VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags
300 vk::VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
301 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
302 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
303 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
304 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
305 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
306 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
307 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
308 };
309
310 const vk::VkAttachmentReference attachmentReference = {
311 0u, // uint32_t attachment
312 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
313 };
314
315 const vk::VkSubpassDescription subpassDescription = {
316 (vk::VkSubpassDescriptionFlags)0u, // VkSubpassDescriptionFlags flags
317 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
318 0u, // uint32_t inputAttachmentCount
319 DE_NULL, // const VkAttachmentReference* pInputAttachments
320 1u, // uint32_t colorAttachmentCount
321 &attachmentReference, // const VkAttachmentReference* pColorAttachments
322 DE_NULL, // const VkAttachmentReference* pResolveAttachments
323 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
324 0u, // uint32_t preserveAttachmentCount
325 DE_NULL // const uint32_t* pPreserveAttachments
326 };
327
328 const vk::VkRenderPassCreateInfo renderPassInfo = {
329 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei sType
330 DE_NULL, // const void* pNext
331 (vk::VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags
332 1u, // uint32_t attachmentCount
333 &attachmentDescription, // const VkAttachmentDescription* pAttachments
334 1u, // uint32_t subpassCount
335 &subpassDescription, // const VkSubpassDescription* pSubpasses
336 0u, // uint32_t dependencyCount
337 DE_NULL // const VkSubpassDependency* pDependencies
338 };
339
340 vk::RenderPassWrapper renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, vk, *device, &renderPassInfo);
341
342 // Create framebuffer
343 const vk::VkImageView attachmentBindInfos[] = {*colorImageView};
344
345 const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
346 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
347 DE_NULL, // const void* pNext;
348 vk::VkFramebufferCreateFlags(0), // VkFramebufferCreateFlags flags;
349 *renderPass, // VkRenderPass renderPass;
350 1u, // uint32_t attachmentCount;
351 attachmentBindInfos, // const VkImageView* pAttachments;
352 32u, // uint32_t width;
353 32u, // uint32_t height;
354 1u // uint32_t layers;
355 };
356
357 renderPass.createFramebuffer(vk, *device, &framebufferCreateInfo, {*colorImage});
358
359 std::array<vk::VkDynamicState, 1> dynamicStates{
360 vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT,
361 };
362
363 vk::VkPipelineDynamicStateCreateInfo pipelineDynamicStateNfo{
364 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
365 DE_NULL, // const void* pNext;
366 (vk::VkPipelineDynamicStateCreateFlags)0u, // VkPipelineDynamicStateCreateFlags flags;
367 static_cast<uint32_t>(dynamicStates.size()), // uint32_t dynamicStateCount;
368 dynamicStates.data() // const VkDynamicState* pDynamicStates;
369 };
370
371 // Create pipeline layout
372 const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
373 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
374 DE_NULL, // const void* pNext;
375 0u, // VkPipelineLayoutCreateFlags flags;
376 0u, // uint32_t descriptorSetCount;
377 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
378 0u, // uint32_t pushConstantRangeCount;
379 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
380 };
381
382 vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, *device, &pipelineLayoutInfo);
383
384 // Create graphics pipeline
385 vk::GraphicsPipelineWrapper graphicsPipelines[2]{
386 {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType},
387 {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType}};
388
389 const vk::VkExtent2D extent = {32, 32};
390 const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(extent));
391 const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(extent));
392
393 for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
394 {
395 graphicsPipelines[i]
396 .setDefaultDepthStencilState()
397 .setDefaultColorBlendState()
398 .setMonolithicPipelineLayout(pipelineLayout)
399 .setDynamicState(&pipelineDynamicStateNfo)
400 .setDefaultMultisampleState()
401 .setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
402 .setDefaultRasterizationState()
403 .setupVertexInputState(&vertexInputStateCreateInfo)
404 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u,
405 vertexShaderModules[i])
406 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentShaderModule, DE_NULL, DE_NULL)
407 .setupFragmentOutputState(*renderPass)
408 .setMonolithicPipelineLayout(pipelineLayout)
409 .buildPipeline();
410 }
411
412 // Create vertex buffer
413 const uint32_t numVertices = 6;
414 const vk::VkDeviceSize vertexBufferSizeBytes = 256;
415
416 const std::array<vk::Move<vk::VkBuffer>, 2> vertexBuffers = {
417 (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)),
418 (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))};
419
420 const std::array<de::MovePtr<vk::Allocation>, 2> vertexBufferAllocs = {
421 (bindBuffer(vk, *device, allocator, *vertexBuffers[0], vk::MemoryRequirement::HostVisible)),
422 (bindBuffer(vk, *device, allocator, *vertexBuffers[1], vk::MemoryRequirement::HostVisible))};
423
424 const uint32_t instanceSize = (uint32_t)sqrt(m_numInstances);
425 const float posIncrement = 1.0f / (float)m_numInstances * (float)instanceSize;
426
427 for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
428 {
429 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));
430 VertexInfo *const pVertices = static_cast<VertexInfo *>(vertexBufferAllocs[i]->getHostPtr());
431
432 pVertices[0] = {tcu::Vec4(posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
433 pVertices[1] = {tcu::Vec4(-posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
434 pVertices[2] = {tcu::Vec4(-posIncrement, posIncrement, 0.0f, 1.0f), vertexColor};
435 pVertices[3] = {tcu::Vec4(-posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
436 pVertices[4] = {tcu::Vec4(posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
437 pVertices[5] = {tcu::Vec4(posIncrement, -posIncrement, 1.0f, 1.0f), vertexColor};
438
439 flushAlloc(vk, *device, *vertexBufferAllocs[i]);
440 }
441
442 // Command buffer
443 const vk::Unique<vk::VkCommandPool> cmdPool(
444 createCommandPool(vk, *device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
445 const vk::Unique<vk::VkCommandBuffer> cmdBuffer(
446 allocateCommandBuffer(vk, *device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
447
448 const vk::VkDeviceSize vertexBufferOffset = 0u;
449
450 // Render result buffer
451 const vk::VkDeviceSize colorBufferSizeBytes =
452 static_cast<vk::VkDeviceSize>(tcu::getPixelSize(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)) * 32 * 32);
453 const vk::Unique<vk::VkBuffer> colorBuffer(
454 makeBuffer(vk, *device, colorBufferSizeBytes, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
455 const de::UniquePtr<vk::Allocation> colorBufferAlloc(
456 bindBuffer(vk, *device, allocator, *colorBuffer, vk::MemoryRequirement::HostVisible));
457
458 const vk::VkClearValue clearColorValue = defaultClearValue(vk::VK_FORMAT_R8G8B8A8_UNORM);
459
460 beginCommandBuffer(vk, *cmdBuffer);
461
462 renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, 32u, 32u), clearColorValue);
463
464 graphicsPipelines[0].bind(*cmdBuffer);
465 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[0].get(), &vertexBufferOffset);
466 vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
467 static_cast<uint32_t>(vertexInputAttributeDesc2EXTGreens.size()),
468 vertexInputAttributeDesc2EXTGreens.data());
469 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
470
471 graphicsPipelines[1].bind(*cmdBuffer);
472 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[1].get(), &vertexBufferOffset);
473 vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
474 static_cast<uint32_t>(vertexInputAttributeDesc2EXT2Reds.size()),
475 vertexInputAttributeDesc2EXT2Reds.data());
476 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
477
478 renderPass.end(vk, *cmdBuffer);
479 copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, tcu::IVec2(32, 32),
480 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
481
482 endCommandBuffer(vk, *cmdBuffer);
483
484 submitCommandsAndWait(vk, *device, queue, *cmdBuffer);
485
486 // Check result image
487 {
488 tcu::TextureLevel referenceTexture(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM), 32, 32);
489 const tcu::PixelBufferAccess referenceAccess = referenceTexture.getAccess();
490 const int segmentSize = static_cast<int32_t>(32u / instanceSize);
491 const int segmentLoc = (32 - segmentSize) / 2;
492
493 tcu::clear(referenceTexture.getAccess(), clearColorValue.color.float32);
494
495 // Create reference image
496 for (int y = 0; y < segmentSize; ++y)
497 {
498 for (int x = 0; x < segmentSize; ++x)
499 {
500 // While running test for all offsets, we create a nice gradient-like color for the pixels.
501 referenceAccess.setPixel(tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), segmentLoc + x, segmentLoc + y);
502 }
503 }
504
505 invalidateAlloc(vk, *device, *colorBufferAlloc);
506
507 const tcu::ConstPixelBufferAccess resultPixelAccess(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM),
508 (int)extent.width, (int)extent.height, 1,
509 colorBufferAlloc->getHostPtr());
510
511 if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceAccess, resultPixelAccess,
512 tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT))
513 return tcu::TestStatus::fail("Rendered image is not correct");
514 }
515
516 return tcu::TestStatus::pass("Success");
517 }
518
519 class NonSequentialCase : public vkt::TestCase
520 {
521 public:
NonSequentialCase(tcu::TestContext & testContext,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)522 NonSequentialCase(tcu::TestContext &testContext, const std::string &name,
523 const vk::PipelineConstructionType pipelineConstructionType, const uint32_t numInstances,
524 const std::vector<uint32_t> attributeLocations)
525 : vkt::TestCase(testContext, name)
526 , m_pipelineConstructionType(pipelineConstructionType)
527 , m_numInstances(numInstances)
528 , m_attributeLocations(attributeLocations)
529 {
530 }
531
~NonSequentialCase(void)532 ~NonSequentialCase(void)
533 {
534 }
535
536 virtual void checkSupport(Context &context) const override;
537 virtual void initPrograms(vk::SourceCollections &sourceCollections) const override;
538 virtual TestInstance *createInstance(Context &context) const override;
539
540 private:
541 const vk::PipelineConstructionType m_pipelineConstructionType;
542 const uint32_t m_numInstances;
543 const std::vector<uint32_t> m_attributeLocations;
544 };
545
checkSupport(Context & context) const546 void NonSequentialCase::checkSupport(Context &context) const
547 {
548 const vk::InstanceInterface &vki = context.getInstanceInterface();
549 const vk::VkPhysicalDevice physDevice = context.getPhysicalDevice();
550
551 std::array<std::string, 3> extensions = {"VK_EXT_extended_dynamic_state", "VK_EXT_vertex_input_dynamic_state",
552 "VK_EXT_extended_dynamic_state2"};
553
554 // Check extension support.
555 for (const auto &extension : extensions)
556 context.requireDeviceFunctionality(extension);
557
558 vk::checkPipelineConstructionRequirements(vki, physDevice, m_pipelineConstructionType);
559 }
560
initPrograms(vk::SourceCollections & sourceCollections) const561 void NonSequentialCase::initPrograms(vk::SourceCollections &sourceCollections) const
562 {
563 // Vertex
564 {
565 for (size_t i = 0; i < m_attributeLocations.size(); ++i)
566 {
567 std::ostringstream src;
568
569 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
570 << "\n"
571 << "layout(location = 0) in vec4 inPosition;\n"
572 << "layout(location = " << m_attributeLocations[i] << ") in vec4 inColor;\n"
573 << "layout(location = 0) out vec4 outColor;\n"
574 << "\n"
575 << "void main (void)\n"
576 << "{\n"
577 << " gl_Position = inPosition;\n"
578 << " outColor = inColor;\n"
579 << "}\n";
580
581 sourceCollections.glslSources.add("vert_" + std::to_string(i)) << glu::VertexSource(src.str());
582 }
583 }
584
585 // Fragment
586 {
587 std::ostringstream src;
588
589 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
590 << "\n"
591 << "layout(location = 0) in vec4 inColor;\n"
592 << "layout(location = 0) out vec4 outColor;\n"
593 << "\n"
594 << "void main (void)\n"
595 << "{\n"
596 << " outColor = inColor;\n"
597 << "}\n";
598
599 sourceCollections.glslSources.add("frag") << glu::FragmentSource(src.str());
600 }
601 }
602
createInstance(Context & context) const603 TestInstance *NonSequentialCase::createInstance(Context &context) const
604 {
605 return new NonSequentialInstance(context, m_pipelineConstructionType, m_numInstances, m_attributeLocations);
606 }
607
608 } // namespace
609
createDynamicVertexAttributeTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)610 tcu::TestCaseGroup *createDynamicVertexAttributeTests(tcu::TestContext &testCtx,
611 vk::PipelineConstructionType pipelineConstructionType)
612 {
613 de::MovePtr<tcu::TestCaseGroup> nonSequentialTestsGroup(
614 new tcu::TestCaseGroup(testCtx, "dynamic_vertex_attribute"));
615
616 nonSequentialTestsGroup->addChild(
617 new NonSequentialCase(testCtx, "nonsequential", pipelineConstructionType, 16u, {1u, 7u}));
618
619 return nonSequentialTestsGroup.release();
620 }
621
622 } // namespace pipeline
623 } // namespace vkt
624