1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2024 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Subgroups uniform descriptor indexing tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSubgroupsUniformDescriptorIndexingTests.hpp"
25 #include "vkBufferWithMemory.hpp"
26 #include "vkBarrierUtil.hpp"
27 #include "vkBuilderUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vkImageUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "deSTLUtil.hpp"
35 #include "tcuStringTemplate.hpp"
36
37 #include <string_view>
38 #include <array>
39 #include <map>
40
41 namespace
42 {
43 using namespace vk;
44 using namespace vkt;
45 using namespace tcu;
46
47 class UniformDescriptorIndexingTestCaseTestInstance : public TestInstance
48 {
49 public:
50 UniformDescriptorIndexingTestCaseTestInstance(Context &context, VkDescriptorType descriptorType);
51 ~UniformDescriptorIndexingTestCaseTestInstance() = default;
52
53 tcu::TestStatus iterate(void) override;
54
55 protected:
56 Move<VkRenderPass> setupRenderPass(uint32_t inputAttachmentCount) const;
57
58 void setupImages(uint32_t imagesCount, uint32_t imageSize, VkImageUsageFlags usage,
59 uint32_t descriptorImageInfosOffset = 0);
60 void setupStorageBuffers(uint32_t buffersCount, const std::vector<float> &clearColors, VkBufferUsageFlags usage);
61 void setupUniformBuffers(uint32_t descriptorCount, const std::vector<float> &clearColors);
62 void setupTexelBuffer(uint32_t descriptorCount, const std::vector<float> &clearColors, VkBufferUsageFlags usage);
63
64 VkImageCreateInfo getImageCreateInfo(VkFormat format, VkExtent3D extent, VkImageUsageFlags usage) const;
65
66 using BufferWithMemoryPtr = std::unique_ptr<BufferWithMemory>;
67 using BufferWithMemoryVec = std::vector<BufferWithMemoryPtr>;
68 using BufferViewPtr = Move<VkBufferView>;
69 using BufferViewVec = std::vector<BufferViewPtr>;
70 using ImageWithMemoryPtr = std::unique_ptr<ImageWithMemory>;
71 using ImageViewPtr = Move<VkImageView>;
72 using ImageWithMemoryVec = std::vector<ImageWithMemoryPtr>;
73 using ImageViewVec = std::vector<ImageViewPtr>;
74 using SamplerPtr = Move<VkSampler>;
75 using SamplerVec = std::vector<SamplerPtr>;
76
77 protected:
78 const uint32_t m_imageSize = 32;
79 const VkFormat m_imageFormat = VK_FORMAT_R8_UNORM;
80 const VkImageSubresourceRange m_imageSubresourceRange =
81 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
82 VkDescriptorType m_descriptorType;
83
84 ImageWithMemoryVec m_imagesWithMemoryVec;
85 ImageViewVec m_imagesViewVec;
86 BufferWithMemoryVec m_buffersWithMemoryVec;
87 BufferViewVec m_buffersViewVec;
88 SamplerVec m_samplersVec;
89
90 std::vector<VkImageView> m_framebufferImageViews;
91 std::vector<VkDescriptorImageInfo> m_imageInfos;
92 std::vector<VkDescriptorBufferInfo> m_bufferInfos;
93 std::vector<VkBufferView> m_bufferViewsRaw;
94 };
95
UniformDescriptorIndexingTestCaseTestInstance(Context & context,VkDescriptorType descriptorType)96 UniformDescriptorIndexingTestCaseTestInstance::UniformDescriptorIndexingTestCaseTestInstance(
97 Context &context, VkDescriptorType descriptorType)
98 : TestInstance(context)
99 , m_descriptorType(descriptorType)
100 {
101 }
102
iterate(void)103 tcu::TestStatus UniformDescriptorIndexingTestCaseTestInstance::iterate(void)
104 {
105 struct TestConfig
106 {
107 uint32_t descriptorCount; // number of descriptor of tested type
108 uint32_t imagesCount; // number of images required by the test (not counting color attachment)
109 uint32_t buffersCount; // number of buffers required by the test
110 uint32_t samplersCount; // number of samplers required by the test
111 uint32_t minGroupsCount; // minimal allowed number of unique colors found in output image
112
113 TestConfig(uint32_t descriptors, uint32_t images, uint32_t buffers, uint32_t samplers, uint32_t minExpected)
114 : descriptorCount(descriptors)
115 , imagesCount(images)
116 , buffersCount(buffers)
117 , samplersCount(samplers)
118 , minGroupsCount(minExpected)
119 {
120 }
121 };
122
123 // note: minGroupsCount was arbitrarily selected basing on results returned by implementations;
124 // there is no obvious verification method for those tests and number of returned groups
125 // of fragments depends from used image size and from noize used in shader
126 static const std::map<VkDescriptorType, TestConfig> configurationMap{
127 {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, TestConfig(4, 0, 4, 0, 4)},
128 {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, TestConfig(12, 0, 1, 0, 9)},
129 {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, TestConfig(16, 0, 1, 0, 5)},
130 {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, TestConfig(16, 0, 1, 0, 5)},
131 {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, TestConfig(4, 4, 0, 0, 4)},
132 {VK_DESCRIPTOR_TYPE_SAMPLER, TestConfig(4, 1, 0, 4, 2)},
133 {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, TestConfig(16, 16, 0, 1, 10)},
134 {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TestConfig(4, 4, 0, 4, 4)},
135 {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, TestConfig(4, 4, 0, 0, 4)},
136 };
137
138 auto [descriptorCount, imagesCount, buffersCount, samplersCount, minGroupsCount] =
139 configurationMap.at(m_descriptorType);
140
141 // create vector of required number of clear values
142 std::vector<float> clearColors(descriptorCount + 1, 0.0f);
143 std::vector<VkClearValue> clearValues(descriptorCount + 1);
144 for (uint32_t i = 1; i < (uint32_t)clearColors.size(); ++i)
145 {
146 clearColors[i] = float(i) / float(descriptorCount + 1);
147 clearValues[i] = makeClearValueColor(tcu::Vec4(clearColors[i]));
148 }
149
150 const VkExtent3D extent = makeExtent3D(m_imageSize, m_imageSize, 1u);
151 const DeviceInterface &vk = m_context.getDeviceInterface();
152 const VkDevice device = m_context.getDevice();
153 Allocator &allocator = m_context.getDefaultAllocator();
154
155 VkPipelineVertexInputStateCreateInfo vertexInputState = initVulkanStructure();
156 const std::vector<VkViewport> viewports{makeViewport(extent)};
157 const std::vector<VkRect2D> scissors{makeRect2D(extent)};
158
159 // create image that will be used as color attachment to which we will write test result
160 const auto srl(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
161 const auto copyRegion(makeBufferImageCopy(extent, srl));
162 const VkImageUsageFlags imageUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
163 const auto imageLayout((m_descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ?
164 VK_IMAGE_LAYOUT_GENERAL :
165 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
166 ImageWithBuffer outImageWithBuffer(vk, device, allocator, extent, m_imageFormat, imageUsage, VK_IMAGE_TYPE_2D,
167 m_imageSubresourceRange);
168 auto outImageView(makeImageView(vk, device, outImageWithBuffer.getImage(), VK_IMAGE_VIEW_TYPE_2D, m_imageFormat,
169 m_imageSubresourceRange));
170
171 m_framebufferImageViews.push_back(*outImageView);
172
173 if (imagesCount)
174 {
175 m_imagesWithMemoryVec.resize(imagesCount);
176 m_imagesViewVec.resize(imagesCount);
177
178 // include number of required samplers when allocating DescriptorImageInfo (when there are samplers there are always also images);
179 // but dont include samplersCount when combined image sampler case is executed as images and samplers share DescriptorImageInfos
180 uint32_t imageInfoCount =
181 imagesCount + samplersCount * (m_descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
182 m_imageInfos = std::vector<VkDescriptorImageInfo>(
183 imageInfoCount, makeDescriptorImageInfo(VK_NULL_HANDLE, VK_NULL_HANDLE, imageLayout));
184
185 if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
186 setupImages(imagesCount, 3, VK_IMAGE_USAGE_SAMPLED_BIT, samplersCount);
187 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
188 setupImages(imagesCount, 3, VK_IMAGE_USAGE_SAMPLED_BIT);
189 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
190 setupImages(imagesCount, 3, VK_IMAGE_USAGE_SAMPLED_BIT);
191 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
192 setupImages(imagesCount, 3, VK_IMAGE_USAGE_STORAGE_BIT);
193 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
194 setupImages(imagesCount, m_imageSize, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
195 }
196
197 if (buffersCount)
198 {
199 m_buffersWithMemoryVec.resize(buffersCount);
200 m_bufferInfos = std::vector<VkDescriptorBufferInfo>(descriptorCount,
201 makeDescriptorBufferInfo(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE));
202
203 if (m_descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
204 setupUniformBuffers(descriptorCount, clearColors);
205 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
206 setupStorageBuffers(buffersCount, clearColors, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
207 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
208 setupTexelBuffer(descriptorCount, clearColors, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
209 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)
210 setupTexelBuffer(descriptorCount, clearColors, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT);
211 }
212
213 if (samplersCount)
214 {
215 m_samplersVec.resize(samplersCount);
216
217 // ofset imageInfos only for sampled image case
218 uint32_t descriptorImageInfosOffset = (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) * descriptorCount;
219
220 VkSamplerCreateInfo samplerCreateInfo = initVulkanStructure();
221 samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
222 VkSamplerAddressMode addressModes[4] = {VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
223 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
224 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER};
225 for (uint32_t i = 0; i < samplersCount; ++i)
226 {
227 samplerCreateInfo.addressModeU = addressModes[i % 4];
228 m_samplersVec[i] = createSampler(vk, device, &samplerCreateInfo);
229 m_imageInfos[descriptorImageInfosOffset + i].sampler = *m_samplersVec[i];
230 }
231 }
232
233 DescriptorPoolBuilder descriptorPoolBuilder;
234 descriptorPoolBuilder.addType(m_descriptorType, descriptorCount);
235 DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
236 descriptorSetLayoutBuilder.addBinding(m_descriptorType, descriptorCount, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr);
237
238 // some cases require additional descriptor types that are neede to be able to check currently tested ones
239 if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
240 {
241 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1);
242 descriptorSetLayoutBuilder.addIndexedBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT,
243 4, nullptr);
244 }
245 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
246 {
247 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 1);
248 descriptorSetLayoutBuilder.addIndexedBinding(VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT,
249 descriptorCount, nullptr);
250 }
251
252 // create descriptors
253 const auto descriptorPool(
254 descriptorPoolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
255 const auto descriptorSetLayout(descriptorSetLayoutBuilder.build(vk, device));
256 const auto descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
257
258 DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
259 descriptorSetUpdateBuilder.write(*descriptorSet, 0, 0, descriptorCount, m_descriptorType,
260 de::dataOrNull(m_imageInfos), de::dataOrNull(m_bufferInfos),
261 de::dataOrNull(m_bufferViewsRaw));
262
263 if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
264 descriptorSetUpdateBuilder.write(*descriptorSet, descriptorCount, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
265 &m_imageInfos[descriptorCount], 0, 0);
266 else if (m_descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
267 descriptorSetUpdateBuilder.write(*descriptorSet, descriptorCount, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLER,
268 &m_imageInfos[descriptorCount], 0, 0);
269
270 descriptorSetUpdateBuilder.update(vk, device);
271
272 const auto pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
273 auto &bc(m_context.getBinaryCollection());
274 const auto vertModule(createShaderModule(vk, device, bc.get("vert")));
275 const auto fragModule(createShaderModule(vk, device, bc.get("frag")));
276 const uint32_t inputsCount((m_descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) * descriptorCount);
277 const auto renderPass(setupRenderPass(inputsCount));
278 const auto framebuffer(makeFramebuffer(vk, device, *renderPass, (uint32_t)m_framebufferImageViews.size(),
279 m_framebufferImageViews.data(), m_imageSize, m_imageSize));
280 const auto pipeline(makeGraphicsPipeline(vk, device, *pipelineLayout, *vertModule, VK_NULL_HANDLE, VK_NULL_HANDLE,
281 VK_NULL_HANDLE, *fragModule, *renderPass, viewports, scissors,
282 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, 0, &vertexInputState));
283
284 // prepare barriers needed by all test variants
285 const auto beforeClearBarrier(makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
286 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_NULL_HANDLE,
287 m_imageSubresourceRange));
288 const auto afterClearBarrier(makeImageMemoryBarrier(
289 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
290 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, VK_NULL_HANDLE, m_imageSubresourceRange));
291 const auto beforeCopyBarrier(makeImageMemoryBarrier(
292 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
293 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outImageWithBuffer.getImage(), m_imageSubresourceRange));
294 const auto bufferAccessMask((m_descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_ACCESS_UNIFORM_READ_BIT :
295 VK_ACCESS_SHADER_READ_BIT);
296 const auto beforeDrawBarrier(
297 makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, bufferAccessMask, VK_NULL_HANDLE, 0, VK_WHOLE_SIZE));
298
299 const auto queueFamilyIndex(m_context.getUniversalQueueFamilyIndex());
300 const auto cmdPool(
301 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
302 const auto cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
303
304 beginCommandBuffer(vk, *cmdBuffer);
305
306 if (imagesCount)
307 {
308 std::vector<VkImageMemoryBarrier> beforeClearBarriers(imagesCount, beforeClearBarrier);
309 std::vector<VkImageMemoryBarrier> afterClearBarriers(imagesCount, afterClearBarrier);
310
311 for (uint32_t i = 0; i < imagesCount; ++i)
312 {
313 beforeClearBarriers[i].image = **m_imagesWithMemoryVec[i];
314 afterClearBarriers[i].image = **m_imagesWithMemoryVec[i];
315 }
316
317 vk.cmdPipelineBarrier(*cmdBuffer, 0, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0, 0, 0, 0, imagesCount,
318 beforeClearBarriers.data());
319 for (uint32_t i = 0; i < imagesCount; ++i)
320 vk.cmdClearColorImage(*cmdBuffer, **m_imagesWithMemoryVec[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
321 &clearValues[i + 1].color, 1, &m_imageSubresourceRange);
322 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0u, 0, 0,
323 0, 0, imagesCount, afterClearBarriers.data());
324 }
325
326 if (buffersCount)
327 {
328 std::vector<VkBufferMemoryBarrier> beforeDrawBarriers(buffersCount, beforeDrawBarrier);
329 for (uint32_t i = 0; i < buffersCount; ++i)
330 beforeDrawBarriers[i].buffer = **m_buffersWithMemoryVec[i];
331
332 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0,
333 0, buffersCount, beforeDrawBarriers.data(), 0, 0);
334 }
335
336 // draw single triangle big enough to cover whole framebuffer
337 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, scissors[0], 1, clearValues.data());
338 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
339 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u,
340 0);
341 vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
342 endRenderPass(vk, *cmdBuffer);
343
344 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
345 0, 0, 0, 0, 1u, &beforeCopyBarrier);
346 vk.cmdCopyImageToBuffer(*cmdBuffer, outImageWithBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
347 outImageWithBuffer.getBuffer(), 1u, ©Region);
348
349 endCommandBuffer(vk, *cmdBuffer);
350
351 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
352
353 const auto &outBufferAllocation = outImageWithBuffer.getBufferAllocation();
354 invalidateAlloc(vk, device, outBufferAllocation);
355
356 // count number of fragments that have same values
357 uint8_t *outBufferPtr = static_cast<uint8_t *>(outBufferAllocation.getHostPtr());
358 std::map<uint32_t, uint32_t> resultMap;
359 for (uint32_t i = 0; i < m_imageSize * m_imageSize; ++i)
360 {
361 uint32_t value = outBufferPtr[i];
362 resultMap[value] = resultMap[value] + 1;
363 }
364
365 // make sure that none of fragments has background color and there is expected number of color groups
366 if ((resultMap.count(0) == 0) && (resultMap.size() >= minGroupsCount) && (resultMap.size() <= descriptorCount))
367 return tcu::TestStatus::pass("Pass");
368
369 tcu::PixelBufferAccess resultAccess(mapVkFormat(m_imageFormat), m_imageSize, m_imageSize, 1, outBufferPtr);
370 m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Result", "")
371 << tcu::TestLog::Image("Output", "", resultAccess) << tcu::TestLog::EndImageSet;
372
373 if (resultMap.count(0))
374 return tcu::TestStatus::fail(std::to_string(resultMap[0]) + " fragments have background color");
375
376 return tcu::TestStatus::fail(std::to_string(resultMap.size()) + " groups, expected <" +
377 std::to_string(minGroupsCount) + ", " + std::to_string(descriptorCount) + ">");
378 }
379
setupRenderPass(uint32_t inputAttachmentCount) const380 Move<VkRenderPass> UniformDescriptorIndexingTestCaseTestInstance::setupRenderPass(uint32_t inputAttachmentCount) const
381 {
382 const DeviceInterface &vk = m_context.getDeviceInterface();
383 const VkDevice device = m_context.getDevice();
384
385 const VkAttachmentDescription defaultAttachmentDescription{
386 0, // VkAttachmentDescriptionFlags flags
387 m_imageFormat, // VkFormat format
388 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
389 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp
390 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
391 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
392 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
393 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
394 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
395 };
396
397 std::vector<VkAttachmentDescription> attachmentDescriptions(1 + inputAttachmentCount, defaultAttachmentDescription);
398 const VkAttachmentReference colorAttachmentRef{0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
399 std::vector<VkAttachmentReference> inputAttachmentsRefs(4, {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL});
400
401 for (uint32_t i = 0; i < inputAttachmentCount; i++)
402 {
403 auto &inputAttachment = attachmentDescriptions[i + 1];
404 inputAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
405 inputAttachment.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
406 inputAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
407 inputAttachmentsRefs[i].attachment = i + 1;
408 };
409
410 const VkSubpassDescription subpassDescription{
411 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
412 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
413 inputAttachmentCount, // uint32_t inputAttachmentCount
414 inputAttachmentsRefs.data(), // const VkAttachmentReference* pInputAttachments
415 1u, // uint32_t colorAttachmentCount
416 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments
417 nullptr, // const VkAttachmentReference* pResolveAttachments
418 nullptr, // const VkAttachmentReference* pDepthStencilAttachment
419 0u, // uint32_t preserveAttachmentCount
420 nullptr // const uint32_t* pPreserveAttachments
421 };
422
423 const VkRenderPassCreateInfo renderPassInfo{
424 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType
425 nullptr, // const void* pNext
426 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
427 (uint32_t)attachmentDescriptions.size(), // uint32_t attachmentCount
428 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
429 1u, // uint32_t subpassCount
430 &subpassDescription, // const VkSubpassDescription* pSubpasses
431 0u, // uint32_t dependencyCount
432 nullptr // const VkSubpassDependency* pDependencies
433 };
434
435 return createRenderPass(vk, device, &renderPassInfo, nullptr);
436 }
437
setupImages(uint32_t imagesCount,uint32_t imageSize,VkImageUsageFlags usage,uint32_t descriptorImageInfosOffset)438 void UniformDescriptorIndexingTestCaseTestInstance::setupImages(uint32_t imagesCount, uint32_t imageSize,
439 VkImageUsageFlags usage,
440 uint32_t descriptorImageInfosOffset)
441 {
442 const DeviceInterface &vk = m_context.getDeviceInterface();
443 const VkDevice device = m_context.getDevice();
444 Allocator &allocator = m_context.getDefaultAllocator();
445
446 VkImageUsageFlags finalUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | usage;
447 const bool isAttachment = usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
448 const VkExtent3D extent = makeExtent3D(imageSize, imageSize, 1u);
449 const VkImageCreateInfo imageCreateInfo(getImageCreateInfo(m_imageFormat, extent, finalUsage));
450
451 // create additional images that will be used as input attachments
452 if (isAttachment)
453 m_framebufferImageViews.resize(imagesCount + 1);
454
455 for (uint32_t i = 0; i < imagesCount; ++i)
456 {
457 m_imagesWithMemoryVec[i] =
458 ImageWithMemoryPtr(new ImageWithMemory(vk, device, allocator, imageCreateInfo, vk::MemoryRequirement::Any));
459 m_imagesViewVec[i] = makeImageView(vk, device, **m_imagesWithMemoryVec[i], VK_IMAGE_VIEW_TYPE_2D, m_imageFormat,
460 m_imageSubresourceRange);
461 m_imageInfos[descriptorImageInfosOffset + i].imageView = *m_imagesViewVec[i];
462
463 if (isAttachment)
464 m_framebufferImageViews[i + 1] = *m_imagesViewVec[i]; // first view is output color attachment
465 }
466 }
467
setupStorageBuffers(uint32_t buffersCount,const std::vector<float> & clearColors,VkBufferUsageFlags usage)468 void UniformDescriptorIndexingTestCaseTestInstance::setupStorageBuffers(uint32_t buffersCount,
469 const std::vector<float> &clearColors,
470 VkBufferUsageFlags usage)
471 {
472 const DeviceInterface &vk = m_context.getDeviceInterface();
473 const VkDevice device = m_context.getDevice();
474 Allocator &allocator = m_context.getDefaultAllocator();
475
476 VkDeviceSize bufferValuesCount(m_imageSize * m_imageSize);
477 auto bufferCreateInfo(
478 makeBufferCreateInfo(bufferValuesCount * sizeof(float), VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage));
479
480 for (uint32_t i = 0; i < buffersCount; ++i)
481 {
482 m_buffersWithMemoryVec[i] = BufferWithMemoryPtr(
483 new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
484 m_bufferInfos[i] = {**m_buffersWithMemoryVec[i], 0, VK_WHOLE_SIZE};
485 auto *bufferHostPtr = static_cast<float *>(m_buffersWithMemoryVec[i]->getAllocation().getHostPtr());
486
487 std::fill(bufferHostPtr, bufferHostPtr + bufferValuesCount,
488 clearColors[1 + i % uint32_t(clearColors.size() - 1)]);
489 flushAlloc(vk, device, m_buffersWithMemoryVec[i]->getAllocation());
490 }
491 }
492
setupUniformBuffers(uint32_t descriptorCount,const std::vector<float> & clearColors)493 void UniformDescriptorIndexingTestCaseTestInstance::setupUniformBuffers(uint32_t descriptorCount,
494 const std::vector<float> &clearColors)
495 {
496 const DeviceInterface &vk = m_context.getDeviceInterface();
497 const VkDevice device = m_context.getDevice();
498 Allocator &allocator = m_context.getDefaultAllocator();
499
500 const VkDeviceSize alignment(m_context.getDeviceProperties().limits.minUniformBufferOffsetAlignment);
501 const VkDeviceSize roundedSize(deAlign64(sizeof(float), static_cast<uint32_t>(alignment)));
502
503 VkBufferCreateInfo bufferCreateInfo(makeBufferCreateInfo(
504 descriptorCount * roundedSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
505 m_buffersWithMemoryVec[0] = BufferWithMemoryPtr(
506 new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
507
508 auto *bufferHostPtr = static_cast<uint8_t *>(m_buffersWithMemoryVec[0]->getAllocation().getHostPtr());
509 for (uint32_t i = 0; i < descriptorCount; ++i)
510 {
511 auto &info = m_bufferInfos[i];
512 info.buffer = **m_buffersWithMemoryVec[0];
513 info.offset = i * roundedSize;
514 info.range = roundedSize;
515
516 float data = clearColors[i + 1];
517 deMemcpy(bufferHostPtr + info.offset, &data, sizeof(float));
518 }
519
520 flushAlloc(vk, device, m_buffersWithMemoryVec[0]->getAllocation());
521 }
522
setupTexelBuffer(uint32_t descriptorCount,const std::vector<float> & clearColors,VkBufferUsageFlags usage)523 void UniformDescriptorIndexingTestCaseTestInstance::setupTexelBuffer(uint32_t descriptorCount,
524 const std::vector<float> &clearColors,
525 VkBufferUsageFlags usage)
526 {
527 const InstanceInterface &vki = m_context.getInstanceInterface();
528 const DeviceInterface &vk = m_context.getDeviceInterface();
529 const VkDevice device = m_context.getDevice();
530 Allocator &allocator = m_context.getDefaultAllocator();
531
532 auto alignment = m_context.getDeviceProperties().limits.minTexelBufferOffsetAlignment;
533 if (m_context.getTexelBufferAlignmentFeaturesEXT().texelBufferAlignment)
534 {
535 VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT alignmentProperties = initVulkanStructure();
536 VkPhysicalDeviceProperties2 properties2 = initVulkanStructure(&alignmentProperties);
537 vki.getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &properties2);
538
539 bool isUniformTexelBuffer = (usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT);
540 VkBool32 singleTexelAlignment = isUniformTexelBuffer ?
541 alignmentProperties.uniformTexelBufferOffsetSingleTexelAlignment :
542 alignmentProperties.storageTexelBufferOffsetSingleTexelAlignment;
543 VkDeviceSize align = isUniformTexelBuffer ? alignmentProperties.uniformTexelBufferOffsetAlignmentBytes :
544 alignmentProperties.storageTexelBufferOffsetAlignmentBytes;
545 alignment = align;
546 if (singleTexelAlignment)
547 alignment = de::min(4u, (uint32_t)align);
548 }
549
550 const uint32_t viewItems(2);
551 const VkDeviceSize usedViewSize(viewItems * sizeof(float));
552 const VkDeviceSize requiredAlignment(alignment - usedViewSize % alignment);
553 const VkDeviceSize alignedViewSize(usedViewSize + requiredAlignment);
554 const VkDeviceSize bufferSize(descriptorCount * alignedViewSize);
555 auto bufferCreateInfo(makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage));
556
557 m_buffersWithMemoryVec[0] = BufferWithMemoryPtr(
558 new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
559 m_bufferInfos[0] = {**m_buffersWithMemoryVec[0], 0, VK_WHOLE_SIZE};
560 auto &allocation = m_buffersWithMemoryVec[0]->getAllocation();
561 auto *bufferHostPtr = static_cast<char *>(allocation.getHostPtr());
562
563 VkBufferViewCreateInfo bufferViewCreateInfo = initVulkanStructure();
564 bufferViewCreateInfo.buffer = **m_buffersWithMemoryVec[0];
565 bufferViewCreateInfo.format = m_imageFormat;
566 bufferViewCreateInfo.range = usedViewSize;
567
568 m_bufferViewsRaw.resize(descriptorCount);
569 m_buffersViewVec.resize(descriptorCount);
570 for (uint32_t i = 0; i < descriptorCount; ++i)
571 {
572 bufferViewCreateInfo.offset = i * alignedViewSize;
573 m_buffersViewVec[i] = createBufferView(vk, device, &bufferViewCreateInfo);
574 m_bufferViewsRaw[i] = *m_buffersViewVec[i];
575
576 float *viewStart = reinterpret_cast<float *>(bufferHostPtr + bufferViewCreateInfo.offset);
577 std::fill(viewStart, viewStart + viewItems, clearColors[1 + i % uint32_t(clearColors.size() - 1)]);
578 }
579
580 flushAlloc(vk, device, allocation);
581 }
582
getImageCreateInfo(VkFormat format,VkExtent3D extent,VkImageUsageFlags usage) const583 VkImageCreateInfo UniformDescriptorIndexingTestCaseTestInstance::getImageCreateInfo(VkFormat format, VkExtent3D extent,
584 VkImageUsageFlags usage) const
585 {
586 return {
587 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
588 nullptr, // const void* pNext
589 0u, // VkImageCreateFlags flags
590 VK_IMAGE_TYPE_2D, // VkImageType imageType
591 format, // VkFormat format
592 extent, // VkExtent3D extent
593 1u, // uint32_t mipLevels
594 1u, // uint32_t arrayLayers
595 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
596 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
597 usage, // VkImageUsageFlags usage
598 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
599 0u, // uint32_t queueFamilyIndexCount
600 nullptr, // const uint32_t* pQueueFamilyIndices
601 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
602 };
603 };
604
605 class UniformDescriptorIndexingTestCase : public vkt::TestCase
606 {
607 public:
608 UniformDescriptorIndexingTestCase(TestContext &testCtx, const std::string &name, VkDescriptorType descriptorType);
609 virtual ~UniformDescriptorIndexingTestCase(void) = default;
610 virtual void checkSupport(Context &context) const override;
611 virtual void initPrograms(SourceCollections &programCollection) const override;
612 virtual TestInstance *createInstance(Context &context) const override;
613
614 private:
615 VkDescriptorType m_descriptorType;
616 };
617
UniformDescriptorIndexingTestCase(TestContext & testCtx,const std::string & name,VkDescriptorType descriptorType)618 UniformDescriptorIndexingTestCase::UniformDescriptorIndexingTestCase(TestContext &testCtx, const std::string &name,
619 VkDescriptorType descriptorType)
620 : vkt::TestCase(testCtx, name)
621 , m_descriptorType(descriptorType)
622 {
623 }
624
checkSupport(Context & context) const625 void UniformDescriptorIndexingTestCase::checkSupport(Context &context) const
626 {
627 const auto &sProperties = context.getSubgroupProperties();
628 if (sProperties.subgroupSize == 1)
629 TCU_THROW(NotSupportedError, "subgroupSize is 1");
630 if ((sProperties.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
631 TCU_THROW(NotSupportedError, "fragment stage doesn't support subgroup operations");
632
633 const auto &diFeatures = context.getDescriptorIndexingFeatures();
634 if (!diFeatures.runtimeDescriptorArray)
635 TCU_THROW(NotSupportedError, "runtimeDescriptorArray not supported");
636
637 switch (m_descriptorType)
638 {
639 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
640 if (!diFeatures.shaderStorageBufferArrayNonUniformIndexing)
641 TCU_THROW(NotSupportedError,
642 "Non-uniform indexing over storage buffer descriptor arrays is not supported.");
643 break;
644 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
645 if (!diFeatures.shaderUniformBufferArrayNonUniformIndexing)
646 TCU_THROW(NotSupportedError, "Non-uniform indexing for uniform buffer descriptor arrays is not supported.");
647 break;
648 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
649 if (!diFeatures.shaderStorageTexelBufferArrayNonUniformIndexing)
650 TCU_THROW(NotSupportedError,
651 "Non-uniform indexing for storage texel buffer descriptor arrays is not supported.");
652 break;
653 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
654 if (!diFeatures.shaderUniformTexelBufferArrayNonUniformIndexing)
655 TCU_THROW(NotSupportedError,
656 "Non-uniform indexing for uniform texel buffer descriptor arrays is not supported.");
657 break;
658 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
659 if (!diFeatures.shaderInputAttachmentArrayNonUniformIndexing)
660 TCU_THROW(NotSupportedError,
661 "Non-uniform indexing over input attachment descriptor arrays is not supported.");
662 break;
663 case VK_DESCRIPTOR_TYPE_SAMPLER:
664 if (!diFeatures.shaderSampledImageArrayNonUniformIndexing)
665 TCU_THROW(NotSupportedError, "Non-uniform indexing over sampler descriptor arrays is not supported.");
666 break;
667 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
668 if (!diFeatures.shaderSampledImageArrayNonUniformIndexing)
669 TCU_THROW(NotSupportedError, "Non-uniform indexing over sampled image descriptor arrays is not supported.");
670 break;
671 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
672 if (!diFeatures.shaderSampledImageArrayNonUniformIndexing)
673 TCU_THROW(NotSupportedError,
674 "Non-uniform indexing over combined image sampler descriptor arrays is not supported.");
675 break;
676 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
677 if (!diFeatures.shaderStorageImageArrayNonUniformIndexing)
678 TCU_THROW(NotSupportedError, "Non-uniform indexing over storage image descriptor arrays is not supported.");
679 break;
680 default:
681 DE_FATAL("Unknown Descriptor Type");
682 break;
683 }
684 }
685
initPrograms(SourceCollections & programCollection) const686 void UniformDescriptorIndexingTestCase::initPrograms(SourceCollections &programCollection) const
687 {
688 const SpirvVersion spirvVersion(vk::SPIRV_VERSION_1_3);
689 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u);
690
691 struct ShaderConfiguration
692 {
693 std::map<std::string, std::string> specializationMap;
694
695 ShaderConfiguration(const std::string &declaration, const std::string &count, const std::string &accessMethod,
696 const std::string &extraDeclarations, const std::string &extraLayout)
697 : specializationMap{{"declaration", declaration},
698 {"count", count},
699 {"accessMethod", accessMethod},
700 {"extraDeclarations", extraDeclarations},
701 {"extraLayout", extraLayout}}
702 {
703 }
704 };
705
706 const std::map<VkDescriptorType, ShaderConfiguration> shaderPartsMap{
707 {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ShaderConfiguration("buffer Data { float c; }", "4", "data[i].c", "", "")},
708 {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
709 ShaderConfiguration("uniform Data { float c; }", "12", "data[i].c", "", "")},
710 {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
711 ShaderConfiguration("uniform imageBuffer", "16", "imageLoad(data[i], 0).r", "", "r8,")},
712 {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
713 ShaderConfiguration("uniform samplerBuffer", "16", "texelFetch(data[i], 0).r", "", "")},
714 {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
715 ShaderConfiguration("uniform subpassInput", "4", "subpassLoad(data[i]).r", "", "input_attachment_index=0,")},
716 {VK_DESCRIPTOR_TYPE_SAMPLER,
717 ShaderConfiguration("uniform sampler", "4", "texture(sampler2D(tex, data[i]), vec2(1.5)).r",
718 "layout(binding = 4) uniform texture2D tex;\n", "")},
719 {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
720 ShaderConfiguration("uniform texture2D", "16", "texture(sampler2D(data[i], samp), vec2(0.5)).r",
721 "layout(binding = 16) uniform sampler samp;\n", "")},
722 {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
723 ShaderConfiguration("uniform sampler2D", "4", "texture(data[i], uvec2(0.5)).r", "", "")},
724 {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
725 ShaderConfiguration("uniform image2D", "4", "imageLoad(data[i], ivec2(0)).r", "", "r8,")},
726 };
727
728 std::string fragTemplate =
729 "#version 450\n"
730 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
731 "#extension GL_EXT_nonuniform_qualifier: enable\n"
732 "layout(location = 0) out highp float fragColor;\n"
733 "layout(${extraLayout}binding = 0) ${declaration} data[];\n"
734 "${extraDeclarations}"
735 "void main (void)\n"
736 "{\n"
737 // use cosine to generate pseudo-random value for each fragment; coordinates of each fragment are used
738 // to calculate angle for cosine; both coordinates are multiplied by big numbers in order to make small
739 // change in coordinates produce completely different cosine value; amplitude is also multiplied by big
740 // number before calculating fraction in order to reduce any visible pattern for selected image size;
741 // there was no reason why those numbers were hosen and they could be replaced with any other big
742 // numbers to get different noize
743 " const float noize = fract(9876.54 * cos(654.3267 * gl_FragCoord.x + 1234.5678 * gl_FragCoord.y));\n"
744 // pseudo-randomly select material for fragment
745 " const uint materialIndex = uint(noize * ${count});\n"
746 " fragColor.r = 0.0;\n"
747 // do a "peeling loop" - iterate over each unique index used such that the accessed resource
748 // is always uniform within the subgroup; and in a way that it's not uniform across the draw
749 " for(;;)\n"
750 " {\n"
751 " uint i = subgroupBroadcastFirst(materialIndex);\n"
752 " if(i == materialIndex)\n"
753 " {\n"
754 // we don't use nonuniformEXT(i) - that is the purpose of tests in this file
755 " fragColor.r = ${accessMethod};\n"
756 " break;\n"
757 " }\n"
758 " }\n"
759 "}\n";
760
761 // draw single triangle big enough to cover whole framebuffer
762 programCollection.glslSources.add("vert")
763 << glu::VertexSource("#version 450\n"
764 "void main (void)\n"
765 "{\n"
766 " const float x = -1.0 + 4.0 * ((gl_VertexIndex & 2)>>1);\n"
767 " const float y = -1.0 + 4.0 * (gl_VertexIndex % 2);\n"
768 " gl_Position = vec4(x, y, 0.0, 1.0);\n"
769 "}\n");
770
771 auto &specializationMap = shaderPartsMap.at(m_descriptorType).specializationMap;
772 programCollection.glslSources.add("frag")
773 << glu::FragmentSource(StringTemplate(fragTemplate).specialize(specializationMap)) << buildOptions;
774 }
775
createInstance(Context & context) const776 TestInstance *UniformDescriptorIndexingTestCase::createInstance(Context &context) const
777 {
778 return new UniformDescriptorIndexingTestCaseTestInstance(context, m_descriptorType);
779 }
780
781 } // unnamed namespace
782
783 namespace vkt::subgroups
784 {
785
createSubgroupsUniformDescriptorIndexingTests(tcu::TestContext & testCtx)786 tcu::TestCaseGroup *createSubgroupsUniformDescriptorIndexingTests(tcu::TestContext &testCtx)
787 {
788 std::pair<const char *, VkDescriptorType> caseList[]{
789 {
790 "storage_buffer",
791 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
792 },
793 {
794 "storage_texel_buffer",
795 VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
796 },
797 {
798 "uniform_texel_buffer",
799 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
800 },
801 {
802 "storage_image",
803 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
804 },
805 {
806 "sampler",
807 VK_DESCRIPTOR_TYPE_SAMPLER,
808 },
809 {
810 "sampled_image",
811 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
812 },
813 {
814 "combined_image_sampler",
815 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
816 },
817 {
818 "uniform_buffer",
819 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
820 },
821 {
822 "input_attachment",
823 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
824 },
825 };
826
827 de::MovePtr<TestCaseGroup> group(new TestCaseGroup(testCtx, "uniform_descriptor_indexing"));
828 for (auto &[name, type] : caseList)
829 group->addChild(new UniformDescriptorIndexingTestCase(testCtx, name, type));
830
831 return group.release();
832 }
833
834 } // namespace vkt::subgroups
835