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 <array>
48 #include <cmath>
49 #include <vector>
50 #include <sstream>
51
52 namespace vkt
53 {
54 namespace pipeline
55 {
56
57 using namespace vk;
58 using namespace std;
59 using de::UniquePtr;
60
61 namespace
62 {
63 typedef de::SharedPtr<Unique<VkBuffer> > VkBufferSp;
64 typedef de::SharedPtr<Allocation> AllocationSp;
65 typedef de::SharedPtr<Unique<VkCommandBuffer> > VkCommandBufferSp;
66 typedef de::SharedPtr<Unique<VkRenderPass> > VkRenderPassSp;
67 typedef de::SharedPtr<Unique<VkFramebuffer> > VkFramebufferSp;
68
69 enum class GroupingStrategy
70 {
71 SINGLE_SET = 0,
72 MULTISET = 1,
73 ARRAYS = 2,
74 };
75
76 struct TestParams
77 {
78 PipelineConstructionType pipelineConstructionType;
79 VkDescriptorType descriptorType;
80 deUint32 numCmdBuffers;
81 bool reverseOrder;
82 deUint32 numDescriptorSetBindings;
83 deUint32 numDynamicBindings;
84 deUint32 numNonDynamicBindings;
85 GroupingStrategy groupingStrategy;
86 };
87 #ifndef CTS_USES_VULKANSC
createQuads(deUint32 numQuads,float size)88 vector<Vertex4RGBA> createQuads (deUint32 numQuads, float size)
89 {
90 vector<Vertex4RGBA> vertices;
91
92 for (deUint32 quadNdx = 0; quadNdx < numQuads; quadNdx++)
93 {
94 const float xOffset = -0.5f + (float)quadNdx;
95 const tcu::Vec4 color (0.0f);
96 const Vertex4RGBA lowerLeftVertex = {tcu::Vec4(-size + xOffset, -size, 0.0f, 1.0f), color};
97 const Vertex4RGBA lowerRightVertex = {tcu::Vec4(size + xOffset, -size, 0.0f, 1.0f), color};
98 const Vertex4RGBA UpperLeftVertex = {tcu::Vec4(-size + xOffset, size, 0.0f, 1.0f), color};
99 const Vertex4RGBA UpperRightVertex = {tcu::Vec4(size + xOffset, size, 0.0f, 1.0f), color};
100
101 vertices.push_back(lowerLeftVertex);
102 vertices.push_back(lowerRightVertex);
103 vertices.push_back(UpperLeftVertex);
104 vertices.push_back(UpperLeftVertex);
105 vertices.push_back(lowerRightVertex);
106 vertices.push_back(UpperRightVertex);
107 }
108
109 return vertices;
110 }
111 #endif // CTS_USES_VULKANSC
112
113 static const tcu::Vec4 testColors[] =
114 {
115 tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f),
116 tcu::Vec4(0.0f, 0.3f, 0.0f, 1.0f),
117 tcu::Vec4(0.0f, 0.0f, 0.3f, 1.0f),
118 tcu::Vec4(0.3f, 0.3f, 0.0f, 1.0f),
119 tcu::Vec4(0.0f, 0.3f, 0.3f, 1.0f),
120 tcu::Vec4(0.3f, 0.0f, 0.3f, 1.0f)
121 };
122 static constexpr VkDeviceSize kColorSize = static_cast<VkDeviceSize>(sizeof(testColors[0]));
123 static constexpr deUint32 kNumTestColors = static_cast<deUint32>(DE_LENGTH_OF_ARRAY(testColors));
124
compareVectors(const tcu::Vec4 firstVector,const tcu::Vec4 secondVector,const float tolerance)125 bool compareVectors (const tcu::Vec4 firstVector, const tcu::Vec4 secondVector, const float tolerance)
126 {
127 for (auto i = 0; i < firstVector.SIZE; i++)
128 {
129 if (abs(firstVector[i] - secondVector[i]) > tolerance)
130 return false;
131 }
132
133 return true;
134 }
135
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)136 inline VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage)
137 {
138 const VkImageCreateInfo imageParams =
139 {
140 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
141 DE_NULL, // const void* pNext;
142 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
143 VK_IMAGE_TYPE_2D, // VkImageType imageType;
144 format, // VkFormat format;
145 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
146 1u, // deUint32 mipLevels;
147 1u, // deUint32 arrayLayers;
148 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
149 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
150 usage, // VkImageUsageFlags usage;
151 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
152 0u, // deUint32 queueFamilyIndexCount;
153 DE_NULL, // const deUint32* pQueueFamilyIndices;
154 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
155 };
156
157 return imageParams;
158 }
159
160 class DynamicOffsetTestInstance : public vkt::TestInstance
161 {
162 public:
DynamicOffsetTestInstance(Context & context,const TestParams & params)163 DynamicOffsetTestInstance (Context& context, const TestParams& params)
164 : vkt::TestInstance (context)
165 , m_params (params)
166 , m_memAlloc (context.getDeviceInterface(), context.getDevice(), getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))
167 {}
168
169 protected:
170 const TestParams m_params;
171 SimpleAllocator m_memAlloc;
172 };
173
174 class DynamicOffsetGraphicsTestInstance : public DynamicOffsetTestInstance
175 {
176 public:
177 DynamicOffsetGraphicsTestInstance (Context& context, const TestParams& params);
178 virtual ~DynamicOffsetGraphicsTestInstance (void);
179 void init (void);
180 virtual tcu::TestStatus iterate (void);
181 tcu::TestStatus verifyImage (void);
182
183 private:
184 const tcu::UVec2 m_renderSize;
185 const VkFormat m_colorFormat;
186 VkImageCreateInfo m_colorImageCreateInfo;
187 Move<VkImage> m_colorImage;
188 de::MovePtr<Allocation> m_colorImageAlloc;
189 Move<VkImageView> m_colorAttachmentView;
190 vector<VkRenderPassSp> m_renderPasses;
191 vector<VkFramebufferSp> m_framebuffers;
192 Move<VkShaderModule> m_vertexShaderModule;
193 Move<VkShaderModule> m_fragmentShaderModule;
194 Move<VkBuffer> m_vertexBuffer;
195 de::MovePtr<Allocation> m_vertexBufferAlloc;
196 Move<VkBuffer> m_buffer;
197 de::MovePtr<Allocation> m_bufferAlloc;
198 vector<Move<VkDescriptorSetLayout>> m_descriptorSetLayouts;
199 Move<VkDescriptorPool> m_descriptorPool;
200 vector<Move<VkDescriptorSet>> m_descriptorSets;
201 Move<VkPipelineLayout> m_pipelineLayout;
202 vector<GraphicsPipelineWrapper> m_graphicsPipelines;
203 Move<VkCommandPool> m_cmdPool;
204 vector<VkCommandBufferSp> m_cmdBuffers;
205 vector<Vertex4RGBA> m_vertices;
206 };
207 #ifndef CTS_USES_VULKANSC
DynamicOffsetGraphicsTestInstance(Context & context,const TestParams & params)208 DynamicOffsetGraphicsTestInstance::DynamicOffsetGraphicsTestInstance (Context& context, const TestParams& params)
209 : DynamicOffsetTestInstance (context, params)
210 , m_renderSize (32, 32)
211 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
212 , m_vertices (createQuads(m_params.numDescriptorSetBindings * m_params.numCmdBuffers, 0.25f))
213 {
214 }
215 #endif // CTS_USES_VULKANSC
216
init(void)217 void DynamicOffsetGraphicsTestInstance::init (void)
218 {
219 const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
220 const DeviceInterface& vk = m_context.getDeviceInterface();
221 const VkDevice vkDevice = m_context.getDevice();
222 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
223 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
224 deUint32 offset = 0;
225 deUint32 quadNdx = 0;
226 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
227 const VkDeviceSize alignment = ((m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
228 const VkDeviceSize extraBytes = kColorSize % alignment;
229 const VkDeviceSize colorBlockInputSize = ((extraBytes == 0ull) ? kColorSize : (kColorSize + alignment - extraBytes));
230 const VkDeviceSize bufferSize = colorBlockInputSize * kNumTestColors;
231 const VkDeviceSize bindingOffset = bufferSize / numBindings;
232 const VkDescriptorType nonDynamicDescriptorType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
233
234 vector<VkDescriptorSetLayout> descriptorSetLayoutsPlain;
235 vector<VkDescriptorSet> descriptorSetsPlain;
236
237 // Create color image
238 {
239
240 const VkImageCreateInfo colorImageParams =
241 {
242 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
243 DE_NULL, // const void* pNext;
244 0u, // VkImageCreateFlags flags;
245 VK_IMAGE_TYPE_2D, // VkImageType imageType;
246 m_colorFormat, // VkFormat format;
247 { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
248 1u, // deUint32 mipLevels;
249 1u, // deUint32 arrayLayers;
250 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
251 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
252 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
253 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
254 1u, // deUint32 queueFamilyIndexCount;
255 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
256 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
257 };
258
259 m_colorImageCreateInfo = colorImageParams;
260 m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
261
262 // Allocate and bind color image memory
263 m_colorImageAlloc = m_memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
264 VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
265 }
266
267 // Create color attachment view
268 {
269 const VkImageViewCreateInfo colorAttachmentViewParams =
270 {
271 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
272 DE_NULL, // const void* pNext;
273 0u, // VkImageViewCreateFlags flags;
274 *m_colorImage, // VkImage image;
275 VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
276 m_colorFormat, // VkFormat format;
277 componentMappingRGBA, // VkChannelMapping channels;
278 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange;
279 };
280
281 m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
282 }
283
284 // Create render passes
285 for (deUint32 renderPassIdx = 0; renderPassIdx < m_params.numCmdBuffers; renderPassIdx++)
286 {
287 // The first pass clears the output image, and the second one draws on top of the first pass.
288 const VkAttachmentLoadOp loadOps[] =
289 {
290 VK_ATTACHMENT_LOAD_OP_CLEAR,
291 VK_ATTACHMENT_LOAD_OP_LOAD
292 };
293
294 const VkImageLayout initialLayouts[] =
295 {
296 VK_IMAGE_LAYOUT_UNDEFINED,
297 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
298 };
299
300 const VkAttachmentDescription attachmentDescription =
301 {
302 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
303 m_colorFormat, // VkFormat format
304 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
305 loadOps[renderPassIdx], // VkAttachmentLoadOp loadOp
306 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
307 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
308 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
309 initialLayouts[renderPassIdx], // VkImageLayout initialLayout
310 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
311 };
312
313 const VkAttachmentReference attachmentRef =
314 {
315 0u, // deUint32 attachment
316 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
317 };
318
319 const VkSubpassDescription subpassDescription =
320 {
321 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
322 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
323 0u, // deUint32 inputAttachmentCount
324 DE_NULL, // const VkAttachmentReference* pInputAttachments
325 1u, // deUint32 colorAttachmentCount
326 &attachmentRef, // const VkAttachmentReference* pColorAttachments
327 DE_NULL, // const VkAttachmentReference* pResolveAttachments
328 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
329 0u, // deUint32 preserveAttachmentCount
330 DE_NULL // const deUint32* pPreserveAttachments
331 };
332
333 const VkRenderPassCreateInfo renderPassInfo =
334 {
335 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei sType
336 DE_NULL, // const void* pNext
337 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
338 1u, // deUint32 attachmentCount
339 &attachmentDescription, // const VkAttachmentDescription* pAttachments
340 1u, // deUint32 subpassCount
341 &subpassDescription, // const VkSubpassDescription* pSubpasses
342 0u, // deUint32 dependencyCount
343 DE_NULL // const VkSubpassDependency* pDependencies
344 };
345
346 m_renderPasses.push_back(VkRenderPassSp(new Unique<VkRenderPass>(createRenderPass(vk, vkDevice, &renderPassInfo))));
347 }
348
349 // Create framebuffers
350 for (deUint32 framebufferIdx = 0; framebufferIdx < m_params.numCmdBuffers; framebufferIdx++)
351 {
352 const VkImageView attachmentBindInfos[] =
353 {
354 *m_colorAttachmentView
355 };
356
357 const VkFramebufferCreateInfo framebufferParams =
358 {
359 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
360 DE_NULL, // const void* pNext;
361 0u, // VkFramebufferCreateFlags flags;
362 **m_renderPasses[framebufferIdx], // VkRenderPass renderPass;
363 1u, // deUint32 attachmentCount;
364 attachmentBindInfos, // const VkImageView* pAttachments;
365 (deUint32)m_renderSize.x(), // deUint32 width;
366 (deUint32)m_renderSize.y(), // deUint32 height;
367 1u // deUint32 layers;
368 };
369
370 m_framebuffers.push_back(VkFramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vk, vkDevice, &framebufferParams))));
371 }
372
373 // Create pipeline layout
374 {
375 // Create descriptor set layouts
376 vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
377
378 for (deUint32 binding = 0; binding < numBindings; binding++)
379 {
380 const bool dynamicDesc = (binding < m_params.numDynamicBindings);
381 const VkDescriptorType descriptorType = (dynamicDesc ? m_params.descriptorType : nonDynamicDescriptorType);
382 const deUint32 bindingNumber = (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET ? binding : 0u);
383 const deUint32 descriptorCount = ((m_params.groupingStrategy == GroupingStrategy::ARRAYS) ? (dynamicDesc ? m_params.numDynamicBindings : m_params.numNonDynamicBindings) : 1u);
384 const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding =
385 {
386 bindingNumber, // uint32_t binding;
387 descriptorType, // VkDescriptorType descriptorType;
388 descriptorCount, // uint32_t descriptorCount;
389 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlags stageFlags;
390 DE_NULL // const VkSampler* pImmutableSamplers;
391 };
392
393 // Skip used descriptors in array mode.
394 if (m_params.groupingStrategy == GroupingStrategy::ARRAYS)
395 binding = (dynamicDesc ? m_params.numDynamicBindings - 1 : numBindings);
396
397 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
398 }
399
400 vector<VkDescriptorSetLayoutCreateInfo> descriptorSetLayoutCreateInfos;
401
402 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
403 {
404 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
405 {
406 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
407 DE_NULL, // const void* pNext;
408 0u, // VkDescriptorSetLayoutCreateFlags flags;
409 numBindings, // uint32_t bindingCount;
410 descriptorSetLayoutBindings.data() // const VkDescriptorSetLayoutBinding* pBindings;
411 };
412
413 m_descriptorSetLayouts.push_back(createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo));
414 }
415 else
416 {
417 for (size_t i = 0; i < descriptorSetLayoutBindings.size(); ++i)
418 {
419 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
420 {
421 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
422 DE_NULL, // const void* pNext;
423 0u, // VkDescriptorSetLayoutCreateFlags flags;
424 1u, // uint32_t bindingCount;
425 &descriptorSetLayoutBindings[i] // const VkDescriptorSetLayoutBinding* pBindings;
426 };
427
428 m_descriptorSetLayouts.push_back(createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo));
429 }
430 }
431
432 // Create pipeline layout
433 descriptorSetLayoutsPlain.resize(m_descriptorSetLayouts.size());
434 for (size_t i = 0; i < descriptorSetLayoutsPlain.size(); ++i)
435 descriptorSetLayoutsPlain[i] = m_descriptorSetLayouts[i].get();
436
437 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
438 {
439 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
440 DE_NULL, // const void* pNext;
441 0u, // VkPipelineLayoutCreateFlags flags;
442 static_cast<deUint32>(descriptorSetLayoutsPlain.size()), // deUint32 descriptorSetCount;
443 descriptorSetLayoutsPlain.data(), // const VkDescriptorSetLayout* pSetLayouts;
444 0u, // deUint32 pushConstantRangeCount;
445 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
446 };
447
448 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
449 }
450
451 // Create buffer
452 {
453 vector<deUint8> hostBuffer((size_t)bufferSize, 0);
454 for (deUint32 colorIdx = 0; colorIdx < kNumTestColors; colorIdx++)
455 deMemcpy(&hostBuffer[(deUint32)colorBlockInputSize * colorIdx], &testColors[colorIdx], kColorSize);
456
457 const VkBufferUsageFlags usageFlags = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
458
459 const VkBufferCreateInfo bufferCreateInfo =
460 {
461 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
462 DE_NULL, // const void* pNext;
463 0u, // VkBufferCreateFlags flags
464 bufferSize, // VkDeviceSize size;
465 usageFlags, // VkBufferUsageFlags usage;
466 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
467 1u, // deUint32 queueFamilyCount;
468 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
469 };
470
471 m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
472 m_bufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
473 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
474
475 deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
476 flushAlloc(vk, vkDevice, *m_bufferAlloc);
477 }
478
479 // Create descriptor pool
480 {
481 DescriptorPoolBuilder poolBuilder;
482 poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
483 poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
484 m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, static_cast<deUint32>(m_descriptorSetLayouts.size()));
485 }
486
487 // Create descriptor sets
488 {
489 for (size_t i = 0; i < m_descriptorSetLayouts.size(); ++i)
490 {
491 const VkDescriptorSetAllocateInfo allocInfo =
492 {
493 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
494 DE_NULL, // const void* pNext;
495 *m_descriptorPool, // VkDescriptorPool descriptorPool;
496 1u, // deUint32 setLayoutCount;
497 &(m_descriptorSetLayouts[i].get()), // const VkDescriptorSetLayout* pSetLayouts;
498 };
499 m_descriptorSets.push_back(allocateDescriptorSet(vk, vkDevice, &allocInfo));
500 }
501 }
502
503 descriptorSetsPlain.resize(m_descriptorSets.size());
504 for (size_t i = 0; i < descriptorSetsPlain.size(); ++i)
505 descriptorSetsPlain[i] = m_descriptorSets[i].get();
506
507 // Update descriptor sets
508 for (deUint32 binding = 0; binding < numBindings; ++binding)
509 {
510 const bool dynamicDesc = (binding < m_params.numDynamicBindings);
511 const VkDescriptorType descriptorType = (dynamicDesc ? m_params.descriptorType : nonDynamicDescriptorType);
512 const VkDescriptorBufferInfo descriptorBufferInfo =
513 {
514 *m_buffer, // VkBuffer buffer;
515 bindingOffset * binding, // VkDeviceSize offset;
516 kColorSize // VkDeviceSize range;
517 };
518
519 VkDescriptorSet bindingSet;
520 deUint32 bindingNumber;
521 deUint32 dstArrayElement;
522
523 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
524 {
525 bindingSet = m_descriptorSets[0].get();
526 bindingNumber = binding;
527 dstArrayElement = 0u;
528 }
529 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
530 {
531 bindingSet = m_descriptorSets[binding].get();
532 bindingNumber = 0u;
533 dstArrayElement = 0u;
534 }
535 else // GroupingStrategy::ARRAYS
536 {
537 bindingSet = (dynamicDesc ? m_descriptorSets[0].get() : m_descriptorSets[1].get());
538 bindingNumber = 0u;
539 dstArrayElement = (dynamicDesc ? binding : (binding - m_params.numDynamicBindings));
540 }
541
542 const VkWriteDescriptorSet writeDescriptorSet =
543 {
544 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
545 DE_NULL, // const void* pNext;
546 bindingSet, // VkDescriptorSet dstSet;
547 bindingNumber, // uint32_t dstBinding;
548 dstArrayElement, // uint32_t dstArrayElement;
549 1u, // uint32_t descriptorCount;
550 descriptorType, // VkDescriptorType descriptorType;
551 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
552 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
553 DE_NULL // const VkBufferView* pTexelBufferView;
554 };
555
556 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
557 }
558
559 // Create shaders
560 {
561 m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0u);
562 m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0u);
563 }
564
565 // Create pipelines
566 m_graphicsPipelines.reserve(m_params.numCmdBuffers);
567 for (deUint32 pipelineIdx = 0; pipelineIdx < m_params.numCmdBuffers; pipelineIdx++)
568 {
569 const VkVertexInputBindingDescription vertexInputBindingDescription =
570 {
571 0u, // deUint32 binding;
572 sizeof(Vertex4RGBA), // deUint32 strideInBytes;
573 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
574 };
575
576 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
577 {
578 {
579 0u, // deUint32 location;
580 0u, // deUint32 binding;
581 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
582 0u // deUint32 offsetInBytes;
583 },
584 {
585 1u, // deUint32 location;
586 0u, // deUint32 binding;
587 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
588 DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offset;
589 }
590 };
591
592 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams
593 {
594 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
595 DE_NULL, // const void* pNext;
596 0u, // vkPipelineVertexInputStateCreateFlags flags;
597 1u, // deUint32 bindingCount;
598 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
599 2u, // deUint32 attributeCount;
600 vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
601 };
602
603 const vector<VkViewport> viewports { makeViewport(m_renderSize) };
604 const vector<VkRect2D> scissors { makeRect2D(m_renderSize) };
605
606 m_graphicsPipelines.emplace_back(vk, vkDevice, m_params.pipelineConstructionType);
607 m_graphicsPipelines.back().setMonolithicPipelineLayout(*m_pipelineLayout)
608 .setDefaultRasterizationState()
609 .setDefaultDepthStencilState()
610 .setDefaultColorBlendState()
611 .setDefaultMultisampleState()
612 .setupVertexInputState(&vertexInputStateParams)
613 .setupPreRasterizationShaderState(viewports,
614 scissors,
615 *m_pipelineLayout,
616 **m_renderPasses[pipelineIdx],
617 0u,
618 *m_vertexShaderModule)
619 .setupFragmentShaderState(*m_pipelineLayout, **m_renderPasses[pipelineIdx], 0u, *m_fragmentShaderModule)
620 .setupFragmentOutputState(**m_renderPasses[pipelineIdx])
621 .buildPipeline();
622 }
623
624 // Create vertex buffer
625 {
626 const VkBufferCreateInfo vertexBufferParams =
627 {
628 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
629 DE_NULL, // const void* pNext;
630 0u, // VkBufferCreateFlags flags;
631 (VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()), // VkDeviceSize size;
632 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
633 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
634 1u, // deUint32 queueFamilyCount;
635 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
636 };
637
638 m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
639 m_vertexBufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
640
641 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
642
643 // Load vertices into vertex buffer
644 deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
645 flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
646 }
647
648 // Create command pool
649 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
650
651 // Create command buffers
652 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
653 m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
654
655 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
656 {
657 const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
658 const VkDeviceSize vertexBufferOffset = 0;
659 const deUint32 idx = m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
660
661 beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
662 beginRenderPass(vk, **m_cmdBuffers[idx], **m_renderPasses[idx], **m_framebuffers[idx], makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue);
663 vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipelines[idx].getPipeline());
664 vk.cmdBindVertexBuffers(**m_cmdBuffers[idx], 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
665
666 for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
667 {
668 vector<deUint32> offsets;
669 for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
670 offsets.push_back(offset + (deUint32)colorBlockInputSize * dynamicBindingIdx);
671
672 vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, static_cast<deUint32>(descriptorSetsPlain.size()), descriptorSetsPlain.data(), m_params.numDynamicBindings, offsets.data());
673 offset += (deUint32)colorBlockInputSize;
674
675 // Draw quad
676 vk.cmdDraw(**m_cmdBuffers[idx], 6, 1, 6 * quadNdx, 0);
677 quadNdx++;
678 }
679
680 endRenderPass(vk, **m_cmdBuffers[idx]);
681 endCommandBuffer(vk, **m_cmdBuffers[idx]);
682 }
683 }
684
~DynamicOffsetGraphicsTestInstance(void)685 DynamicOffsetGraphicsTestInstance::~DynamicOffsetGraphicsTestInstance (void)
686 {
687 }
688
iterate(void)689 tcu::TestStatus DynamicOffsetGraphicsTestInstance::iterate (void)
690 {
691 init();
692
693 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
694 submitCommandsAndWait(m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueue(), **m_cmdBuffers[cmdBufferIdx]);
695
696 return verifyImage();
697 }
698
verifyImage(void)699 tcu::TestStatus DynamicOffsetGraphicsTestInstance::verifyImage (void)
700 {
701 const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
702 const tcu::TextureFormat tcuDepthFormat = tcu::TextureFormat();
703 const ColorVertexShader vertexShader;
704 const ColorFragmentShader fragmentShader (tcuColorFormat, tcuDepthFormat);
705 const rr::Program program (&vertexShader, &fragmentShader);
706 ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
707 bool compareOk = false;
708
709 // Render reference image
710 {
711 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
712 const deUint32 bindingOffset = kNumTestColors / numBindings;
713
714 for (deUint32 quadIdx = 0; quadIdx < m_vertices.size() / 6; quadIdx++)
715 for (deUint32 vertexIdx = 0; vertexIdx < 6; vertexIdx++)
716 {
717 tcu::Vec4 refColor(0.0f);
718
719 for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
720 refColor += testColors[quadIdx + binding * bindingOffset + binding];
721 for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
722 refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
723 refColor.w() = 1.0f;
724
725 m_vertices[quadIdx * 6 + vertexIdx].color.xyzw() = refColor;
726 }
727
728 refRenderer.draw(rr::RenderState(refRenderer.getViewportState(), m_context.getDeviceProperties().limits.subPixelPrecisionBits),
729 rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
730 }
731
732 // Compare result with reference image
733 {
734 de::MovePtr<tcu::TextureLevel> result = readColorAttachment(
735 m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueue(),
736 m_context.getUniversalQueueFamilyIndex(), m_memAlloc, *m_colorImage, m_colorFormat, m_renderSize);
737
738 compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
739 "IntImageCompare",
740 "Image comparison",
741 refRenderer.getAccess(),
742 result->getAccess(),
743 tcu::UVec4(2, 2, 2, 2),
744 tcu::IVec3(1, 1, 0),
745 true,
746 tcu::COMPARE_LOG_RESULT);
747 }
748
749 if (compareOk)
750 return tcu::TestStatus::pass("Result image matches reference");
751 else
752 return tcu::TestStatus::fail("Image mismatch");
753 }
754 #ifndef CTS_USES_VULKANSC
755 class DynamicOffsetGraphicsTest : public vkt::TestCase
756 {
757 public:
758 DynamicOffsetGraphicsTest (tcu::TestContext& testContext,
759 const string& name,
760 const string& description,
761 const TestParams& params);
762 ~DynamicOffsetGraphicsTest (void);
763 void initPrograms (SourceCollections& sourceCollections) const;
764 TestInstance* createInstance (Context& context) const;
765 void checkSupport (Context& context) const;
766
767 protected:
768 const TestParams m_params;
769 };
770
DynamicOffsetGraphicsTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)771 DynamicOffsetGraphicsTest::DynamicOffsetGraphicsTest (tcu::TestContext& testContext,
772 const string& name,
773 const string& description,
774 const TestParams& params)
775 : vkt::TestCase (testContext, name, description)
776 , m_params (params)
777 {
778 }
779
~DynamicOffsetGraphicsTest(void)780 DynamicOffsetGraphicsTest::~DynamicOffsetGraphicsTest (void)
781 {
782 }
783
createInstance(Context & context) const784 TestInstance* DynamicOffsetGraphicsTest::createInstance (Context& context) const
785 {
786 return new DynamicOffsetGraphicsTestInstance(context, m_params);
787 }
788
checkSupport(Context & context) const789 void DynamicOffsetGraphicsTest::checkSupport(Context& context) const
790 {
791 checkPipelineLibraryRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.pipelineConstructionType);
792 }
793
initPrograms(SourceCollections & sourceCollections) const794 void DynamicOffsetGraphicsTest::initPrograms (SourceCollections& sourceCollections) const
795 {
796 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
797 const string bufferType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "readonly buffer";
798 ostringstream inputBlocks;
799 ostringstream inputSum;
800 string setAndBinding;
801 string blockSuffix;
802 string accessSuffix;
803 bool dynArrayDecl = false; // Dynamic descriptor block array declared?
804 bool nonDynArrayDecl = false; // Nondynamic descriptor block array declared?
805
806 for (deUint32 b = 0; b < numBindings; b++)
807 {
808 const bool dynBind = (b < m_params.numDynamicBindings);
809 const string bStr = de::toString(b);
810
811 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
812 {
813 setAndBinding = "set = 0, binding = " + bStr;
814 blockSuffix = bStr;
815 accessSuffix = bStr;
816 }
817 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
818 {
819 setAndBinding = "set = " + bStr + ", binding = 0";
820 blockSuffix = bStr;
821 accessSuffix = bStr;
822 }
823 else // GroupingStrategy::ARRAYS
824 {
825 // In array mode, only two sets are declared, one with an array of dynamic descriptors and another one with an array of
826 // nondynamic descriptors.
827 setAndBinding = "set = " + string(dynBind ? "0" : "1") + ", binding = 0";
828 blockSuffix = string(dynBind ? "Dyn" : "NonDyn") + "[" + (dynBind ? de::toString(m_params.numDynamicBindings) : de::toString(m_params.numNonDynamicBindings)) + "]";
829 accessSuffix = string(dynBind ? "Dyn" : "NonDyn") + "[" + (dynBind ? de::toString(b) : de::toString(b - m_params.numDynamicBindings)) + "]";
830 }
831
832 // In array mode, declare the input block only once per descriptor type.
833 bool& arrayDeclFlag = (dynBind ? dynArrayDecl : nonDynArrayDecl);
834 if (m_params.groupingStrategy != GroupingStrategy::ARRAYS || !arrayDeclFlag)
835 {
836 inputBlocks
837 << "layout(" << setAndBinding << ") " << bufferType << " Block" << bStr << "\n"
838 << "{\n"
839 << " vec4 color;\n"
840 << "} inputData" << blockSuffix << ";\n"
841 ;
842 arrayDeclFlag = true;
843 }
844
845 // But the sum always needs to be added once per descriptor.
846 inputSum << " vtxColor.rgb += inputData" << accessSuffix << ".color.rgb;\n";
847 }
848
849 const string vertexSrc =
850 "#version 450\n"
851 "layout(location = 0) in highp vec4 position;\n"
852 "layout(location = 1) in highp vec4 color;\n"
853 "layout(location = 0) out highp vec4 vtxColor;\n"
854 + inputBlocks.str() +
855 "\n"
856 "out gl_PerVertex { vec4 gl_Position; };\n"
857 "\n"
858 "void main()\n"
859 "{\n"
860 " gl_Position = position;\n"
861 " vtxColor = vec4(0, 0, 0, 1);\n"
862 + inputSum.str() +
863 "}\n";
864
865 const string fragmentSrc =
866 "#version 450\n"
867 "layout(location = 0) in highp vec4 vtxColor;\n"
868 "layout(location = 0) out highp vec4 fragColor;\n"
869 "\n"
870 "void main (void)\n"
871 "{\n"
872 " fragColor = vtxColor;\n"
873 "}\n";
874
875 sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSrc);
876 sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
877 }
878 #endif // CTS_USES_VULKANSC
879 class DynamicOffsetComputeTestInstance : public DynamicOffsetTestInstance
880 {
881 public:
882 DynamicOffsetComputeTestInstance (Context& context, const TestParams& params);
883 virtual ~DynamicOffsetComputeTestInstance (void);
884 void init (void);
885 virtual tcu::TestStatus iterate (void);
886 tcu::TestStatus verifyOutput (void);
887
888 private:
889 const deUint32 m_numBindings;
890 const deUint32 m_numOutputColors;
891 const VkPhysicalDeviceLimits m_deviceLimits;
892 Move<VkShaderModule> m_computeShaderModule;
893 Move<VkBuffer> m_buffer;
894 de::MovePtr<Allocation> m_bufferAlloc;
895 vector<Move<VkDescriptorSetLayout>> m_descriptorSetLayouts;
896 Move<VkDescriptorPool> m_descriptorPool;
897 vector<Move<VkDescriptorSet>> m_descriptorSets;
898 Move<VkPipelineLayout> m_pipelineLayout;
899 Move<VkPipeline> m_computePipeline;
900 Move<VkBuffer> m_outputBuffer;
901 de::MovePtr<Allocation> m_outputBufferAlloc;
902 Move<VkCommandPool> m_cmdPool;
903 vector<VkCommandBufferSp> m_cmdBuffers;
904 };
905
DynamicOffsetComputeTestInstance(Context & context,const TestParams & params)906 DynamicOffsetComputeTestInstance::DynamicOffsetComputeTestInstance (Context& context, const TestParams& params)
907 : DynamicOffsetTestInstance (context, params)
908 , m_numBindings (params.numDynamicBindings + params.numNonDynamicBindings)
909 , m_numOutputColors (params.numCmdBuffers * params.numDescriptorSetBindings)
910 , m_deviceLimits (getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits)
911 {
912 }
913
init(void)914 void DynamicOffsetComputeTestInstance::init (void)
915 {
916 const DeviceInterface& vk = m_context.getDeviceInterface();
917 const VkDevice vkDevice = m_context.getDevice();
918 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
919 const VkDeviceSize inputAlignment = ((m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ? m_deviceLimits.minUniformBufferOffsetAlignment : m_deviceLimits.minStorageBufferOffsetAlignment);
920 const VkDeviceSize inputExtraBytes = kColorSize % inputAlignment;
921 const VkDeviceSize colorBlockInputSize = ((inputExtraBytes == 0ull) ? kColorSize : (kColorSize + inputAlignment - inputExtraBytes));
922 const deUint32 colorBlockInputSizeU32 = static_cast<deUint32>(colorBlockInputSize);
923 const VkDeviceSize outputExtraBytes = kColorSize % m_deviceLimits.minStorageBufferOffsetAlignment;
924 const VkDeviceSize colorBlockOutputSize = ((outputExtraBytes == 0ull) ? kColorSize : (kColorSize + m_deviceLimits.minStorageBufferOffsetAlignment - outputExtraBytes));
925 const deUint32 colorBlockOutputSizeU32 = static_cast<deUint32>(colorBlockOutputSize);
926 const VkDeviceSize bufferSize = colorBlockInputSize * kNumTestColors;
927 const VkDeviceSize bindingOffset = bufferSize / m_numBindings;
928 const VkDescriptorType nonDynamicDescriptorType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
929 const VkDeviceSize outputBufferSize = colorBlockOutputSize * m_numOutputColors;
930
931 vector<VkDescriptorSetLayout> descriptorSetLayoutsPlain;
932 vector<VkDescriptorSet> descriptorSetsPlain;
933
934 // Create pipeline layout
935 {
936 // Create descriptor set layouts
937 vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
938
939 for (deUint32 binding = 0; binding < m_numBindings; binding++)
940 {
941 const bool dynamicDesc = (binding < m_params.numDynamicBindings);
942 const VkDescriptorType descriptorType = (dynamicDesc ? m_params.descriptorType : nonDynamicDescriptorType);
943 const deUint32 bindingNumber = (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET ? binding : 0u);
944 const deUint32 descriptorCount = ((m_params.groupingStrategy == GroupingStrategy::ARRAYS) ? (dynamicDesc ? m_params.numDynamicBindings : m_params.numNonDynamicBindings) : 1u);
945 const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding =
946 {
947 bindingNumber, // uint32_t binding;
948 descriptorType, // VkDescriptorType descriptorType;
949 descriptorCount, // uint32_t descriptorCount;
950 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
951 DE_NULL // const VkSampler* pImmutableSamplers;
952 };
953
954 // Skip used descriptors in array mode.
955 if (m_params.groupingStrategy == GroupingStrategy::ARRAYS)
956 binding = (dynamicDesc ? m_params.numDynamicBindings - 1 : m_numBindings);
957
958 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
959 }
960
961 const deUint32 bindingNumberOutput = (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET ? m_numBindings : 0u);
962 const VkDescriptorSetLayoutBinding descriptorSetLayoutBindingOutput =
963 {
964 bindingNumberOutput, // uint32_t binding;
965 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, // VkDescriptorType descriptorType;
966 1u, // uint32_t descriptorCount;
967 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
968 DE_NULL // const VkSampler* pImmutableSamplers;
969 };
970
971 descriptorSetLayoutBindings.push_back(descriptorSetLayoutBindingOutput);
972
973 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
974 {
975 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
976 {
977 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
978 DE_NULL, // const void* pNext;
979 0u, // VkDescriptorSetLayoutCreateFlags flags;
980 m_numBindings + 1, // uint32_t bindingCount;
981 descriptorSetLayoutBindings.data() // const VkDescriptorSetLayoutBinding* pBindings;
982 };
983
984 m_descriptorSetLayouts.push_back(createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL));
985 }
986 else
987 {
988 for (size_t i = 0; i < descriptorSetLayoutBindings.size(); ++i)
989 {
990 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
991 {
992 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
993 DE_NULL, // const void* pNext;
994 0u, // VkDescriptorSetLayoutCreateFlags flags;
995 1u, // uint32_t bindingCount;
996 &descriptorSetLayoutBindings[i] // const VkDescriptorSetLayoutBinding* pBindings;
997 };
998
999 m_descriptorSetLayouts.push_back(createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL));
1000 }
1001 }
1002
1003 // Create pipeline layout
1004 descriptorSetLayoutsPlain.resize(m_descriptorSetLayouts.size());
1005 for (size_t i = 0; i < descriptorSetLayoutsPlain.size(); ++i)
1006 descriptorSetLayoutsPlain[i] = m_descriptorSetLayouts[i].get();
1007
1008 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
1009 {
1010 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1011 DE_NULL, // const void* pNext;
1012 0u, // VkPipelineLayoutCreateFlags flags;
1013 static_cast<deUint32>(descriptorSetLayoutsPlain.size()), // deUint32 descriptorSetCount;
1014 descriptorSetLayoutsPlain.data(), // const VkDescriptorSetLayout* pSetLayouts;
1015 0u, // deUint32 pushConstantRangeCount;
1016 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
1017 };
1018
1019 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
1020 }
1021
1022 // Create buffer
1023 {
1024 vector<deUint8> hostBuffer((deUint32)bufferSize, 0);
1025 for (deUint32 colorIdx = 0; colorIdx < kNumTestColors; colorIdx++)
1026 deMemcpy(&hostBuffer[colorBlockInputSizeU32 * colorIdx], &testColors[colorIdx], kColorSize);
1027
1028 const VkBufferUsageFlags usageFlags = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
1029
1030 const VkBufferCreateInfo bufferCreateInfo =
1031 {
1032 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1033 DE_NULL, // const void* pNext;
1034 0u, // VkBufferCreateFlags flags
1035 bufferSize, // VkDeviceSize size;
1036 usageFlags, // VkBufferUsageFlags usage;
1037 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1038 1u, // deUint32 queueFamilyCount;
1039 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
1040 };
1041
1042 m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1043 m_bufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
1044 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
1045
1046 deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
1047 flushAlloc(vk, vkDevice, *m_bufferAlloc);
1048 }
1049
1050 // Create output buffer
1051 {
1052 const VkBufferCreateInfo bufferCreateInfo =
1053 {
1054 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1055 DE_NULL, // const void* pNext;
1056 0u, // VkBufferCreateFlags flags
1057 outputBufferSize, // VkDeviceSize size;
1058 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage;
1059 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1060 1u, // deUint32 queueFamilyCount;
1061 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
1062 };
1063
1064 m_outputBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1065 m_outputBufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outputBuffer), MemoryRequirement::HostVisible);
1066 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outputBuffer, m_outputBufferAlloc->getMemory(), m_outputBufferAlloc->getOffset()));
1067 }
1068
1069 // Create descriptor pool
1070 {
1071 DescriptorPoolBuilder poolBuilder;
1072 poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
1073 poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
1074 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1u);
1075 m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, static_cast<deUint32>(m_descriptorSetLayouts.size()));
1076 }
1077
1078 // Create descriptor sets
1079 {
1080 for (size_t i = 0; i < m_descriptorSetLayouts.size(); ++i)
1081 {
1082 const VkDescriptorSetAllocateInfo allocInfo =
1083 {
1084 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
1085 DE_NULL, // const void* pNext;
1086 *m_descriptorPool, // VkDescriptorPool descriptorPool;
1087 1u, // deUint32 setLayoutCount;
1088 &(m_descriptorSetLayouts[i].get()), // const VkDescriptorSetLayout* pSetLayouts;
1089 };
1090 m_descriptorSets.push_back(allocateDescriptorSet(vk, vkDevice, &allocInfo));
1091 }
1092 }
1093
1094 descriptorSetsPlain.resize(m_descriptorSets.size());
1095 for (size_t i = 0; i < descriptorSetsPlain.size(); ++i)
1096 descriptorSetsPlain[i] = m_descriptorSets[i].get();
1097
1098 // Update input buffer descriptors
1099 for (deUint32 binding = 0; binding < m_numBindings; ++binding)
1100 {
1101 const bool dynamicDesc = (binding < m_params.numDynamicBindings);
1102 const VkDescriptorType descriptorType = dynamicDesc ? m_params.descriptorType : nonDynamicDescriptorType;
1103 const VkDescriptorBufferInfo descriptorBufferInfo =
1104 {
1105 *m_buffer, // VkBuffer buffer;
1106 bindingOffset * binding, // VkDeviceSize offset;
1107 kColorSize // VkDeviceSize range;
1108 };
1109
1110 VkDescriptorSet bindingSet;
1111 deUint32 bindingNumber;
1112 deUint32 dstArrayElement;
1113
1114 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
1115 {
1116 bindingSet = m_descriptorSets[0].get();
1117 bindingNumber = binding;
1118 dstArrayElement = 0u;
1119 }
1120 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
1121 {
1122 bindingSet = m_descriptorSets[binding].get();
1123 bindingNumber = 0u;
1124 dstArrayElement = 0u;
1125 }
1126 else // GroupingStrategy::ARRAYS
1127 {
1128 bindingSet = (dynamicDesc ? m_descriptorSets[0].get() : m_descriptorSets[1].get());
1129 bindingNumber = 0u;
1130 dstArrayElement = (dynamicDesc ? binding : (binding - m_params.numDynamicBindings));
1131 }
1132
1133 const VkWriteDescriptorSet writeDescriptorSet =
1134 {
1135 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
1136 DE_NULL, // const void* pNext;
1137 bindingSet, // VkDescriptorSet dstSet;
1138 bindingNumber, // uint32_t dstBinding;
1139 dstArrayElement, // uint32_t dstArrayElement;
1140 1u, // uint32_t descriptorCount;
1141 descriptorType, // VkDescriptorType descriptorType;
1142 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
1143 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
1144 DE_NULL // const VkBufferView* pTexelBufferView;
1145 };
1146
1147 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
1148 }
1149
1150 // Update output buffer descriptor
1151 {
1152 const VkDescriptorBufferInfo descriptorBufferInfo =
1153 {
1154 *m_outputBuffer, // VkBuffer buffer;
1155 0u, // VkDeviceSize offset;
1156 kColorSize // VkDeviceSize range;
1157 };
1158
1159 VkDescriptorSet bindingSet;
1160 deUint32 bindingNumber;
1161
1162 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
1163 {
1164 bindingSet = m_descriptorSets[0].get();
1165 bindingNumber = m_numBindings;
1166 }
1167 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
1168 {
1169 bindingSet = m_descriptorSets.back().get();
1170 bindingNumber = 0u;
1171 }
1172 else // GroupingStrategy::ARRAYS
1173 {
1174 bindingSet = m_descriptorSets.back().get();
1175 bindingNumber = 0u;
1176 }
1177
1178 const VkWriteDescriptorSet writeDescriptorSet =
1179 {
1180 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
1181 DE_NULL, // const void* pNext;
1182 bindingSet, // VkDescriptorSet dstSet;
1183 bindingNumber, // uint32_t dstBinding;
1184 0u, // uint32_t dstArrayElement;
1185 1u, // uint32_t descriptorCount;
1186 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, // VkDescriptorType descriptorType;
1187 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
1188 &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
1189 DE_NULL // const VkBufferView* pTexelBufferView;
1190 };
1191
1192 vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
1193 }
1194
1195 // Create shader
1196 {
1197 m_computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0u);
1198 }
1199
1200 // Create pipeline
1201 {
1202 const VkPipelineShaderStageCreateInfo stageCreateInfo =
1203 {
1204 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1205 DE_NULL, // const void* pNext;
1206 0u, // VkPipelineShaderStageCreateFlags flags;
1207 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1208 *m_computeShaderModule, // VkShaderModule module;
1209 "main", // const char* pName;
1210 DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
1211 };
1212
1213 const VkComputePipelineCreateInfo createInfo =
1214 {
1215 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1216 DE_NULL, // const void* pNext;
1217 0u, // VkPipelineCreateFlags flags;
1218 stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
1219 *m_pipelineLayout, // VkPipelineLayout layout;
1220 (VkPipeline)0, // VkPipeline basePipelineHandle;
1221 0u, // int32_t basePipelineIndex;
1222 };
1223
1224 m_computePipeline = createComputePipeline(vk, vkDevice, (vk::VkPipelineCache)0u, &createInfo);
1225 }
1226
1227 // Create command pool
1228 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1229
1230 // Create command buffers
1231 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
1232 m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
1233
1234 deUint32 inputOffset = 0u;
1235 deUint32 outputOffset = 0u;
1236
1237 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
1238 {
1239 const deUint32 idx = m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
1240
1241 beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
1242 vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
1243
1244 for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
1245 {
1246 // Create pipeline barrier
1247 const vk::VkBufferMemoryBarrier bufferBarrier =
1248 {
1249 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1250 DE_NULL, // const void* pNext;
1251 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1252 vk::VK_ACCESS_SHADER_WRITE_BIT | vk::VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1253 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
1254 VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
1255 *m_outputBuffer, // VkBuffer buffer;
1256 outputOffset, // VkDeviceSize offset;
1257 VK_WHOLE_SIZE // VkDeviceSize size;
1258 };
1259
1260 vector<deUint32> offsets;
1261
1262 // Offsets for input buffers
1263 for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
1264 offsets.push_back(inputOffset + colorBlockInputSizeU32 * dynamicBindingIdx);
1265 inputOffset += colorBlockInputSizeU32;
1266
1267 // Offset for output buffer
1268 offsets.push_back(outputOffset);
1269 outputOffset += colorBlockOutputSizeU32;
1270
1271 vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, static_cast<deUint32>(descriptorSetsPlain.size()), descriptorSetsPlain.data(), (deUint32)offsets.size(), offsets.data());
1272
1273 // Dispatch
1274 vk.cmdDispatch(**m_cmdBuffers[idx], 1, 1, 1);
1275
1276 vk.cmdPipelineBarrier(**m_cmdBuffers[idx], vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferBarrier, 0u, DE_NULL);
1277 }
1278
1279 endCommandBuffer(vk, **m_cmdBuffers[idx]);
1280 }
1281 }
1282
~DynamicOffsetComputeTestInstance(void)1283 DynamicOffsetComputeTestInstance::~DynamicOffsetComputeTestInstance (void)
1284 {
1285 }
1286
iterate(void)1287 tcu::TestStatus DynamicOffsetComputeTestInstance::iterate (void)
1288 {
1289 init();
1290
1291 for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
1292 submitCommandsAndWait(m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueue(), **m_cmdBuffers[cmdBufferIdx]);
1293
1294 return verifyOutput();
1295 }
1296
verifyOutput(void)1297 tcu::TestStatus DynamicOffsetComputeTestInstance::verifyOutput (void)
1298 {
1299 const deUint32 bindingOffset = kNumTestColors / m_numBindings;
1300 const deUint32 colorBlockOutputSize = static_cast<deUint32>(de::max(kColorSize, m_deviceLimits.minStorageBufferOffsetAlignment));
1301 vector<tcu::Vec4> refColors (m_numOutputColors);
1302 vector<tcu::Vec4> outColors (m_numOutputColors);
1303
1304 for (deUint32 i = 0; i < m_numOutputColors; i++)
1305 {
1306 tcu::Vec4 refColor(0.0f);
1307
1308 for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
1309 refColor += testColors[i + binding * bindingOffset + binding];
1310 for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
1311 refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
1312 refColor.w() = 1.0f;
1313
1314 refColors[i] = refColor;
1315 }
1316
1317 invalidateAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_outputBufferAlloc);
1318
1319 // Grab the output results using offset alignment
1320 for (deUint32 i = 0; i < m_numOutputColors; i++)
1321 outColors[i] = *(tcu::Vec4*)((deUint8*)m_outputBufferAlloc->getHostPtr() + colorBlockOutputSize * i);
1322
1323 // Verify results
1324 for (deUint32 i = 0; i < m_numOutputColors; i++)
1325 if (outColors[i] != refColors[i])
1326 return tcu::TestStatus::fail("Output mismatch");
1327
1328 return tcu::TestStatus::pass("Output matches expected values");
1329 }
1330
1331 class DynamicOffsetComputeTest : public vkt::TestCase
1332 {
1333 public:
1334 DynamicOffsetComputeTest (tcu::TestContext& testContext,
1335 const string& name,
1336 const string& description,
1337 const TestParams& params);
1338 ~DynamicOffsetComputeTest (void);
1339 void initPrograms (SourceCollections& sourceCollections) const;
1340 TestInstance* createInstance (Context& context) const;
1341
1342 protected:
1343 const TestParams m_params;
1344 };
1345
DynamicOffsetComputeTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)1346 DynamicOffsetComputeTest::DynamicOffsetComputeTest (tcu::TestContext& testContext,
1347 const string& name,
1348 const string& description,
1349 const TestParams& params)
1350 : vkt::TestCase (testContext, name, description)
1351 , m_params (params)
1352 {
1353 }
1354
~DynamicOffsetComputeTest(void)1355 DynamicOffsetComputeTest::~DynamicOffsetComputeTest (void)
1356 {
1357 }
1358
createInstance(Context & context) const1359 TestInstance* DynamicOffsetComputeTest::createInstance (Context& context) const
1360 {
1361 return new DynamicOffsetComputeTestInstance(context, m_params);
1362 }
1363
initPrograms(SourceCollections & sourceCollections) const1364 void DynamicOffsetComputeTest::initPrograms (SourceCollections& sourceCollections) const
1365 {
1366 const deUint32 numBindings = m_params.numDynamicBindings + m_params.numNonDynamicBindings;
1367 const string bufferType = m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "buffer";
1368 ostringstream inputBlocks;
1369 ostringstream inputSum;
1370 string setAndBinding;
1371 string blockSuffix;
1372 string accessSuffix;
1373 bool dynArrayDecl = false; // Dynamic descriptor block array declared?
1374 bool nonDynArrayDecl = false; // Nondynamic descriptor block array declared?
1375 string bStr;
1376
1377 for (deUint32 b = 0; b < numBindings; b++)
1378 {
1379 const bool dynBind = (b < m_params.numDynamicBindings);
1380 bStr = de::toString(b);
1381
1382 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
1383 {
1384 setAndBinding = "set = 0, binding = " + bStr;
1385 blockSuffix = bStr;
1386 accessSuffix = bStr;
1387 }
1388 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
1389 {
1390 setAndBinding = "set = " + bStr + ", binding = 0";
1391 blockSuffix = bStr;
1392 accessSuffix = bStr;
1393 }
1394 else // GroupingStrategy::ARRAYS
1395 {
1396 // In array mode, only two sets are declared, one with an array of dynamic descriptors and another one with an array of
1397 // nondynamic descriptors.
1398 setAndBinding = "set = " + string(dynBind ? "0" : "1") + ", binding = 0";
1399 blockSuffix = string(dynBind ? "Dyn" : "NonDyn") + "[" + (dynBind ? de::toString(m_params.numDynamicBindings) : de::toString(m_params.numNonDynamicBindings)) + "]";
1400 accessSuffix = string(dynBind ? "Dyn" : "NonDyn") + "[" + (dynBind ? de::toString(b) : de::toString(b - m_params.numDynamicBindings)) + "]";
1401 }
1402
1403 // In array mode, declare the input block only once per descriptor type.
1404 bool& arrayDeclFlag = (dynBind ? dynArrayDecl : nonDynArrayDecl);
1405 if (m_params.groupingStrategy != GroupingStrategy::ARRAYS || !arrayDeclFlag)
1406 {
1407 inputBlocks
1408 << "layout(" << setAndBinding << ") " << bufferType << " Block" << bStr << "\n"
1409 << "{\n"
1410 << " vec4 color;\n"
1411 << "} inputData" << blockSuffix << ";\n"
1412 ;
1413 arrayDeclFlag = true;
1414 }
1415
1416 // But the sum always needs to be added once per descriptor.
1417 inputSum << " outData.color.rgb += inputData" << accessSuffix << ".color.rgb;\n";
1418 }
1419
1420 bStr = de::toString(numBindings);
1421 if (m_params.groupingStrategy == GroupingStrategy::SINGLE_SET)
1422 {
1423 setAndBinding = "set = 0, binding = " + bStr;
1424 }
1425 else if (m_params.groupingStrategy == GroupingStrategy::MULTISET)
1426 {
1427 setAndBinding = "set = " + bStr + ", binding = 0";
1428 }
1429 else // GroupingStrategy::ARRAYS
1430 {
1431 // The output buffer goes to a separate set.
1432 deUint32 usedSets = 0u;
1433 if (dynArrayDecl) ++usedSets;
1434 if (nonDynArrayDecl) ++usedSets;
1435
1436 setAndBinding = "set = " + de::toString(usedSets) + ", binding = 0";
1437 }
1438
1439 const string computeSrc =
1440 "#version 450\n"
1441 + inputBlocks.str() +
1442 "layout(" + setAndBinding + ") writeonly buffer Output\n"
1443 "{\n"
1444 " vec4 color;\n"
1445 "} outData;\n"
1446 "\n"
1447 "void main()\n"
1448 "{\n"
1449 " outData.color = vec4(0, 0, 0, 1);\n"
1450 + inputSum.str() +
1451 "}\n";
1452
1453 sourceCollections.glslSources.add("compute") << glu::ComputeSource(computeSrc);
1454 }
1455
1456 class DynamicOffsetMixedTestInstance : public vkt::TestInstance
1457 {
1458 public:
DynamicOffsetMixedTestInstance(Context & context,const tcu::IVec2 renderSize,const deUint32 numInstances,const bool testAllOffsets,const bool reverseOrder,const bool runComputeFirst,const deUint32 vertexOffset,const deUint32 sharedUboOffset,const deUint32 fragUboOffset,const deUint32 ssboReadOffset,const deUint32 ssboWriteOffset)1459 DynamicOffsetMixedTestInstance (Context& context,
1460 const tcu::IVec2 renderSize,
1461 const deUint32 numInstances,
1462 const bool testAllOffsets,
1463 const bool reverseOrder,
1464 const bool runComputeFirst,
1465 const deUint32 vertexOffset,
1466 const deUint32 sharedUboOffset,
1467 const deUint32 fragUboOffset,
1468 const deUint32 ssboReadOffset,
1469 const deUint32 ssboWriteOffset)
1470 : vkt::TestInstance (context)
1471 , m_renderSize (renderSize)
1472 , m_numInstances (numInstances)
1473 , m_testAllOffsets (testAllOffsets)
1474 , m_reverseOrder (reverseOrder)
1475 , m_runComputeFirst (runComputeFirst)
1476 , m_vertexOffset (vertexOffset)
1477 , m_sharedUboOffset (sharedUboOffset)
1478 , m_fragUboOffset (fragUboOffset)
1479 , m_ssboReadOffset (ssboReadOffset)
1480 , m_ssboWriteOffset (ssboWriteOffset)
1481 {}
1482
1483 ~DynamicOffsetMixedTestInstance ();
1484
1485 virtual tcu::TestStatus iterate (void);
1486
1487 private:
1488 struct VertexInfo
1489 {
1490 tcu::Vec4 position;
1491 tcu::Vec4 color;
1492 };
1493
1494 const VkFormat OUTPUT_COLOR_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
1495
1496 const tcu::IVec2 m_renderSize;
1497 const deUint32 m_numInstances;
1498 const bool m_testAllOffsets;
1499 const bool m_reverseOrder;
1500 const bool m_runComputeFirst;
1501 const deUint32 m_vertexOffset;
1502 const deUint32 m_sharedUboOffset;
1503 const deUint32 m_fragUboOffset;
1504 const deUint32 m_ssboReadOffset;
1505 const deUint32 m_ssboWriteOffset;
1506 };
1507
~DynamicOffsetMixedTestInstance()1508 DynamicOffsetMixedTestInstance::~DynamicOffsetMixedTestInstance ()
1509 {
1510 }
1511
iterate(void)1512 tcu::TestStatus DynamicOffsetMixedTestInstance::iterate (void)
1513 {
1514 tcu::TestLog& log = m_context.getTestContext().getLog();
1515 const DeviceInterface& vk = m_context.getDeviceInterface();
1516 const VkDevice device = m_context.getDevice();
1517 Allocator& allocator = m_context.getDefaultAllocator();
1518 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1519
1520 // Create shaders
1521 const Move<VkShaderModule> vertexShaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
1522 const Move<VkShaderModule> fragmentShaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
1523 const Move<VkShaderModule> computeShaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u);
1524
1525 const deUint32 vertexBufferBindId = 0u;
1526
1527 // Vertex input state and binding
1528 VkVertexInputBindingDescription bindingDescription
1529 {
1530 vertexBufferBindId, // uint32_t binding;
1531 sizeof(VertexInfo), // uint32_t stride;
1532 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
1533 };
1534
1535 const std::array<VkVertexInputAttributeDescription, 2> vertexAttributeDescs
1536 { {
1537 VkVertexInputAttributeDescription
1538 {
1539 0u, // uint32_t location;
1540 vertexBufferBindId, // uint32_t binding;
1541 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1542 0u // uint32_t offset;
1543 },
1544
1545 VkVertexInputAttributeDescription
1546 {
1547 1u, // uint32_t location;
1548 vertexBufferBindId, // uint32_t binding;
1549 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1550 deUint32(sizeof(float)) * 4u // uint32_t offset;
1551 }
1552 } };
1553
1554 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
1555 {
1556 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1557 DE_NULL, // const void* pNext;
1558 0u, // VkPipelineVertexInputStateCreateFlags flags;
1559 1u, // uint32_t vertexBindingDescriptionCount;
1560 &bindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1561 static_cast<uint32_t>(vertexAttributeDescs.size()), // uint32_t vertexAttributeDescriptionCount;
1562 vertexAttributeDescs.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1563 };
1564
1565 // Descriptor pool and descriptor set
1566 DescriptorPoolBuilder poolBuilder;
1567
1568 poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3u);
1569 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 2u);
1570
1571 const Move<VkDescriptorPool> descriptorPool = poolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1572
1573 DescriptorSetLayoutBuilder layoutBuilderAttachments;
1574 {
1575 if (!m_reverseOrder)
1576 {
1577 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_VERTEX_BIT);
1578 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT);
1579 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT);
1580 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT);
1581 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT);
1582 }
1583 else
1584 {
1585 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT);
1586 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT);
1587 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT);
1588 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT);
1589 layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_VERTEX_BIT);
1590 }
1591 }
1592
1593 const Move<VkDescriptorSetLayout> descriptorSetLayout = layoutBuilderAttachments.build(vk, device);
1594
1595 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, descriptorPool.get(), descriptorSetLayout.get());
1596
1597 Move<VkImage> colorImage = (makeImage(vk, device, makeImageCreateInfo(m_renderSize, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
1598
1599 // Allocate and bind color image memory
1600 const VkImageSubresourceRange colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1601 const UniquePtr<Allocation> colorImageAlloc (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1602 Move<VkImageView> colorImageView = (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, OUTPUT_COLOR_FORMAT, colorSubresourceRange));
1603
1604 // Create renderpass
1605 const VkAttachmentDescription attachmentDescription =
1606 {
1607 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
1608 OUTPUT_COLOR_FORMAT, // VkFormat format
1609 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
1610 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
1611 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
1612 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
1613 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
1614 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
1615 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
1616 };
1617
1618 const VkAttachmentReference attachmentReference =
1619 {
1620 0u, // deUint32 attachment
1621 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
1622 };
1623
1624 const VkSubpassDescription subpassDescription =
1625 {
1626 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
1627 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
1628 0u, // deUint32 inputAttachmentCount
1629 DE_NULL, // const VkAttachmentReference* pInputAttachments
1630 1u, // deUint32 colorAttachmentCount
1631 &attachmentReference, // const VkAttachmentReference* pColorAttachments
1632 DE_NULL, // const VkAttachmentReference* pResolveAttachments
1633 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
1634 0u, // deUint32 preserveAttachmentCount
1635 DE_NULL // const deUint32* pPreserveAttachments
1636 };
1637
1638 const VkRenderPassCreateInfo renderPassInfo =
1639 {
1640 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei sType
1641 DE_NULL, // const void* pNext
1642 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
1643 1u, // deUint32 attachmentCount
1644 &attachmentDescription, // const VkAttachmentDescription* pAttachments
1645 1u, // deUint32 subpassCount
1646 &subpassDescription, // const VkSubpassDescription* pSubpasses
1647 0u, // deUint32 dependencyCount
1648 DE_NULL // const VkSubpassDependency* pDependencies
1649 };
1650
1651 Move<VkRenderPass> renderPass = createRenderPass(vk, device, &renderPassInfo);
1652
1653 // Create framebuffer
1654 const VkImageView attachmentBindInfos[] =
1655 {
1656 *colorImageView
1657 };
1658
1659 const VkFramebufferCreateInfo framebufferCreateInfo =
1660 {
1661 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1662 DE_NULL, // const void* pNext;
1663 VkFramebufferCreateFlags(0), // VkFramebufferCreateFlags flags;
1664 *renderPass, // VkRenderPass renderPass;
1665 1u, // deUint32 attachmentCount;
1666 attachmentBindInfos, // const VkImageView* pAttachments;
1667 (deUint32)m_renderSize.x(), // deUint32 width;
1668 (deUint32)m_renderSize.y(), // deUint32 height;
1669 1u // deUint32 layers;
1670 };
1671
1672 Move<VkFramebuffer> framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
1673
1674 // Create pipeline layout
1675 const VkPipelineLayoutCreateInfo pipelineLayoutInfo =
1676 {
1677 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1678 DE_NULL, // const void* pNext;
1679 0u, // VkPipelineLayoutCreateFlags flags;
1680 1u, // deUint32 descriptorSetCount;
1681 &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1682 0u, // deUint32 pushConstantRangeCount;
1683 DE_NULL // const VkPushDescriptorRange* pPushDescriptorRanges;
1684 };
1685
1686 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutInfo);
1687
1688 // Create graphics pipeline
1689 const std::vector<VkViewport> viewports(1, makeViewport(m_renderSize));
1690 const std::vector<VkRect2D> scissors(1, makeRect2D(m_renderSize));
1691
1692 Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(
1693 vk, // const DeviceInterface& vk
1694 device, // const VkDevice device
1695 *pipelineLayout, // const VkPipelineLayout pipelineLayout
1696 *vertexShaderModule, // const VkShaderModule vertexShaderModule
1697 DE_NULL, // const VkShaderModule tessellationControlShaderModule
1698 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
1699 DE_NULL, // const VkShaderModule geometryShaderModule
1700 *fragmentShaderModule, // const VkShaderModule fragmentShaderModule
1701 *renderPass, // const VkRenderPass renderPass
1702 viewports, // const std::vector<VkViewport>& viewports
1703 scissors, // const std::vector<VkRect2D>& scissors
1704 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1705 0u, // const deUint32 subpass
1706 0u, // const deUint32 patchControlPoints
1707 &vertexInputStateCreateInfo); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1708
1709 // Create compute pipeline
1710 const VkPipelineShaderStageCreateInfo compPipStageCreateInfo =
1711 {
1712 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1713 DE_NULL, // const void* pNext;
1714 0u, // VkPipelineShaderStageCreateFlags flags;
1715 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1716 *computeShaderModule, // VkShaderModule module;
1717 "main", // const char* pName;
1718 DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
1719 };
1720
1721 const VkComputePipelineCreateInfo compPipelinecreateInfo =
1722 {
1723 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1724 DE_NULL, // const void* pNext;
1725 0u, // VkPipelineCreateFlags flags;
1726 compPipStageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
1727 *pipelineLayout, // VkPipelineLayout layout;
1728 (VkPipeline)0, // VkPipeline basePipelineHandle;
1729 0u, // int32_t basePipelineIndex;
1730 };
1731
1732 Move<VkPipeline> computePipeline = createComputePipeline(vk, device, (vk::VkPipelineCache)0u, &compPipelinecreateInfo);
1733
1734 const VkQueue queue = m_context.getUniversalQueue();
1735 const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
1736
1737 // Create vertex buffer
1738 const deUint32 numVertices = 6;
1739 const VkDeviceSize vertexBufferSizeBytes = 256;
1740 const Unique<VkBuffer> vertexBuffer (makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1741 const de::UniquePtr<Allocation> vertexBufferAlloc (bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
1742
1743 const deUint32 instanceSize = (deUint32)std::sqrt(m_numInstances);
1744 const float posIncrement = 1.0f / (float)m_numInstances * float(instanceSize);
1745
1746 // Result image has to be a square and multiple of 16.
1747 DE_ASSERT(instanceSize * instanceSize == m_numInstances && m_numInstances % 16u == 0);
1748
1749 {
1750 tcu::Vec4 vertexColor = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
1751 VertexInfo* const pVertices = reinterpret_cast<VertexInfo*>(vertexBufferAlloc->getHostPtr());
1752
1753 pVertices[0] = { tcu::Vec4(posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor };
1754 pVertices[1] = { tcu::Vec4(-posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor };
1755 pVertices[2] = { tcu::Vec4(-posIncrement, posIncrement, 0.0f, 1.0f), vertexColor };
1756 pVertices[3] = { tcu::Vec4(-posIncrement, posIncrement, 1.0f, 1.0f), vertexColor };
1757 pVertices[4] = { tcu::Vec4(posIncrement, posIncrement, 1.0f, 1.0f), vertexColor };
1758 pVertices[5] = { tcu::Vec4(posIncrement, -posIncrement, 1.0f, 1.0f), vertexColor };
1759
1760 flushAlloc(vk, device, *vertexBufferAlloc);
1761 }
1762
1763 // Prepare buffers
1764 const vk::VkDeviceSize minUboAlignment = deviceLimits.minUniformBufferOffsetAlignment;
1765 const deUint32 bufferElementSizeVec4 = (deUint32)sizeof(tcu::Vec4);
1766 const deUint32 bufferElementSizeMat4 = (deUint32)sizeof(tcu::Mat4);
1767 deUint32 dynamicAlignmentVec4 = bufferElementSizeVec4;
1768 deUint32 dynamicAlignmentMat4 = bufferElementSizeMat4;
1769
1770 if (minUboAlignment > 0)
1771 {
1772 dynamicAlignmentVec4 = (dynamicAlignmentVec4 + (deUint32)minUboAlignment - 1) & ~((deUint32)minUboAlignment - 1);
1773 dynamicAlignmentMat4 = (dynamicAlignmentMat4 + (deUint32)minUboAlignment - 1) & ~((deUint32)minUboAlignment - 1);
1774 }
1775
1776 const deUint32 bufferSizeVec4 = m_numInstances * dynamicAlignmentVec4;
1777 const deUint32 bufferSizeMat4 = m_numInstances * dynamicAlignmentMat4;
1778
1779 const Unique<VkBuffer> uboBufferVertex (makeBuffer(vk, device, bufferSizeVec4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
1780 const Unique<VkBuffer> uboBufferShared (makeBuffer(vk, device, bufferSizeVec4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
1781 const Unique<VkBuffer> ssboBufferWrite (makeBuffer(vk, device, bufferSizeVec4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
1782 const Unique<VkBuffer> uboBufferFrag (makeBuffer(vk, device, bufferSizeMat4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
1783 const Unique<VkBuffer> ssboBufferRead (makeBuffer(vk, device, bufferSizeMat4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
1784
1785 const UniquePtr<Allocation> uboBufferAllocVertex (bindBuffer(vk, device, allocator, *uboBufferVertex, MemoryRequirement::HostVisible));
1786 const UniquePtr<Allocation> uboBufferAllocShared (bindBuffer(vk, device, allocator, *uboBufferShared, MemoryRequirement::HostVisible));
1787 const UniquePtr<Allocation> ssboBufferAllocWrite (bindBuffer(vk, device, allocator, *ssboBufferWrite, MemoryRequirement::HostVisible));
1788 const UniquePtr<Allocation> uboBufferAllocFrag (bindBuffer(vk, device, allocator, *uboBufferFrag, MemoryRequirement::HostVisible));
1789 const UniquePtr<Allocation> ssboBufferAllocRead (bindBuffer(vk, device, allocator, *ssboBufferRead, MemoryRequirement::HostVisible));
1790
1791 const float colorIncrement = 1.0f / float(m_numInstances);
1792
1793 std::vector<tcu::Vec4> constVertexOffsets;
1794
1795 deUint32 columnCount = 0u;
1796 float columnOffset = posIncrement;
1797 float rowOffset = -1.0f + posIncrement;
1798
1799 for (deUint32 posId = 0; posId < m_numInstances; posId++)
1800 {
1801 constVertexOffsets.push_back(tcu::Vec4(-1.0f + columnOffset, rowOffset, 0.0f, 0.0f));
1802
1803 columnOffset += 2 * posIncrement;
1804 columnCount++;
1805
1806 if (columnCount >= instanceSize)
1807 {
1808 columnCount = 0;
1809 columnOffset = posIncrement;
1810 rowOffset += 2 * posIncrement;
1811 }
1812 }
1813
1814 // Fill buffers
1815 {
1816 char* pPosUboVertex = static_cast<char*>(uboBufferAllocVertex->getHostPtr());
1817 char* pPosUboShared = static_cast<char*>(uboBufferAllocShared->getHostPtr());
1818 char* pPosSsboWrite = static_cast<char*>(ssboBufferAllocWrite->getHostPtr());
1819 char* pPosUboFrag = static_cast<char*>(uboBufferAllocFrag->getHostPtr());
1820 char* pPosSsboRead = static_cast<char*>(ssboBufferAllocRead->getHostPtr());
1821
1822 if (m_testAllOffsets)
1823 {
1824 for (deUint32 posId = 0; posId < m_numInstances; posId++)
1825 {
1826 const float constFragMat[] =
1827 {
1828 colorIncrement, colorIncrement, colorIncrement, colorIncrement,
1829 colorIncrement, colorIncrement, colorIncrement, colorIncrement,
1830 colorIncrement, colorIncrement, colorIncrement, colorIncrement,
1831 colorIncrement, colorIncrement, colorIncrement, colorIncrement * float(posId + 1u)
1832 };
1833
1834 const float constReadMat[] =
1835 {
1836 1.0f, 0.0f, 1.0f, 0.0f,
1837 0.0f, 1.0f, 0.0f, 1.0f - colorIncrement * float(posId + 1u),
1838 1.0f, 0.0f, 1.0f, 0.17f,
1839 0.0f, 1.0f, 0.0f, 1.0f
1840 };
1841
1842 *((tcu::Vec4*)pPosUboVertex) = constVertexOffsets[posId];
1843 *((tcu::Vec4*)pPosUboShared) = tcu::Vec4(colorIncrement * float(posId + 1u), 0.0f, 0.0f, 1.0f);
1844 *((tcu::Vec4*)pPosSsboWrite) = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1845 *((tcu::Mat4*)pPosUboFrag) = tcu::Mat4(constFragMat);
1846 *((tcu::Mat4*)pPosSsboRead) = tcu::Mat4(constReadMat);
1847 pPosUboVertex += dynamicAlignmentVec4;
1848 pPosUboShared += dynamicAlignmentVec4;
1849 pPosSsboWrite += dynamicAlignmentVec4;
1850 pPosUboFrag += dynamicAlignmentMat4;
1851 pPosSsboRead += dynamicAlignmentMat4;
1852 }
1853 }
1854 else
1855 {
1856 for (deUint32 posId = 0; posId < m_numInstances; posId++)
1857 {
1858 const float constFragMat[] =
1859 {
1860 0.0f, 0.0f, 0.0f, 0.0f,
1861 0.0f, 0.0f, 0.0f, 0.0f,
1862 0.0f, 0.0f, 0.0f, 0.0f,
1863 0.0f, 0.0f, 0.0f, m_fragUboOffset == posId ? 1.0f : 0.0f
1864 };
1865
1866 const float constReadMat[] =
1867 {
1868 0.0f, 0.0f, 0.0f, 0.0f,
1869 0.0f, 0.0f, 0.0f, m_ssboReadOffset == posId ? 0.25f : 0.0f,
1870 0.0f, 0.0f, 0.0f, m_ssboReadOffset == posId ? 0.17f : 0.0f,
1871 0.0f, 0.0f, 0.0f, 0.0f
1872 };
1873
1874 *((tcu::Vec4*)pPosUboVertex) = constVertexOffsets[posId];
1875 *((tcu::Vec4*)pPosUboShared) = m_sharedUboOffset == posId ? tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) : tcu::Vec4(0);
1876 *((tcu::Vec4*)pPosSsboWrite) = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1877 *((tcu::Mat4*)pPosUboFrag) = tcu::Mat4(constFragMat);
1878 *((tcu::Mat4*)pPosSsboRead) = tcu::Mat4(constReadMat);
1879 pPosUboVertex += dynamicAlignmentVec4;
1880 pPosUboShared += dynamicAlignmentVec4;
1881 pPosSsboWrite += dynamicAlignmentVec4;
1882 pPosUboFrag += dynamicAlignmentMat4;
1883 pPosSsboRead += dynamicAlignmentMat4;
1884 }
1885 }
1886
1887 flushAlloc(vk, device, *uboBufferAllocVertex);
1888 flushAlloc(vk, device, *uboBufferAllocShared);
1889 flushAlloc(vk, device, *ssboBufferAllocWrite);
1890 flushAlloc(vk, device, *uboBufferAllocFrag);
1891 flushAlloc(vk, device, *ssboBufferAllocRead);
1892 }
1893
1894 const vk::VkDescriptorBufferInfo uboInfoVertexVec = makeDescriptorBufferInfo(*uboBufferVertex, 0u, bufferElementSizeVec4);
1895 const vk::VkDescriptorBufferInfo uboInfoVec = makeDescriptorBufferInfo(*uboBufferShared, 0u, bufferElementSizeVec4);
1896 const vk::VkDescriptorBufferInfo ssboInfoVec = makeDescriptorBufferInfo(*ssboBufferWrite, 0u, bufferElementSizeVec4);
1897 const vk::VkDescriptorBufferInfo uboInfoMat = makeDescriptorBufferInfo(*uboBufferFrag, 0u, bufferElementSizeMat4);
1898 const vk::VkDescriptorBufferInfo ssboInfoMat = makeDescriptorBufferInfo(*ssboBufferRead, 0u, bufferElementSizeMat4);
1899
1900 // Update descriptors
1901 DescriptorSetUpdateBuilder builder;
1902
1903 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(m_reverseOrder ? 4u : 0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &uboInfoVertexVec);
1904 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(m_reverseOrder ? 3u : 1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &uboInfoVec);
1905 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding( 2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, &ssboInfoVec);
1906 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(m_reverseOrder ? 1u : 3u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &uboInfoMat);
1907 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(m_reverseOrder ? 0u : 4u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, &ssboInfoMat);
1908 builder.update(vk, device);
1909
1910 // Command buffer
1911 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1912 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1913
1914 const VkDeviceSize vertexBufferOffset = 0u;
1915
1916 // Render result buffer
1917 const VkDeviceSize colorBufferSizeBytes = tcu::getPixelSize(mapVkFormat(OUTPUT_COLOR_FORMAT)) * static_cast<VkDeviceSize>(m_renderSize.x()) * static_cast<VkDeviceSize>(m_renderSize.y());
1918 const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1919 const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
1920
1921 const VkClearValue clearColorValue = defaultClearValue(OUTPUT_COLOR_FORMAT);
1922
1923 bool runGraphics = !m_runComputeFirst;
1924
1925 for (int i = 0; i < 2; i++)
1926 {
1927 beginCommandBuffer(vk, *cmdBuffer);
1928
1929 if (runGraphics)
1930 {
1931 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), clearColorValue);
1932 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1933 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1934 }
1935 else
1936 {
1937 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
1938 }
1939
1940 if (m_testAllOffsets)
1941 {
1942 for (deUint32 instance = 0; instance < m_numInstances; instance++)
1943 {
1944 deUint32 offsetVec4 = dynamicAlignmentVec4 * instance;
1945 deUint32 offsetMat4 = dynamicAlignmentMat4 * instance;
1946 std::vector<deUint32> offsets;
1947
1948 offsets.push_back(m_reverseOrder ? offsetMat4 : offsetVec4);
1949 offsets.push_back(m_reverseOrder ? offsetMat4 : offsetVec4);
1950 offsets.push_back(offsetVec4);
1951 offsets.push_back(m_reverseOrder ? offsetVec4 : offsetMat4);
1952 offsets.push_back(m_reverseOrder ? offsetVec4 : offsetMat4);
1953
1954 if (runGraphics)
1955 {
1956 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
1957 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
1958 }
1959 else
1960 {
1961 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
1962 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
1963 }
1964 }
1965 }
1966 else
1967 {
1968 std::vector<deUint32> offsets;
1969
1970 offsets.push_back(m_reverseOrder ? dynamicAlignmentMat4 * m_ssboReadOffset : dynamicAlignmentVec4 * m_vertexOffset);
1971 offsets.push_back(m_reverseOrder ? dynamicAlignmentMat4 * m_fragUboOffset : dynamicAlignmentVec4 * m_sharedUboOffset);
1972 offsets.push_back(dynamicAlignmentVec4 * m_ssboWriteOffset);
1973 offsets.push_back(m_reverseOrder ? dynamicAlignmentVec4 * m_sharedUboOffset : dynamicAlignmentMat4 * m_fragUboOffset);
1974 offsets.push_back(m_reverseOrder ? dynamicAlignmentVec4 * m_vertexOffset : dynamicAlignmentMat4 * m_ssboReadOffset);
1975
1976 if (runGraphics)
1977 {
1978 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
1979 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
1980 }
1981 else
1982 {
1983 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
1984 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
1985 }
1986 }
1987
1988 if (runGraphics)
1989 {
1990 endRenderPass(vk, *cmdBuffer);
1991 copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, m_renderSize, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
1992 }
1993
1994 runGraphics = !runGraphics;
1995
1996 endCommandBuffer(vk, *cmdBuffer);
1997
1998 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1999 m_context.resetCommandPoolForVKSC(device, *cmdPool);
2000 }
2001
2002 // Check result image
2003 {
2004 tcu::TextureLevel referenceTexture (mapVkFormat(OUTPUT_COLOR_FORMAT), m_renderSize.x(), m_renderSize.y());
2005 const tcu::PixelBufferAccess referenceAccess = referenceTexture.getAccess();
2006 const deUint32 segmentSize = m_renderSize.x() / instanceSize;
2007
2008 // Create reference image
2009 if (m_testAllOffsets)
2010 {
2011 for (int y = 0; y < m_renderSize.y(); ++y)
2012 {
2013 for (int x = 0; x < m_renderSize.x(); ++x)
2014 {
2015 // While running test for all offsets, we create a nice gradient-like color for the pixels.
2016 float colorValue = (float)(y / segmentSize * instanceSize + x / segmentSize + 1u) * colorIncrement;
2017
2018 referenceAccess.setPixel(tcu::Vec4(colorValue, 0.5f, colorValue, 1.0f), x, y);
2019 }
2020 }
2021 }
2022 else
2023 {
2024 // At first we have to find a correct location for the drawn square.
2025 const deUint32 segmentCountPerRow = (deUint32)m_renderSize.x() / segmentSize;
2026 const deUint32 offsetY = m_vertexOffset > segmentCountPerRow ? m_vertexOffset / segmentCountPerRow : 0u;
2027 const deUint32 offsetX = offsetY > 0 ? m_vertexOffset - (segmentCountPerRow * offsetY) : m_vertexOffset;
2028 const deUint32 pixelOffsetY = segmentSize * offsetY;
2029 const deUint32 pixelOffsetX = segmentSize * offsetX;
2030
2031 for (int y = 0; y < m_renderSize.y(); ++y)
2032 {
2033 for (int x = 0; x < m_renderSize.x(); ++x)
2034 {
2035 float colorValueRed = clearColorValue.color.float32[0];
2036 float colorValueGreen = clearColorValue.color.float32[1];
2037 float colorValueBlue = clearColorValue.color.float32[2];
2038
2039 // Next, we fill the correct number of pixels with test color.
2040 if (x >= (int)pixelOffsetX && x < int(pixelOffsetX + segmentSize) && y >= (int)pixelOffsetY && y < int(pixelOffsetY + segmentSize))
2041 {
2042 // While running test only for one offset, the result color for pixel is constant.
2043 colorValueRed = 1.0f;
2044 colorValueGreen = 0.5f;
2045 colorValueBlue = colorValueRed;
2046 }
2047
2048 referenceAccess.setPixel(tcu::Vec4(colorValueRed, colorValueGreen, colorValueBlue, 1.0f), x, y);
2049 }
2050 }
2051 }
2052
2053 invalidateAlloc(vk, device, *colorBufferAlloc);
2054
2055 const tcu::ConstPixelBufferAccess resultPixelAccess(mapVkFormat(OUTPUT_COLOR_FORMAT), m_renderSize.x(), m_renderSize.y(), 1, colorBufferAlloc->getHostPtr());
2056
2057 if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceAccess, resultPixelAccess, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT))
2058 return tcu::TestStatus::fail("Rendered image is not correct");
2059 }
2060
2061 // Check result buffer values
2062 {
2063 invalidateAlloc(vk, device, *ssboBufferAllocWrite);
2064
2065 std::vector<tcu::Vec4> refColors;
2066 std::vector<tcu::Vec4> outColors;
2067
2068 for (deUint32 i = 0; i < m_numInstances; i++)
2069 {
2070 if (m_testAllOffsets)
2071 {
2072 refColors.push_back(tcu::Vec4(float(i + 1) * colorIncrement, 1.0f - float(i + 1) * colorIncrement, 0.17f, 1.0f));
2073 }
2074 else
2075 {
2076 refColors.push_back(m_ssboWriteOffset == i ? tcu::Vec4(1.0f, 0.25f, 0.17f, 1.0f) : tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
2077 }
2078
2079 outColors.push_back(*(tcu::Vec4*)((deUint8*)ssboBufferAllocWrite->getHostPtr() + dynamicAlignmentVec4 * i));
2080
2081 if (!compareVectors(outColors[i], refColors[i], 0.01f))
2082 {
2083 log << tcu::TestLog::Message << "Reference: " << refColors[i].x() << ", " << refColors[i].y() << ", " << refColors[i].z() << ", " << refColors[i].w() << ", " << tcu::TestLog::EndMessage;
2084 log << tcu::TestLog::Message << "Result : " << outColors[i].x() << ", " << outColors[i].y() << ", " << outColors[i].z() << ", " << outColors[i].w() << ", " << tcu::TestLog::EndMessage;
2085
2086 return tcu::TestStatus::fail("Result value is not correct");
2087 }
2088 }
2089 }
2090
2091 return tcu::TestStatus::pass("Success");
2092 }
2093
2094 class DynamicOffsetMixedTest : public vkt::TestCase
2095 {
2096 public:
DynamicOffsetMixedTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const tcu::IVec2 renderSize,const deUint32 numInstances,const bool testAllOffsets,const bool reverseOrder,const bool runComputeFirst=false,const deUint32 vertexOffset=0u,const deUint32 sharedUboOffset=0u,const deUint32 fragUboOffset=0u,const deUint32 ssboReadOffset=0u,const deUint32 ssboWriteOffset=0u)2097 DynamicOffsetMixedTest (tcu::TestContext& testContext,
2098 const std::string& name,
2099 const std::string& description,
2100 const tcu::IVec2 renderSize,
2101 const deUint32 numInstances,
2102 const bool testAllOffsets,
2103 const bool reverseOrder,
2104 const bool runComputeFirst = false,
2105 const deUint32 vertexOffset = 0u,
2106 const deUint32 sharedUboOffset = 0u,
2107 const deUint32 fragUboOffset = 0u,
2108 const deUint32 ssboReadOffset = 0u,
2109 const deUint32 ssboWriteOffset = 0u)
2110 : vkt::TestCase (testContext, name, description)
2111 , m_renderSize (renderSize)
2112 , m_numInstances (numInstances)
2113 , m_testAllOffsets (testAllOffsets)
2114 , m_reverseOrder (reverseOrder)
2115 , m_runComputeFirst (runComputeFirst)
2116 , m_vertexOffset (vertexOffset)
2117 , m_sharedUboOffset (sharedUboOffset)
2118 , m_fragUboOffset (fragUboOffset)
2119 , m_ssboReadOffset (ssboReadOffset)
2120 , m_ssboWriteOffset (ssboWriteOffset)
2121 {}
2122
2123 ~DynamicOffsetMixedTest (void);
2124
2125 void initPrograms (SourceCollections& sourceCollections) const;
2126 TestInstance *createInstance (Context& context) const;
2127 private:
2128 const tcu::IVec2 m_renderSize;
2129 const deUint32 m_numInstances;
2130 const bool m_testAllOffsets;
2131 const bool m_reverseOrder;
2132 const bool m_runComputeFirst;
2133 const deUint32 m_vertexOffset;
2134 const deUint32 m_sharedUboOffset;
2135 const deUint32 m_fragUboOffset;
2136 const deUint32 m_ssboReadOffset;
2137 const deUint32 m_ssboWriteOffset;
2138 };
2139
~DynamicOffsetMixedTest(void)2140 DynamicOffsetMixedTest::~DynamicOffsetMixedTest (void)
2141 {
2142 }
2143
initPrograms(SourceCollections & sourceCollections) const2144 void DynamicOffsetMixedTest::initPrograms (SourceCollections& sourceCollections) const
2145 {
2146 // Vertex
2147 {
2148 std::ostringstream src;
2149
2150 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2151 << "\n"
2152 << "layout(set = 0, binding = " << (m_reverseOrder ? "4" : "0") << ") uniform uboVertexData\n"
2153 << "{\n"
2154 << " vec4 position;\n"
2155 << "} inputPosData;\n"
2156 << "\n"
2157 << "layout(location = 0) in vec4 inPosition;\n"
2158 << "layout(location = 1) in vec4 inColor;\n"
2159 << "layout(location = 0) out vec4 outColor;\n"
2160 << "\n"
2161 << "out gl_PerVertex\n"
2162 << "{\n"
2163 << " vec4 gl_Position;\n"
2164 << "};\n"
2165 << "\n"
2166 << "void main (void)\n"
2167 << "{\n"
2168 << " gl_Position = inPosition + inputPosData.position;\n"
2169 << " outColor = inColor;\n"
2170 << "}\n";
2171
2172 sourceCollections.glslSources.add("vert") << glu::VertexSource(src.str());
2173 }
2174
2175 // Fragment
2176 {
2177 std::ostringstream src;
2178
2179 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2180 << "\n"
2181 << "layout(set = 0, binding = " << (m_reverseOrder ? "3" : "1") << ") uniform uboSharedData\n"
2182 << "{\n"
2183 << " vec4 color;\n"
2184 << "} inputData0;\n"
2185 << "\n"
2186 << "layout(set = 0, binding = " << (m_reverseOrder ? "1" : "3") << ") uniform uboFragOnly\n"
2187 << "{\n"
2188 << " mat4 color;\n"
2189 << "} inputData1;\n"
2190 << "\n"
2191 << "layout(location = 0) in vec4 inColor;\n"
2192 << "layout(location = 0) out vec4 outColor;\n"
2193 << "\n"
2194 << "void main (void)\n"
2195 << "{\n"
2196 << " outColor = inColor + inputData0.color;\n"
2197 << " outColor.b = inputData1.color[3][3];\n"
2198 << "}\n";
2199
2200 sourceCollections.glslSources.add("frag") << glu::FragmentSource(src.str());
2201 }
2202
2203 // Compute
2204 {
2205 std::ostringstream src;
2206
2207 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2208 << "\n"
2209 << "layout(set = 0, binding = " << (m_reverseOrder ? "3" : "1") << ") uniform uboSharedData\n"
2210 << "{\n"
2211 << " vec4 color;\n"
2212 << "} inputData;\n"
2213 << "\n"
2214 << "layout(set = 0, binding = 2) writeonly buffer ssboOutput\n"
2215 << "{\n"
2216 << " vec4 color;\n"
2217 << "} outData;\n"
2218 << "\n"
2219 << "layout(set = 0, binding = " << (m_reverseOrder ? "0" : "4") << ") readonly buffer ssboInput\n"
2220 << "{\n"
2221 << " mat4 color;\n"
2222 << "} readData;\n"
2223 << "\n"
2224 << "void main (void)\n"
2225 << "{\n"
2226 << " outData.color = inputData.color;\n"
2227 << " outData.color.g = readData.color[3][1];\n"
2228 << " outData.color.b = readData.color[3][2];\n"
2229 << "}\n";
2230
2231 sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
2232 }
2233 }
2234
createInstance(Context & context) const2235 TestInstance* DynamicOffsetMixedTest::createInstance (Context& context) const
2236 {
2237 return new DynamicOffsetMixedTestInstance (context,
2238 m_renderSize,
2239 m_numInstances,
2240 m_testAllOffsets,
2241 m_reverseOrder,
2242 m_runComputeFirst,
2243 m_vertexOffset,
2244 m_sharedUboOffset,
2245 m_fragUboOffset,
2246 m_ssboReadOffset,
2247 m_ssboWriteOffset);
2248 }
2249
2250 } // anonymous
2251
createDynamicOffsetTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)2252 tcu::TestCaseGroup* createDynamicOffsetTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
2253 {
2254 const char* pipelineTypes[] = { "graphics", "compute" };
2255
2256 struct
2257 {
2258 const char* name;
2259 const GroupingStrategy strategy;
2260 }
2261 const groupingTypes[] =
2262 {
2263 { "single_set", GroupingStrategy::SINGLE_SET },
2264 { "multiset", GroupingStrategy::MULTISET },
2265 { "arrays", GroupingStrategy::ARRAYS },
2266 };
2267
2268 struct
2269 {
2270 const char* name;
2271 VkDescriptorType type;
2272 }
2273 const descriptorTypes[] =
2274 {
2275 { "uniform_buffer", VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC },
2276 { "storage_buffer", VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC }
2277 };
2278
2279 struct
2280 {
2281 const char* name;
2282 deUint32 num;
2283 }
2284 const numCmdBuffers[] =
2285 {
2286 { "numcmdbuffers_1", 1u },
2287 { "numcmdbuffers_2", 2u }
2288 };
2289
2290 struct
2291 {
2292 const char* name;
2293 bool reverse;
2294 }
2295 const reverseOrders[] =
2296 {
2297 { "reverseorder", true },
2298 { "sameorder", false }
2299 };
2300
2301 struct
2302 {
2303 const char* name;
2304 deUint32 num;
2305 }
2306 const numDescriptorSetBindings[] =
2307 {
2308 { "numdescriptorsetbindings_1", 1u },
2309 { "numdescriptorsetbindings_2", 2u }
2310 };
2311
2312 struct
2313 {
2314 const char* name;
2315 deUint32 num;
2316 }
2317 const numDynamicBindings[] =
2318 {
2319 { "numdynamicbindings_1", 1u },
2320 { "numdynamicbindings_2", 2u }
2321 };
2322
2323 struct
2324 {
2325 const char* name;
2326 deUint32 num;
2327 }
2328 const numNonDynamicBindings[] =
2329 {
2330 { "numnondynamicbindings_0", 0u },
2331 { "numnondynamicbindings_1", 1u }
2332 };
2333
2334 de::MovePtr<tcu::TestCaseGroup> dynamicOffsetTests (new tcu::TestCaseGroup(testCtx, "dynamic_offset", "Dynamic offset tests"));
2335
2336 for (deUint32 pipelineTypeIdx = 0; pipelineTypeIdx < DE_LENGTH_OF_ARRAY(pipelineTypes); pipelineTypeIdx++)
2337 {
2338 // VK_EXT_graphics_pipeline_library can't be tested with compute pipeline
2339 if ((pipelineTypeIdx == 1) && (pipelineConstructionType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC))
2340 continue;
2341
2342 de::MovePtr<tcu::TestCaseGroup> pipelineTypeGroup (new tcu::TestCaseGroup(testCtx, pipelineTypes[pipelineTypeIdx], ""));
2343
2344 for (deUint32 groupingTypeIdx = 0; groupingTypeIdx < DE_LENGTH_OF_ARRAY(groupingTypes); ++groupingTypeIdx)
2345 {
2346 de::MovePtr<tcu::TestCaseGroup> groupingTypeGroup (new tcu::TestCaseGroup(testCtx, groupingTypes[groupingTypeIdx].name, ""));
2347
2348 for (deUint32 descriptorTypeIdx = 0; descriptorTypeIdx < DE_LENGTH_OF_ARRAY(descriptorTypes); descriptorTypeIdx++)
2349 {
2350 de::MovePtr<tcu::TestCaseGroup> descriptorTypeGroup (new tcu::TestCaseGroup(testCtx, descriptorTypes[descriptorTypeIdx].name, ""));
2351
2352 for (deUint32 numCmdBuffersIdx = 0; numCmdBuffersIdx < DE_LENGTH_OF_ARRAY(numCmdBuffers); numCmdBuffersIdx++)
2353 {
2354 de::MovePtr<tcu::TestCaseGroup> numCmdBuffersGroup (new tcu::TestCaseGroup(testCtx, numCmdBuffers[numCmdBuffersIdx].name, ""));
2355
2356 for (deUint32 reverseOrderIdx = 0; reverseOrderIdx < DE_LENGTH_OF_ARRAY(reverseOrders); reverseOrderIdx++)
2357 {
2358 if (numCmdBuffers[numCmdBuffersIdx].num < 2 && reverseOrders[reverseOrderIdx].reverse)
2359 continue;
2360
2361 de::MovePtr<tcu::TestCaseGroup> reverseOrderGroup (new tcu::TestCaseGroup(testCtx, reverseOrders[reverseOrderIdx].name, ""));
2362
2363 for (deUint32 numDescriptorSetBindingsIdx = 0; numDescriptorSetBindingsIdx < DE_LENGTH_OF_ARRAY(numDescriptorSetBindings); numDescriptorSetBindingsIdx++)
2364 {
2365 if (numCmdBuffers[numCmdBuffersIdx].num > 1 && numDescriptorSetBindings[numDescriptorSetBindingsIdx].num > 1)
2366 continue;
2367
2368 de::MovePtr<tcu::TestCaseGroup> numDescriptorSetBindingsGroup (new tcu::TestCaseGroup(testCtx, numDescriptorSetBindings[numDescriptorSetBindingsIdx].name, ""));
2369 for (deUint32 numDynamicBindingsIdx = 0; numDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numDynamicBindings); numDynamicBindingsIdx++)
2370 {
2371 de::MovePtr<tcu::TestCaseGroup> numDynamicBindingsGroup (new tcu::TestCaseGroup(testCtx, numDynamicBindings[numDynamicBindingsIdx].name, ""));
2372
2373 for (deUint32 numNonDynamicBindingsIdx = 0; numNonDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numNonDynamicBindings); numNonDynamicBindingsIdx++)
2374 {
2375 TestParams params
2376 {
2377 pipelineConstructionType,
2378 descriptorTypes[descriptorTypeIdx].type,
2379 numCmdBuffers[numCmdBuffersIdx].num,
2380 reverseOrders[reverseOrderIdx].reverse,
2381 numDescriptorSetBindings[numDescriptorSetBindingsIdx].num,
2382 numDynamicBindings[numDynamicBindingsIdx].num,
2383 numNonDynamicBindings[numNonDynamicBindingsIdx].num,
2384 groupingTypes[groupingTypeIdx].strategy
2385 };
2386 #ifndef CTS_USES_VULKANSC
2387 if (strcmp(pipelineTypes[pipelineTypeIdx], "graphics") == 0)
2388 numDynamicBindingsGroup->addChild(new DynamicOffsetGraphicsTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
2389 else
2390 #endif // CTS_USES_VULKANSC
2391 numDynamicBindingsGroup->addChild(new DynamicOffsetComputeTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
2392 }
2393
2394 numDescriptorSetBindingsGroup->addChild(numDynamicBindingsGroup.release());
2395 }
2396
2397 reverseOrderGroup->addChild(numDescriptorSetBindingsGroup.release());
2398 }
2399
2400 numCmdBuffersGroup->addChild(reverseOrderGroup.release());
2401 }
2402
2403 descriptorTypeGroup->addChild(numCmdBuffersGroup.release());
2404 }
2405
2406 groupingTypeGroup->addChild(descriptorTypeGroup.release());
2407 }
2408
2409 pipelineTypeGroup->addChild(groupingTypeGroup.release());
2410 }
2411
2412 dynamicOffsetTests->addChild(pipelineTypeGroup.release());
2413 }
2414
2415 // Dynamic descriptor offset test for combined descriptor sets.
2416 {
2417 de::MovePtr<tcu::TestCaseGroup> combinedDescriptorsTests(new tcu::TestCaseGroup(testCtx, "combined_descriptors", ""));
2418
2419 struct
2420 {
2421 const char* name;
2422 const bool reverseDescriptors;
2423 }
2424 const orders[] =
2425 {
2426 { "same_order", false },
2427 { "reverse_order", true }
2428 };
2429
2430 struct
2431 {
2432 const char* name;
2433 const deUint32 offsetCount;
2434 const deUint32 offsets[5];
2435 }
2436 const numOffsets[] =
2437 {
2438 { "16", 16u, { 15u, 7u, 2u, 3u, 5u } },
2439 { "64", 64u, { 27u, 22u, 45u, 19u, 59u } },
2440 { "256", 256u, { 197u, 244u, 110u, 238u, 88u } }
2441 };
2442
2443 struct
2444 {
2445 const char* name;
2446 const bool computeFirst;
2447 }
2448 const pipelineOrders[] =
2449 {
2450 { "graphics_first", false },
2451 { "compute_first", true }
2452 };
2453
2454 // Run tests for all offsets
2455 {
2456 de::MovePtr<tcu::TestCaseGroup> allOffsetsGroup(new tcu::TestCaseGroup(testCtx, "all_offsets", ""));
2457 de::MovePtr<tcu::TestCaseGroup> singleOffsetGroup(new tcu::TestCaseGroup(testCtx, "single_offset", ""));
2458
2459 for (const auto& order : orders)
2460 {
2461 for (const auto& offsets : numOffsets)
2462 {
2463 for (const auto& pipeline : pipelineOrders)
2464 {
2465 allOffsetsGroup->addChild(new DynamicOffsetMixedTest(
2466 testCtx,
2467 std::string(order.name) + "_" + std::string(offsets.name) + "_" + pipeline.name,
2468 "",
2469 tcu::IVec2(32, 32), // Render size
2470 offsets.offsetCount,
2471 true, // All offsets
2472 order.reverseDescriptors,
2473 pipeline.computeFirst));
2474 singleOffsetGroup->addChild(new DynamicOffsetMixedTest(
2475 testCtx,
2476 std::string(order.name) + "_" + std::string(offsets.name) + "_" + pipeline.name,
2477 "",
2478 tcu::IVec2(32, 32), // Render size
2479 offsets.offsetCount,
2480 false, // Single offset only
2481 order.reverseDescriptors,
2482 pipeline.computeFirst,
2483 offsets.offsets[0], // For vertex ubo
2484 offsets.offsets[1], // For shared ubo (fragment & compute)
2485 offsets.offsets[2], // For fragment ubo
2486 offsets.offsets[3], // For ssbo read only
2487 offsets.offsets[4])); // For ssbo write only
2488 }
2489 }
2490 }
2491 combinedDescriptorsTests->addChild(allOffsetsGroup.release());
2492 combinedDescriptorsTests->addChild(singleOffsetGroup.release());
2493 }
2494
2495 dynamicOffsetTests->addChild(combinedDescriptorsTests.release());
2496 }
2497
2498 return dynamicOffsetTests.release();
2499 }
2500
2501 } // pipeline
2502 } // vkt
2503