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