1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 Google Inc.
7 * Copyright (c) 2018 ARM Limited.
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 Offset Tests
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktPipelineDynamicOffsetTests.hpp"
27 #include "vktPipelineClearUtil.hpp"
28 #include "vktPipelineImageUtil.hpp"
29 #include "vktPipelineVertexUtil.hpp"
30 #include "vktPipelineReferenceRenderer.hpp"
31 #include "vktTestCase.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkDeviceUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "tcuImageCompare.hpp"
44 #include "deMemory.h"
45 #include "deUniquePtr.hpp"
46 #include "tcuTestLog.hpp"
47 #include <vector>
48
49 namespace vkt
50 {
51 namespace pipeline
52 {
53
54 using namespace vk;
55 using namespace std;
56
57 namespace
58 {
59 typedef de::SharedPtr<Unique<VkBuffer> > VkBufferSp;
60 typedef de::SharedPtr<Allocation> AllocationSp;
61 typedef de::SharedPtr<Unique<VkCommandBuffer> > VkCommandBufferSp;
62 typedef de::SharedPtr<Unique<VkRenderPass> > VkRenderPassSp;
63 typedef de::SharedPtr<Unique<VkFramebuffer> > VkFramebufferSp;
64 typedef de::SharedPtr<Unique<VkPipeline> > VkPipelineSp;
65
66 struct TestParams
67 {
68 VkDescriptorType descriptorType;
69 deUint32 numCmdBuffers;
70 bool reverseOrder;
71 deUint32 numDescriptorSetBindings;
72 deUint32 numDynamicBindings;
73 deUint32 numNonDynamicBindings;
74 };
75
createQuads(deUint32 numQuads,float size)76 vector<Vertex4RGBA> createQuads (deUint32 numQuads, float size)
77 {
78 vector<Vertex4RGBA> vertices;
79
80 for (deUint32 quadNdx = 0; quadNdx < numQuads; quadNdx++)
81 {
82 const float xOffset = -0.5f + (float)quadNdx;
83 const tcu::Vec4 color (0.0f);
84 const Vertex4RGBA lowerLeftVertex = {tcu::Vec4(-size + xOffset, -size, 0.0f, 1.0f), color};
85 const Vertex4RGBA lowerRightVertex = {tcu::Vec4(size + xOffset, -size, 0.0f, 1.0f), color};
86 const Vertex4RGBA UpperLeftVertex = {tcu::Vec4(-size + xOffset, size, 0.0f, 1.0f), color};
87 const Vertex4RGBA UpperRightVertex = {tcu::Vec4(size + xOffset, size, 0.0f, 1.0f), color};
88
89 vertices.push_back(lowerLeftVertex);
90 vertices.push_back(lowerRightVertex);
91 vertices.push_back(UpperLeftVertex);
92 vertices.push_back(UpperLeftVertex);
93 vertices.push_back(lowerRightVertex);
94 vertices.push_back(UpperRightVertex);
95 }
96
97 return vertices;
98 }
99
100 static const tcu::Vec4 testColors[] =
101 {
102 tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f),
103 tcu::Vec4(0.0f, 0.3f, 0.0f, 1.0f),
104 tcu::Vec4(0.0f, 0.0f, 0.3f, 1.0f),
105 tcu::Vec4(0.3f, 0.3f, 0.0f, 1.0f),
106 tcu::Vec4(0.0f, 0.3f, 0.3f, 1.0f),
107 tcu::Vec4(0.3f, 0.0f, 0.3f, 1.0f)
108 };
109
110 class DynamicOffsetGraphicsTestInstance : public vkt::TestInstance
111 {
112 public:
113 DynamicOffsetGraphicsTestInstance (Context& context, const TestParams& params);
114 virtual ~DynamicOffsetGraphicsTestInstance (void);
115 void init (void);
116 virtual tcu::TestStatus iterate (void);
117 tcu::TestStatus verifyImage (void);
118
119 private:
120 const TestParams m_params;
121 const tcu::UVec2 m_renderSize;
122 const VkFormat m_colorFormat;
123 VkImageCreateInfo m_colorImageCreateInfo;
124 Move<VkImage> m_colorImage;
125 de::MovePtr<Allocation> m_colorImageAlloc;
126 Move<VkImageView> m_colorAttachmentView;
127 vector<VkRenderPassSp> m_renderPasses;
128 vector<VkFramebufferSp> m_framebuffers;
129 Move<VkShaderModule> m_vertexShaderModule;
130 Move<VkShaderModule> m_fragmentShaderModule;
131 Move<VkBuffer> m_vertexBuffer;
132 de::MovePtr<Allocation> m_vertexBufferAlloc;
133 Move<VkBuffer> m_buffer;
134 de::MovePtr<Allocation> m_bufferAlloc;
135 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
136 Move<VkDescriptorPool> m_descriptorPool;
137 Move<VkDescriptorSet> m_descriptorSet;
138 Move<VkPipelineLayout> m_pipelineLayout;
139 vector<VkPipelineSp> m_graphicsPipelines;
140 Move<VkCommandPool> m_cmdPool;
141 vector<VkCommandBufferSp> m_cmdBuffers;
142 vector<Vertex4RGBA> m_vertices;
143 };
144
DynamicOffsetGraphicsTestInstance(Context & context,const TestParams & params)145 DynamicOffsetGraphicsTestInstance::DynamicOffsetGraphicsTestInstance (Context& context, const TestParams& params)
146 : vkt::TestInstance (context)
147 , m_params (params)
148 , m_renderSize (32, 32)
149 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
150 , m_vertices (createQuads(m_params.numDescriptorSetBindings * m_params.numCmdBuffers, 0.25f))
151 {
152 }
153
init(void)154 void DynamicOffsetGraphicsTestInstance::init (void)
155 {
156 const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
157 const DeviceInterface& vk = m_context.getDeviceInterface();
158 const VkDevice vkDevice = m_context.getDevice();
159 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
160 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
161 const deUint32 numColors = DE_LENGTH_OF_ARRAY(testColors);
162 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
163 deUint32 offset = 0;
164 deUint32 quadNdx = 0;
165 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
166 const VkDeviceSize offsetAlignment = de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
167 const VkDeviceSize bufferSize = offsetAlignment * numColors;
168 const VkDeviceSize bindingOffset = bufferSize / numBindings;
169 const VkDescriptorType nonDynamicDescriptorType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
170
171 // Create color image
172 {
173
174 const VkImageCreateInfo colorImageParams =
175 {
176 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
177 DE_NULL, // const void* pNext;
178 0u, // VkImageCreateFlags flags;
179 VK_IMAGE_TYPE_2D, // VkImageType imageType;
180 m_colorFormat, // VkFormat format;
181 { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
182 1u, // deUint32 mipLevels;
183 1u, // deUint32 arrayLayers;
184 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
185 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
186 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
187 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
188 1u, // deUint32 queueFamilyIndexCount;
189 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
190 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
191 };
192
193 m_colorImageCreateInfo = colorImageParams;
194 m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
195
196 // Allocate and bind color image memory
197 m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
198 VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
199 }
200
201 // Create color attachment view
202 {
203 const VkImageViewCreateInfo colorAttachmentViewParams =
204 {
205 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
206 DE_NULL, // const void* pNext;
207 0u, // VkImageViewCreateFlags flags;
208 *m_colorImage, // VkImage image;
209 VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
210 m_colorFormat, // VkFormat format;
211 componentMappingRGBA, // VkChannelMapping channels;
212 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange;
213 };
214
215 m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
216 }
217
218 // Create render passes
219 for (deUint32 renderPassIdx = 0; renderPassIdx < 2; renderPassIdx++)
220 {
221 // The first pass clears the output image, and the second one draws on top of the first pass.
222 const VkAttachmentLoadOp loadOps[] =
223 {
224 VK_ATTACHMENT_LOAD_OP_CLEAR,
225 VK_ATTACHMENT_LOAD_OP_LOAD
226 };
227
228 const VkImageLayout initialLayouts[] =
229 {
230 VK_IMAGE_LAYOUT_UNDEFINED,
231 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
232 };
233
234 const VkAttachmentDescription attachmentDescription =
235 {
236 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
237 m_colorFormat, // VkFormat format
238 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
239 loadOps[renderPassIdx], // VkAttachmentLoadOp loadOp
240 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
241 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
242 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
243 initialLayouts[renderPassIdx], // VkImageLayout initialLayout
244 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
245 };
246
247 const VkAttachmentReference attachmentRef =
248 {
249 0u, // deUint32 attachment
250 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
251 };
252
253 const VkSubpassDescription subpassDescription =
254 {
255 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
256 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
257 0u, // deUint32 inputAttachmentCount
258 DE_NULL, // const VkAttachmentReference* pInputAttachments
259 1u, // deUint32 colorAttachmentCount
260 &attachmentRef, // const VkAttachmentReference* pColorAttachments
261 DE_NULL, // const VkAttachmentReference* pResolveAttachments
262 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
263 0u, // deUint32 preserveAttachmentCount
264 DE_NULL // const deUint32* pPreserveAttachments
265 };
266
267 const VkRenderPassCreateInfo renderPassInfo =
268 {
269 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei sType
270 DE_NULL, // const void* pNext
271 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
272 1u, // deUint32 attachmentCount
273 &attachmentDescription, // const VkAttachmentDescription* pAttachments
274 1u, // deUint32 subpassCount
275 &subpassDescription, // const VkSubpassDescription* pSubpasses
276 0u, // deUint32 dependencyCount
277 DE_NULL // const VkSubpassDependency* pDependencies
278 };
279
280 m_renderPasses.push_back(VkRenderPassSp(new Unique<VkRenderPass>(createRenderPass(vk, vkDevice, &renderPassInfo))));
281 }
282
283 // Create framebuffers
284 for (deUint32 framebufferIdx = 0; framebufferIdx < 2; framebufferIdx++)
285 {
286 const VkImageView attachmentBindInfos[] =
287 {
288 *m_colorAttachmentView
289 };
290
291 const VkFramebufferCreateInfo framebufferParams =
292 {
293 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
294 DE_NULL, // const void* pNext;
295 0u, // VkFramebufferCreateFlags flags;
296 **m_renderPasses[framebufferIdx], // VkRenderPass renderPass;
297 1u, // deUint32 attachmentCount;
298 attachmentBindInfos, // const VkImageView* pAttachments;
299 (deUint32)m_renderSize.x(), // deUint32 width;
300 (deUint32)m_renderSize.y(), // deUint32 height;
301 1u // deUint32 layers;
302 };
303
304 m_framebuffers.push_back(VkFramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vk, vkDevice, &framebufferParams))));
305 }
306
307 // Create pipeline layout
308 {
309 // Create descriptor set layout
310 vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
311
312 for (deUint32 binding = 0; binding < numBindings; binding++)
313 {
314 const VkDescriptorType descriptorType = binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
315 const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding =
316 {
317 binding, // uint32_t binding;
318 descriptorType, // VkDescriptorType descriptorType;
319 1u, // uint32_t descriptorCount;
320 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlags stageFlags;
321 DE_NULL // const VkSampler* pImmutableSamplers;
322 };
323
324 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
325 }
326
327 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
328 {
329 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
330 DE_NULL, // const void* pNext;
331 0u, // VkDescriptorSetLayoutCreateFlags flags;
332 numBindings, // uint32_t bindingCount;
333 descriptorSetLayoutBindings.data() // const VkDescriptorSetLayoutBinding* pBindings;
334 };
335
336 m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL);
337
338 // Create pipeline layout
339 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
340 {
341 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
342 DE_NULL, // const void* pNext;
343 0u, // VkPipelineLayoutCreateFlags flags;
344 1u, // deUint32 descriptorSetCount;
345 &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
346 0u, // deUint32 pushConstantRangeCount;
347 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
348 };
349
350 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
351 }
352
353 // Create buffer
354 {
355 vector<deUint8> hostBuffer((size_t)bufferSize, 0);
356 for (deUint32 colorIdx = 0; colorIdx < numColors; colorIdx++)
357 deMemcpy(&hostBuffer[(deUint32)offsetAlignment * colorIdx], &testColors[colorIdx], 16);
358
359 const VkBufferUsageFlags usageFlags = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
360
361 const VkBufferCreateInfo bufferCreateInfo =
362 {
363 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
364 DE_NULL, // const void* pNext;
365 0u, // VkBufferCreateFlags flags
366 bufferSize, // VkDeviceSize size;
367 usageFlags, // VkBufferUsageFlags usage;
368 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
369 1u, // deUint32 queueFamilyCount;
370 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
371 };
372
373 m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
374 m_bufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
375 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
376
377 deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
378 flushAlloc(vk, vkDevice, *m_bufferAlloc);
379 }
380
381 // Create descriptor pool
382 {
383 DescriptorPoolBuilder poolBuilder;
384 poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
385 poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
386 m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
387 }
388
389 // Create descriptor set
390 {
391 const VkDescriptorSetAllocateInfo allocInfo =
392 {
393 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
394 DE_NULL, // const void* pNext;
395 *m_descriptorPool, // VkDescriptorPool descriptorPool;
396 1u, // deUint32 setLayoutCount;
397 &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
398 };
399 m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
400 }
401
402 // Update descriptor set
403 for (deUint32 binding = 0; binding < numBindings; ++binding)
404 {
405 const VkDescriptorType descriptorType = binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
406 const VkDescriptorBufferInfo descriptorBufferInfo =
407 {
408 *m_buffer, // VkBuffer buffer;
409 bindingOffset * binding, // VkDeviceSize offset;
410 16u // VkDeviceSize range;
411 };
412
413 const VkWriteDescriptorSet writeDescriptorSet =
414 {
415 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
416 DE_NULL, // const void* pNext;
417 *m_descriptorSet, // VkDescriptorSet dstSet;
418 binding, // uint32_t dstBinding;
419 0u, // uint32_t dstArrayElement;
420 1u, // uint32_t descriptorCount;
421 descriptorType, // VkDescriptorType descriptorType;
422 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
423 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
424 DE_NULL // const VkBufferView* pTexelBufferView;
425 };
426
427 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
428 }
429
430 // Create shaders
431 {
432 m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0u);
433 m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0u);
434 }
435
436 // Create pipelines
437 for (deUint32 pipelineIdx = 0; pipelineIdx < 2; pipelineIdx++)
438 {
439 const VkVertexInputBindingDescription vertexInputBindingDescription =
440 {
441 0u, // deUint32 binding;
442 sizeof(Vertex4RGBA), // deUint32 strideInBytes;
443 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
444 };
445
446 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
447 {
448 {
449 0u, // deUint32 location;
450 0u, // deUint32 binding;
451 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
452 0u // deUint32 offsetInBytes;
453 },
454 {
455 1u, // deUint32 location;
456 0u, // deUint32 binding;
457 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
458 DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offset;
459 }
460 };
461
462 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
463 {
464 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
465 DE_NULL, // const void* pNext;
466 0u, // vkPipelineVertexInputStateCreateFlags flags;
467 1u, // deUint32 bindingCount;
468 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
469 2u, // deUint32 attributeCount;
470 vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
471 };
472
473 const VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
474
475 const vector<VkViewport> viewports (1, makeViewport(m_renderSize));
476 const vector<VkRect2D> scissors (1, makeRect2D(m_renderSize));
477
478 m_graphicsPipelines.push_back(VkPipelineSp(new Unique<VkPipeline>(makeGraphicsPipeline(vk, // const DeviceInterface& vk
479 vkDevice, // const VkDevice device
480 *m_pipelineLayout, // const VkPipelineLayout pipelineLayout
481 *m_vertexShaderModule, // const VkShaderModule vertexShaderModule
482 DE_NULL, // const VkShaderModule tessellationControlShaderModule
483 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
484 DE_NULL, // const VkShaderModule geometryShaderModule
485 *m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
486 **m_renderPasses[pipelineIdx], // const VkRenderPass renderPass
487 viewports, // const std::vector<VkViewport>& viewports
488 scissors, // const std::vector<VkRect2D>& scissors
489 topology, // const VkPrimitiveTopology topology
490 0u, // const deUint32 subpass
491 0u, // const deUint32 patchControlPoints
492 &vertexInputStateParams)))); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
493 }
494
495 // Create vertex buffer
496 {
497 const VkBufferCreateInfo vertexBufferParams =
498 {
499 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
500 DE_NULL, // const void* pNext;
501 0u, // VkBufferCreateFlags flags;
502 (VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()), // VkDeviceSize size;
503 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
504 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
505 1u, // deUint32 queueFamilyCount;
506 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
507 };
508
509 m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
510 m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
511
512 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
513
514 // Load vertices into vertex buffer
515 deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
516 flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
517 }
518
519 // Create command pool
520 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
521
522 // Create command buffers
523 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
524 m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
525
526 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
527 {
528 const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
529 const VkDeviceSize vertexBufferOffset = 0;
530 const deUint32 idx = m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
531
532 beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
533 beginRenderPass(vk, **m_cmdBuffers[idx], **m_renderPasses[idx], **m_framebuffers[idx], makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue);
534 vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, **m_graphicsPipelines[idx]);
535 vk.cmdBindVertexBuffers(**m_cmdBuffers[idx], 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
536
537 for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
538 {
539 vector<deUint32> offsets;
540 for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
541 offsets.push_back(offset + (deUint32)offsetAlignment * dynamicBindingIdx);
542
543 vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), m_params.numDynamicBindings, offsets.data());
544 offset += (deUint32)offsetAlignment;
545
546 // Draw quad
547 vk.cmdDraw(**m_cmdBuffers[idx], 6, 1, 6 * quadNdx, 0);
548 quadNdx++;
549 }
550
551 endRenderPass(vk, **m_cmdBuffers[idx]);
552 endCommandBuffer(vk, **m_cmdBuffers[idx]);
553 }
554 }
555
~DynamicOffsetGraphicsTestInstance(void)556 DynamicOffsetGraphicsTestInstance::~DynamicOffsetGraphicsTestInstance (void)
557 {
558 }
559
iterate(void)560 tcu::TestStatus DynamicOffsetGraphicsTestInstance::iterate (void)
561 {
562 const DeviceInterface& vk = m_context.getDeviceInterface();
563 const VkDevice vkDevice = m_context.getDevice();
564 const VkQueue queue = m_context.getUniversalQueue();
565
566 init();
567
568 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
569 submitCommandsAndWait(vk, vkDevice, queue, **m_cmdBuffers[cmdBufferIdx]);
570
571 return verifyImage();
572 }
573
verifyImage(void)574 tcu::TestStatus DynamicOffsetGraphicsTestInstance::verifyImage (void)
575 {
576 const DeviceInterface& vk = m_context.getDeviceInterface();
577 const VkDevice vkDevice = m_context.getDevice();
578 const VkQueue queue = m_context.getUniversalQueue();
579 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
580 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
581 const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
582 const tcu::TextureFormat tcuDepthFormat = tcu::TextureFormat();
583 const ColorVertexShader vertexShader;
584 const ColorFragmentShader fragmentShader (tcuColorFormat, tcuDepthFormat);
585 const rr::Program program (&vertexShader, &fragmentShader);
586 ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
587 bool compareOk = false;
588
589 // Render reference image
590 {
591 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
592 const deUint32 numTestColors = DE_LENGTH_OF_ARRAY(testColors);
593 const deUint32 bindingOffset = numTestColors / numBindings;
594
595 for (deUint32 quadIdx = 0; quadIdx < m_vertices.size() / 6; quadIdx++)
596 for (deUint32 vertexIdx = 0; vertexIdx < 6; vertexIdx++)
597 {
598 tcu::Vec4 refColor(0.0f);
599
600 for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
601 refColor += testColors[quadIdx + binding * bindingOffset + binding];
602 for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
603 refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
604 refColor.w() = 1.0f;
605
606 m_vertices[quadIdx * 6 + vertexIdx].color.xyzw() = refColor;
607 }
608
609 refRenderer.draw(rr::RenderState(refRenderer.getViewportState()), rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
610 }
611
612 // Compare result with reference image
613 {
614 de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_colorImage, m_colorFormat, m_renderSize);
615
616 compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
617 "IntImageCompare",
618 "Image comparison",
619 refRenderer.getAccess(),
620 result->getAccess(),
621 tcu::UVec4(2, 2, 2, 2),
622 tcu::IVec3(1, 1, 0),
623 true,
624 tcu::COMPARE_LOG_RESULT);
625 }
626
627 if (compareOk)
628 return tcu::TestStatus::pass("Result image matches reference");
629 else
630 return tcu::TestStatus::fail("Image mismatch");
631 }
632
633 class DynamicOffsetGraphicsTest : public vkt::TestCase
634 {
635 public:
636 DynamicOffsetGraphicsTest (tcu::TestContext& testContext,
637 const string& name,
638 const string& description,
639 const TestParams& params);
640 ~DynamicOffsetGraphicsTest (void);
641 void initPrograms (SourceCollections& sourceCollections) const;
642 TestInstance* createInstance (Context& context) const;
643
644 protected:
645 const TestParams m_params;
646 };
647
DynamicOffsetGraphicsTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)648 DynamicOffsetGraphicsTest::DynamicOffsetGraphicsTest (tcu::TestContext& testContext,
649 const string& name,
650 const string& description,
651 const TestParams& params)
652 : vkt::TestCase (testContext, name, description)
653 , m_params (params)
654 {
655 }
656
~DynamicOffsetGraphicsTest(void)657 DynamicOffsetGraphicsTest::~DynamicOffsetGraphicsTest (void)
658 {
659 }
660
createInstance(Context & context) const661 TestInstance* DynamicOffsetGraphicsTest::createInstance (Context& context) const
662 {
663 return new DynamicOffsetGraphicsTestInstance(context, m_params);
664 }
665
initPrograms(SourceCollections & sourceCollections) const666 void DynamicOffsetGraphicsTest::initPrograms (SourceCollections& sourceCollections) const
667 {
668 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
669 const string bufferType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "readonly buffer";
670 string inputBlocks;
671 string inputSum;
672
673 for (deUint32 binding = 0; binding < numBindings; binding++)
674 {
675 const string b = de::toString(binding);
676 inputBlocks +=
677 string("layout(set = 0, binding = ") + b + ") " + bufferType + " Block" + b + "\n"
678 + "{\n" + " vec4 color;\n" + "} inputData" + b + ";\n";
679 inputSum += string(" vtxColor.rgb += inputData") + b + ".color.rgb;\n";
680 }
681
682 const string vertexSrc =
683 "#version 450\n"
684 "layout(location = 0) in highp vec4 position;\n"
685 "layout(location = 1) in highp vec4 color;\n"
686 "layout(location = 0) out highp vec4 vtxColor;\n"
687 + inputBlocks +
688 "\n"
689 "out gl_PerVertex { vec4 gl_Position; };\n"
690 "\n"
691 "void main()\n"
692 "{\n"
693 " gl_Position = position;\n"
694 " vtxColor = vec4(0, 0, 0, 1);\n"
695 + inputSum +
696 "}\n";
697
698 const string fragmentSrc =
699 "#version 450\n"
700 "layout(location = 0) in highp vec4 vtxColor;\n"
701 "layout(location = 0) out highp vec4 fragColor;\n"
702 "\n"
703 "void main (void)\n"
704 "{\n"
705 " fragColor = vtxColor;\n"
706 "}\n";
707
708 sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSrc);
709 sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
710 }
711
712 class DynamicOffsetComputeTestInstance : public vkt::TestInstance
713 {
714 public:
715 DynamicOffsetComputeTestInstance (Context& context, const TestParams& params);
716 virtual ~DynamicOffsetComputeTestInstance (void);
717 void init (void);
718 virtual tcu::TestStatus iterate (void);
719 tcu::TestStatus verifyOutput (void);
720
721 private:
722 const TestParams m_params;
723 Move<VkShaderModule> m_computeShaderModule;
724 Move<VkBuffer> m_buffer;
725 de::MovePtr<Allocation> m_bufferAlloc;
726 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
727 Move<VkDescriptorPool> m_descriptorPool;
728 Move<VkDescriptorSet> m_descriptorSet;
729 Move<VkPipelineLayout> m_pipelineLayout;
730 Move<VkPipeline> m_computePipeline;
731 Move<VkBuffer> m_outputBuffer;
732 de::MovePtr<Allocation> m_outputBufferAlloc;
733 Move<VkCommandPool> m_cmdPool;
734 vector<VkCommandBufferSp> m_cmdBuffers;
735 };
736
DynamicOffsetComputeTestInstance(Context & context,const TestParams & params)737 DynamicOffsetComputeTestInstance::DynamicOffsetComputeTestInstance (Context& context, const TestParams& params)
738 : vkt::TestInstance (context)
739 , m_params (params)
740 {
741 }
742
init(void)743 void DynamicOffsetComputeTestInstance::init (void)
744 {
745 const DeviceInterface& vk = m_context.getDeviceInterface();
746 const VkDevice vkDevice = m_context.getDevice();
747 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
748 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
749 const deUint32 numColors = DE_LENGTH_OF_ARRAY(testColors);
750 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
751 deUint32 offset = 0;
752 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
753 const VkDeviceSize offsetAlignment = de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
754 const VkDeviceSize bufferSize = offsetAlignment * numColors;
755 const VkDeviceSize bindingOffset = bufferSize / numBindings;
756 const VkDescriptorType nonDynamicDescriptorType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
757 const deUint32 numOutputColors = m_params.numCmdBuffers * m_params.numDescriptorSetBindings;
758 const VkDeviceSize outputBufferSize = offsetAlignment * numOutputColors;
759
760 // Create pipeline layout
761 {
762 // Create descriptor set layout
763 vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
764
765 for (deUint32 binding = 0; binding < numBindings; binding++)
766 {
767 const VkDescriptorType descriptorType = binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
768 const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding =
769 {
770 binding, // uint32_t binding;
771 descriptorType, // VkDescriptorType descriptorType;
772 1u, // uint32_t descriptorCount;
773 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
774 DE_NULL // const VkSampler* pImmutableSamplers;
775 };
776
777 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
778 }
779
780 const VkDescriptorSetLayoutBinding descriptorSetLayoutBindingOutput =
781 {
782 numBindings, // uint32_t binding;
783 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, // VkDescriptorType descriptorType;
784 1u, // uint32_t descriptorCount;
785 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
786 DE_NULL // const VkSampler* pImmutableSamplers;
787 };
788
789 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBindingOutput);
790
791 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
792 {
793 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
794 DE_NULL, // const void* pNext;
795 0u, // VkDescriptorSetLayoutCreateFlags flags;
796 numBindings + 1, // uint32_t bindingCount;
797 descriptorSetLayoutBindings.data() // const VkDescriptorSetLayoutBinding* pBindings;
798 };
799
800 m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL);
801
802 // Create pipeline layout
803 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
804 {
805 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
806 DE_NULL, // const void* pNext;
807 0u, // VkPipelineLayoutCreateFlags flags;
808 1u, // deUint32 descriptorSetCount;
809 &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
810 0u, // deUint32 pushConstantRangeCount;
811 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
812 };
813
814 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
815 }
816
817 // Create buffer
818 {
819 vector<deUint8> hostBuffer((deUint32)bufferSize, 0);
820 for (deUint32 colorIdx = 0; colorIdx < numColors; colorIdx++)
821 deMemcpy(&hostBuffer[(deUint32)offsetAlignment * colorIdx], &testColors[colorIdx], 16);
822
823 const VkBufferUsageFlags usageFlags = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
824
825 const VkBufferCreateInfo bufferCreateInfo =
826 {
827 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
828 DE_NULL, // const void* pNext;
829 0u, // VkBufferCreateFlags flags
830 bufferSize, // VkDeviceSize size;
831 usageFlags, // VkBufferUsageFlags usage;
832 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
833 1u, // deUint32 queueFamilyCount;
834 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
835 };
836
837 m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
838 m_bufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
839 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
840
841 deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
842 flushAlloc(vk, vkDevice, *m_bufferAlloc);
843 }
844
845 // Create output buffer
846 {
847 const VkBufferCreateInfo bufferCreateInfo =
848 {
849 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
850 DE_NULL, // const void* pNext;
851 0u, // VkBufferCreateFlags flags
852 outputBufferSize, // VkDeviceSize size;
853 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage;
854 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
855 1u, // deUint32 queueFamilyCount;
856 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
857 };
858
859 m_outputBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
860 m_outputBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outputBuffer), MemoryRequirement::HostVisible);
861 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outputBuffer, m_outputBufferAlloc->getMemory(), m_outputBufferAlloc->getOffset()));
862 }
863
864 // Create descriptor pool
865 {
866 DescriptorPoolBuilder poolBuilder;
867 poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
868 poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
869 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1u);
870 m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
871 }
872
873 // Create descriptor set
874 {
875 const VkDescriptorSetAllocateInfo allocInfo =
876 {
877 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
878 DE_NULL, // const void* pNext;
879 *m_descriptorPool, // VkDescriptorPool descriptorPool;
880 1u, // deUint32 setLayoutCount;
881 &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
882 };
883 m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
884 }
885
886 // Update input buffer descriptors
887 for (deUint32 binding = 0; binding < numBindings; ++binding)
888 {
889 const VkDescriptorType descriptorType = binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
890 const VkDescriptorBufferInfo descriptorBufferInfo =
891 {
892 *m_buffer, // VkBuffer buffer;
893 bindingOffset * binding, // VkDeviceSize offset;
894 16u // VkDeviceSize range;
895 };
896
897 const VkWriteDescriptorSet writeDescriptorSet =
898 {
899 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
900 DE_NULL, // const void* pNext;
901 *m_descriptorSet, // VkDescriptorSet dstSet;
902 binding, // uint32_t dstBinding;
903 0u, // uint32_t dstArrayElement;
904 1u, // uint32_t descriptorCount;
905 descriptorType, // VkDescriptorType descriptorType;
906 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
907 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
908 DE_NULL // const VkBufferView* pTexelBufferView;
909 };
910
911 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
912 }
913
914 // Update output buffer descriptor
915 {
916 const VkDescriptorBufferInfo descriptorBufferInfo =
917 {
918 *m_outputBuffer, // VkBuffer buffer;
919 0u, // VkDeviceSize offset;
920 16u // VkDeviceSize range;
921 };
922
923 const VkWriteDescriptorSet writeDescriptorSet =
924 {
925 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
926 DE_NULL, // const void* pNext;
927 *m_descriptorSet, // VkDescriptorSet dstSet;
928 numBindings, // uint32_t dstBinding;
929 0u, // uint32_t dstArrayElement;
930 1u, // uint32_t descriptorCount;
931 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, // VkDescriptorType descriptorType;
932 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
933 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
934 DE_NULL // const VkBufferView* pTexelBufferView;
935 };
936
937 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
938 }
939
940 // Create shader
941 {
942 m_computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0u);
943 }
944
945 // Create pipeline
946 {
947 const VkPipelineShaderStageCreateInfo stageCreateInfo =
948 {
949 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
950 DE_NULL, // const void* pNext;
951 0u, // VkPipelineShaderStageCreateFlags flags;
952 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
953 *m_computeShaderModule, // VkShaderModule module;
954 "main", // const char* pName;
955 DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
956 };
957
958 const VkComputePipelineCreateInfo createInfo =
959 {
960 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
961 DE_NULL, // const void* pNext;
962 0u, // VkPipelineCreateFlags flags;
963 stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
964 *m_pipelineLayout, // VkPipelineLayout layout;
965 (VkPipeline)0, // VkPipeline basePipelineHandle;
966 0u, // int32_t basePipelineIndex;
967 };
968
969 m_computePipeline = createComputePipeline(vk, vkDevice, (vk::VkPipelineCache)0u, &createInfo);
970 }
971
972 // Create command pool
973 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
974
975 // Create command buffers
976 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
977 m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
978
979 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
980 {
981 const deUint32 idx = m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
982
983 beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
984 vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
985
986 for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
987 {
988 vector<deUint32> offsets;
989 for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
990 offsets.push_back(offset + (deUint32)offsetAlignment * dynamicBindingIdx);
991
992 // Offset for output buffer
993 offsets.push_back(offset);
994
995 vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
996 offset += (deUint32)offsetAlignment;
997
998 // Dispatch
999 vk.cmdDispatch(**m_cmdBuffers[idx], 1, 1, 1);
1000 }
1001
1002 endCommandBuffer(vk, **m_cmdBuffers[idx]);
1003 }
1004 }
1005
~DynamicOffsetComputeTestInstance(void)1006 DynamicOffsetComputeTestInstance::~DynamicOffsetComputeTestInstance (void)
1007 {
1008 }
1009
iterate(void)1010 tcu::TestStatus DynamicOffsetComputeTestInstance::iterate (void)
1011 {
1012 const DeviceInterface& vk = m_context.getDeviceInterface();
1013 const VkDevice vkDevice = m_context.getDevice();
1014 const VkQueue queue = m_context.getUniversalQueue();
1015
1016 init();
1017
1018 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
1019 submitCommandsAndWait(vk, vkDevice, queue, **m_cmdBuffers[cmdBufferIdx]);
1020
1021 return verifyOutput();
1022 }
1023
verifyOutput(void)1024 tcu::TestStatus DynamicOffsetComputeTestInstance::verifyOutput (void)
1025 {
1026 const DeviceInterface& vk = m_context.getDeviceInterface();
1027 const VkDevice vkDevice = m_context.getDevice();
1028 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
1029 const deUint32 numTestColors = DE_LENGTH_OF_ARRAY(testColors);
1030 const deUint32 bindingOffset = numTestColors / numBindings;
1031 const deUint32 numOutputColors = m_params.numCmdBuffers * m_params.numDescriptorSetBindings;
1032 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
1033 const VkDeviceSize offsetAlignment = de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
1034 vector<tcu::Vec4> refColors (numOutputColors);
1035 vector<tcu::Vec4> outColors (numOutputColors);
1036
1037 for (deUint32 i = 0; i < numOutputColors; i++)
1038 {
1039 tcu::Vec4 refColor(0.0f);
1040
1041 for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
1042 refColor += testColors[i + binding * bindingOffset + binding];
1043 for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
1044 refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
1045 refColor.w() = 1.0f;
1046
1047 refColors[i] = refColor;
1048 }
1049
1050 invalidateAlloc(vk, vkDevice, *m_outputBufferAlloc);
1051
1052 // Grab the output results using offset alignment
1053 for (deUint32 i = 0; i < numOutputColors; i++)
1054 outColors[i] = *(tcu::Vec4*)((deUint8*)m_outputBufferAlloc->getHostPtr() + offsetAlignment * i);
1055
1056 // Verify results
1057 for (deUint32 i = 0; i < numOutputColors; i++)
1058 if (outColors[i] != refColors[i])
1059 return tcu::TestStatus::fail("Output mismatch");
1060
1061 return tcu::TestStatus::pass("Output matches expected values");
1062 }
1063
1064 class DynamicOffsetComputeTest : public vkt::TestCase
1065 {
1066 public:
1067 DynamicOffsetComputeTest (tcu::TestContext& testContext,
1068 const string& name,
1069 const string& description,
1070 const TestParams& params);
1071 ~DynamicOffsetComputeTest (void);
1072 void initPrograms (SourceCollections& sourceCollections) const;
1073 TestInstance* createInstance (Context& context) const;
1074
1075 protected:
1076 const TestParams m_params;
1077 };
1078
DynamicOffsetComputeTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)1079 DynamicOffsetComputeTest::DynamicOffsetComputeTest (tcu::TestContext& testContext,
1080 const string& name,
1081 const string& description,
1082 const TestParams& params)
1083 : vkt::TestCase (testContext, name, description)
1084 , m_params (params)
1085 {
1086 }
1087
~DynamicOffsetComputeTest(void)1088 DynamicOffsetComputeTest::~DynamicOffsetComputeTest (void)
1089 {
1090 }
1091
createInstance(Context & context) const1092 TestInstance* DynamicOffsetComputeTest::createInstance (Context& context) const
1093 {
1094 return new DynamicOffsetComputeTestInstance(context, m_params);
1095 }
1096
initPrograms(SourceCollections & sourceCollections) const1097 void DynamicOffsetComputeTest::initPrograms (SourceCollections& sourceCollections) const
1098 {
1099 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
1100 const string bufferType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "buffer";
1101 string inputBlocks;
1102 string inputSum;
1103
1104 for (deUint32 binding = 0; binding < numBindings; binding++)
1105 {
1106 const string b = de::toString(binding);
1107 inputBlocks +=
1108 string("layout(set = 0, binding = ") + b + ") " + bufferType + " Block" + b + "\n"
1109 + "{\n" + " vec4 color;\n" + "} inputData" + b + ";\n";
1110 inputSum += string(" outData.color.rgb += inputData") + b + ".color.rgb;\n";
1111 }
1112
1113 const string computeSrc =
1114 "#version 450\n"
1115 + inputBlocks +
1116 "layout(set = 0, binding = " + de::toString(numBindings) + ") writeonly buffer Output\n"
1117 "{\n"
1118 " vec4 color;\n"
1119 "} outData;\n"
1120 "\n"
1121 "void main()\n"
1122 "{\n"
1123 " outData.color = vec4(0, 0, 0, 1);\n"
1124 + inputSum +
1125 "}\n";
1126
1127 sourceCollections.glslSources.add("compute") << glu::ComputeSource(computeSrc);
1128 }
1129
1130 } // anonymous
1131
createDynamicOffsetTests(tcu::TestContext & testCtx)1132 tcu::TestCaseGroup* createDynamicOffsetTests (tcu::TestContext& testCtx)
1133 {
1134 const char* pipelineTypes[] = { "graphics", "compute" };
1135
1136 struct
1137 {
1138 const char* name;
1139 VkDescriptorType type;
1140 }
1141 const descriptorTypes[] =
1142 {
1143 { "uniform_buffer", VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC },
1144 { "storage_buffer", VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC }
1145 };
1146
1147 struct
1148 {
1149 const char* name;
1150 deUint32 num;
1151 }
1152 const numCmdBuffers[] =
1153 {
1154 { "numcmdbuffers_1", 1u },
1155 { "numcmdbuffers_2", 2u }
1156 };
1157
1158 struct
1159 {
1160 const char* name;
1161 bool reverse;
1162 }
1163 const reverseOrders[] =
1164 {
1165 { "reverseorder", true },
1166 { "sameorder", false }
1167 };
1168
1169 struct
1170 {
1171 const char* name;
1172 deUint32 num;
1173 }
1174 const numDescriptorSetBindings[] =
1175 {
1176 { "numdescriptorsetbindings_1", 1u },
1177 { "numdescriptorsetbindings_2", 2u }
1178 };
1179
1180 struct
1181 {
1182 const char* name;
1183 deUint32 num;
1184 }
1185 const numDynamicBindings[] =
1186 {
1187 { "numdynamicbindings_1", 1u },
1188 { "numdynamicbindings_2", 2u }
1189 };
1190
1191 struct
1192 {
1193 const char* name;
1194 deUint32 num;
1195 }
1196 const numNonDynamicBindings[] =
1197 {
1198 { "numnondynamicbindings_0", 0u },
1199 { "numnondynamicbindings_1", 1u }
1200 };
1201
1202 de::MovePtr<tcu::TestCaseGroup> dynamicOffsetTests (new tcu::TestCaseGroup(testCtx, "dynamic_offset", "Dynamic offset tests"));
1203 de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics", "graphics pipeline"));
1204
1205 for (deUint32 pipelineTypeIdx = 0; pipelineTypeIdx < DE_LENGTH_OF_ARRAY(pipelineTypes); pipelineTypeIdx++)
1206 {
1207 de::MovePtr<tcu::TestCaseGroup> pipelineTypeGroup (new tcu::TestCaseGroup(testCtx, pipelineTypes[pipelineTypeIdx], ""));
1208
1209 for (deUint32 descriptorTypeIdx = 0; descriptorTypeIdx < DE_LENGTH_OF_ARRAY(descriptorTypes); descriptorTypeIdx++)
1210 {
1211 de::MovePtr<tcu::TestCaseGroup> descriptorTypeGroup (new tcu::TestCaseGroup(testCtx, descriptorTypes[descriptorTypeIdx].name, ""));
1212
1213 for (deUint32 numCmdBuffersIdx = 0; numCmdBuffersIdx < DE_LENGTH_OF_ARRAY(numCmdBuffers); numCmdBuffersIdx++)
1214 {
1215 de::MovePtr<tcu::TestCaseGroup> numCmdBuffersGroup (new tcu::TestCaseGroup(testCtx, numCmdBuffers[numCmdBuffersIdx].name, ""));
1216
1217 for (deUint32 reverseOrderIdx = 0; reverseOrderIdx < DE_LENGTH_OF_ARRAY(reverseOrders); reverseOrderIdx++)
1218 {
1219 if (numCmdBuffers[numCmdBuffersIdx].num < 2 && reverseOrders[reverseOrderIdx].reverse)
1220 continue;
1221
1222 de::MovePtr<tcu::TestCaseGroup> reverseOrderGroup (new tcu::TestCaseGroup(testCtx, reverseOrders[reverseOrderIdx].name, ""));
1223
1224 for (deUint32 numDescriptorSetBindingsIdx = 0; numDescriptorSetBindingsIdx < DE_LENGTH_OF_ARRAY(numDescriptorSetBindings); numDescriptorSetBindingsIdx++)
1225 {
1226 if (numCmdBuffers[numCmdBuffersIdx].num > 1 && numDescriptorSetBindings[numDescriptorSetBindingsIdx].num > 1)
1227 continue;
1228
1229 de::MovePtr<tcu::TestCaseGroup> numDescriptorSetBindingsGroup (new tcu::TestCaseGroup(testCtx, numDescriptorSetBindings[numDescriptorSetBindingsIdx].name, ""));
1230 for (deUint32 numDynamicBindingsIdx = 0; numDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numDynamicBindings); numDynamicBindingsIdx++)
1231 {
1232 de::MovePtr<tcu::TestCaseGroup> numDynamicBindingsGroup (new tcu::TestCaseGroup(testCtx, numDynamicBindings[numDynamicBindingsIdx].name, ""));
1233
1234 for (deUint32 numNonDynamicBindingsIdx = 0; numNonDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numNonDynamicBindings); numNonDynamicBindingsIdx++)
1235 {
1236 TestParams params;
1237 params.descriptorType = descriptorTypes[descriptorTypeIdx].type;
1238 params.numCmdBuffers = numCmdBuffers[numCmdBuffersIdx].num;
1239 params.reverseOrder = reverseOrders[reverseOrderIdx].reverse;
1240 params.numDescriptorSetBindings = numDescriptorSetBindings[numDescriptorSetBindingsIdx].num;
1241 params.numDynamicBindings = numDynamicBindings[numDynamicBindingsIdx].num;
1242 params.numNonDynamicBindings = numNonDynamicBindings[numNonDynamicBindingsIdx].num;
1243
1244 if (strcmp(pipelineTypes[pipelineTypeIdx], "graphics") == 0)
1245 numDynamicBindingsGroup->addChild(new DynamicOffsetGraphicsTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
1246 else
1247 numDynamicBindingsGroup->addChild(new DynamicOffsetComputeTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
1248 }
1249
1250 numDescriptorSetBindingsGroup->addChild(numDynamicBindingsGroup.release());
1251 }
1252
1253 reverseOrderGroup->addChild(numDescriptorSetBindingsGroup.release());
1254 }
1255
1256 numCmdBuffersGroup->addChild(reverseOrderGroup.release());
1257 }
1258
1259 descriptorTypeGroup->addChild(numCmdBuffersGroup.release());
1260 }
1261
1262 pipelineTypeGroup->addChild(descriptorTypeGroup.release());
1263 }
1264 dynamicOffsetTests->addChild(pipelineTypeGroup.release());
1265 }
1266
1267 return dynamicOffsetTests.release();
1268 }
1269
1270 } // pipeline
1271 } // vkt
1272