1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 Google Inc.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file vktPipelineDescriptorLimits.cpp
24  * \brief Descriptor limit tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineDescriptorLimitsTests.hpp"
28 #include "vktPipelineClearUtil.hpp"
29 
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 
38 #include "tcuImageCompare.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuTextureUtil.hpp"
41 
42 #include "deUniquePtr.hpp"
43 
44 #include <array>
45 
46 namespace vkt
47 {
48 namespace pipeline
49 {
50 
51 using namespace vk;
52 
53 namespace
54 {
55 
56 enum class TestType
57 {
58     Samplers         = 0,
59     UniformBuffers   = 1,
60     StorageBuffers   = 2,
61     SampledImages    = 3,
62     StorageImages    = 4,
63     InputAttachments = 5
64 };
65 
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)66 inline VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const VkFormat format,
67                                              const VkImageUsageFlags usage)
68 {
69     const VkImageCreateInfo imageParams = {
70         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
71         DE_NULL,                             // const void* pNext;
72         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
73         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
74         format,                              // VkFormat format;
75         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
76         1u,                                  // uint32_t mipLevels;
77         1u,                                  // uint32_t arrayLayers;
78         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
79         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
80         usage,                               // VkImageUsageFlags usage;
81         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
82         0u,                                  // uint32_t queueFamilyIndexCount;
83         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
84         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
85     };
86     return imageParams;
87 }
88 
generateColorImage(const VkFormat format,const tcu::IVec2 & renderSize,const tcu::Vec4 color)89 tcu::TextureLevel generateColorImage(const VkFormat format, const tcu::IVec2 &renderSize, const tcu::Vec4 color)
90 {
91     tcu::TextureLevel image(mapVkFormat(format), renderSize.x(), renderSize.y());
92     tcu::clear(image.getAccess(), color);
93 
94     return image;
95 }
96 
makeRenderPassInputAttachment(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat)97 RenderPassWrapper makeRenderPassInputAttachment(const DeviceInterface &vk, const VkDevice device,
98                                                 const PipelineConstructionType pipelineConstructionType,
99                                                 const VkFormat colorFormat)
100 {
101     const VkAttachmentDescription colorAttachmentDescription = {
102         (VkAttachmentDescriptionFlags)0,         // VkAttachmentDescriptionFlags    flags
103         colorFormat,                             // VkFormat                        format
104         VK_SAMPLE_COUNT_1_BIT,                   // VkSampleCountFlagBits        samples
105         VK_ATTACHMENT_LOAD_OP_CLEAR,             // VkAttachmentLoadOp            loadOp
106         VK_ATTACHMENT_STORE_OP_STORE,            // VkAttachmentStoreOp            storeOp
107         VK_ATTACHMENT_LOAD_OP_DONT_CARE,         // VkAttachmentLoadOp            stencilLoadOp
108         VK_ATTACHMENT_STORE_OP_DONT_CARE,        // VkAttachmentStoreOp            stencilStoreOp
109         VK_IMAGE_LAYOUT_UNDEFINED,               // VkImageLayout                initialLayout
110         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                finalLayout
111     };
112 
113     const VkAttachmentDescription inputAttachmentDescription = {
114         VkAttachmentDescriptionFlags(0),          // VkAttachmentDescriptionFlags flags;
115         colorFormat,                              // VkFormat format;
116         VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
117         VK_ATTACHMENT_LOAD_OP_LOAD,               // VkAttachmentLoadOp loadOp;
118         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
119         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
120         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
121         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
122         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL  // VkImageLayout finalLayout;
123     };
124 
125     const std::vector<VkAttachmentDescription> attachmentDescriptions = {
126         inputAttachmentDescription, inputAttachmentDescription, colorAttachmentDescription};
127 
128     const std::vector<VkAttachmentReference> inputAttachmentReferences = {{0u, inputAttachmentDescription.finalLayout},
129                                                                           {1u, inputAttachmentDescription.finalLayout}};
130 
131     const VkAttachmentReference colorAttachmentReference = {2u, colorAttachmentDescription.finalLayout};
132 
133     const VkSubpassDescription subpassDescription = {
134         (VkSubpassDescriptionFlags)0,                            // VkSubpassDescriptionFlags    flags
135         VK_PIPELINE_BIND_POINT_GRAPHICS,                         // VkPipelineBindPoint            pipelineBindPoint
136         static_cast<uint32_t>(inputAttachmentReferences.size()), // uint32_t                        inputAttachmentCount
137         inputAttachmentReferences.data(),                        // const VkAttachmentReference*    pInputAttachments
138         1u,                                                      // uint32_t                        colorAttachmentCount
139         &colorAttachmentReference,                               // const VkAttachmentReference*    pColorAttachments
140         DE_NULL,                                                 // const VkAttachmentReference*    pResolveAttachments
141         DE_NULL, // const VkAttachmentReference*    pDepthStencilAttachment
142         0u,      // uint32_t                        preserveAttachmentCount
143         DE_NULL  // const uint32_t*                pPreserveAttachments
144     };
145 
146     const VkRenderPassCreateInfo renderPassInfo = {
147         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                    sType
148         DE_NULL,                                   // const void*                        pNext
149         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags            flags
150         (uint32_t)attachmentDescriptions.size(),   // uint32_t                            attachmentCount
151         attachmentDescriptions.data(),             // const VkAttachmentDescription*    pAttachments
152         1u,                                        // uint32_t                            subpassCount
153         &subpassDescription,                       // const VkSubpassDescription*        pSubpasses
154         0u,                                        // uint32_t                            dependencyCount
155         DE_NULL                                    // const VkSubpassDependency*        pDependencies
156     };
157 
158     return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
159 }
160 
161 struct TestParams
162 {
TestParamsvkt::pipeline::__anon6ccf44290111::TestParams163     TestParams(const PipelineConstructionType pipelineConstructionType, const TestType testType,
164                const bool useCompShader, const tcu::IVec2 framebufferSize, const uint32_t descCount)
165         : m_pipelineConstructionType(pipelineConstructionType)
166         , m_testType(testType)
167         , m_useCompShader(useCompShader)
168         , m_framebufferSize(framebufferSize)
169         , m_descCount(descCount)
170     {
171     }
172 
173     const PipelineConstructionType m_pipelineConstructionType;
174     const TestType m_testType;
175     const bool m_useCompShader;
176     const tcu::IVec2 m_framebufferSize;
177     const uint32_t m_descCount;
178 
getDescCountvkt::pipeline::__anon6ccf44290111::TestParams179     uint32_t getDescCount() const
180     {
181         uint32_t descCnt = m_descCount;
182 
183         if (m_testType == TestType::StorageBuffers && m_useCompShader)
184             descCnt = m_descCount - 1u;
185 
186         return descCnt;
187     }
188 };
189 
190 class DescriptorLimitTestInstance : public vkt::TestInstance
191 {
192 public:
DescriptorLimitTestInstance(Context & context,const TestParams & params)193     DescriptorLimitTestInstance(Context &context, const TestParams &params)
194         : vkt::TestInstance(context)
195         , m_params(params)
196     {
197     }
198 
~DescriptorLimitTestInstance()199     ~DescriptorLimitTestInstance()
200     {
201     }
202 
203     virtual tcu::TestStatus iterate(void);
204 
205 private:
206     struct BufferInfo
207     {
208         tcu::Vec4 color;
209     };
210     TestParams m_params;
211 };
212 
iterate(void)213 tcu::TestStatus DescriptorLimitTestInstance::iterate(void)
214 {
215     tcu::TestLog &log                     = m_context.getTestContext().getLog();
216     const InstanceInterface &vki          = m_context.getInstanceInterface();
217     const DeviceInterface &vk             = m_context.getDeviceInterface();
218     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
219     const VkDevice vkDevice               = m_context.getDevice();
220     Allocator &allocator                  = m_context.getDefaultAllocator();
221     const VkQueue queue                   = m_context.getUniversalQueue();
222     const uint32_t queueFamilyIndex       = m_context.getUniversalQueueFamilyIndex();
223     VkFormat colorFormat                  = VK_FORMAT_R8G8B8A8_UNORM;
224 
225     // Pick correct test parameters based on test type
226     const VkShaderStageFlags shaderStageFlags     = m_params.m_useCompShader ?
227                                                         VkShaderStageFlags(VK_SHADER_STAGE_COMPUTE_BIT) :
228                                                         VkShaderStageFlags(VK_SHADER_STAGE_FRAGMENT_BIT);
229     const VkPipelineStageFlags pipelineStageFlags = m_params.m_useCompShader ?
230                                                         VkPipelineStageFlags(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT) :
231                                                         VkPipelineStageFlags(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
232 
233     const VkImageUsageFlags imageFlags =
234         m_params.m_testType == TestType::InputAttachments ?
235             VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
236                               VK_IMAGE_USAGE_TRANSFER_DST_BIT) :
237         m_params.m_testType == TestType::StorageImages ?
238             VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT :
239             VkImageUsageFlags(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
240 
241     const VkImageLayout finalImageLayout =
242         m_params.m_testType == TestType::InputAttachments ? VkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) :
243         m_params.m_testType == TestType::StorageImages    ? VkImageLayout(VK_IMAGE_LAYOUT_GENERAL) :
244                                                             VkImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
245 
246     // Create shaders
247     ShaderWrapper vertexShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0u);
248     ShaderWrapper testedShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("test"), 0u);
249 
250     // Create images
251     const VkImageSubresourceRange colorSubresourceRange =
252         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
253     const Move<VkImage> colorImage(
254         makeImage(vk, vkDevice,
255                   makeImageCreateInfo(m_params.m_framebufferSize, colorFormat,
256                                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
257     const de::MovePtr<Allocation> colorImageAlloc(
258         bindImage(vk, vkDevice, allocator, *colorImage, MemoryRequirement::Any));
259     const Move<VkImageView> colorImageView(
260         makeImageView(vk, vkDevice, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
261 
262     const Move<VkImage> inputImages[2]{
263         (makeImage(vk, vkDevice, makeImageCreateInfo(m_params.m_framebufferSize, colorFormat, imageFlags))),
264         (makeImage(vk, vkDevice, makeImageCreateInfo(m_params.m_framebufferSize, colorFormat, imageFlags)))};
265     const de::MovePtr<Allocation> inputImageAllocs[2]{
266         (bindImage(vk, vkDevice, allocator, *inputImages[0], MemoryRequirement::Any)),
267         (bindImage(vk, vkDevice, allocator, *inputImages[1], MemoryRequirement::Any))};
268     Move<VkImageView> inputImageViews[2]{
269         (makeImageView(vk, vkDevice, *inputImages[0], VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange)),
270         (makeImageView(vk, vkDevice, *inputImages[1], VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange))};
271 
272     std::array<tcu::Vec4, 2> testColors{tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)};
273 
274     const uint32_t descCount = m_params.getDescCount();
275 
276     for (int i = 0; i < 2; i++)
277     {
278         clearColorImage(vk, vkDevice, queue, queueFamilyIndex, inputImages[i].get(), testColors[i],
279                         VK_IMAGE_LAYOUT_UNDEFINED, finalImageLayout, pipelineStageFlags);
280     }
281 
282     std::vector<VkImage> images;
283     std::vector<VkImageView> attachmentImages;
284 
285     // Create Samplers
286     const tcu::Sampler sampler = tcu::Sampler(
287         tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST,
288         tcu::Sampler::NEAREST, 0.0f, true, tcu::Sampler::COMPAREMODE_NONE, 0, tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
289     const tcu::TextureFormat texFormat      = mapVkFormat(colorFormat);
290     const VkSamplerCreateInfo samplerParams = mapSampler(sampler, texFormat);
291 
292     Move<VkSampler> samplers[2] = {createSampler(vk, vkDevice, &samplerParams),
293                                    createSampler(vk, vkDevice, &samplerParams)};
294 
295     // Create buffers
296     const uint32_t bufferElementSize = static_cast<uint32_t>(sizeof(tcu::Vec4));
297 
298     const Move<VkBuffer> uboBuffers[2]{
299         (makeBuffer(vk, vkDevice, bufferElementSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)),
300         (makeBuffer(vk, vkDevice, bufferElementSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT))};
301 
302     const Move<VkBuffer> ssboBuffers[2]{
303         (makeBuffer(vk, vkDevice, bufferElementSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)),
304         (makeBuffer(vk, vkDevice, bufferElementSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))};
305 
306     const Move<VkBuffer> compBufferResult(
307         makeBuffer(vk, vkDevice, bufferElementSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
308 
309     const de::MovePtr<Allocation> uboBufferAllocs[2]{
310         (bindBuffer(vk, vkDevice, allocator, *uboBuffers[0], MemoryRequirement::HostVisible)),
311         (bindBuffer(vk, vkDevice, allocator, *uboBuffers[1], MemoryRequirement::HostVisible))};
312 
313     const de::MovePtr<Allocation> ssboBufferAllocs[2]{
314         (bindBuffer(vk, vkDevice, allocator, *ssboBuffers[0], MemoryRequirement::HostVisible)),
315         (bindBuffer(vk, vkDevice, allocator, *ssboBuffers[1], MemoryRequirement::HostVisible))};
316 
317     const de::MovePtr<Allocation> ssboBufferAllocResult(
318         bindBuffer(vk, vkDevice, allocator, *compBufferResult, MemoryRequirement::HostVisible));
319 
320     // Fill buffers
321     {
322         char *pPosUbos[2] = {static_cast<char *>(uboBufferAllocs[0]->getHostPtr()),
323                              static_cast<char *>(uboBufferAllocs[1]->getHostPtr())};
324 
325         char *pPosSsbos[2] = {static_cast<char *>(ssboBufferAllocs[0]->getHostPtr()),
326                               static_cast<char *>(ssboBufferAllocs[1]->getHostPtr())};
327 
328         char *pPosSsboResult = static_cast<char *>(ssboBufferAllocResult->getHostPtr());
329 
330         *((tcu::Vec4 *)pPosUbos[0]) = testColors[0];
331         *((tcu::Vec4 *)pPosUbos[1]) = testColors[1];
332 
333         flushAlloc(vk, vkDevice, *uboBufferAllocs[0]);
334         flushAlloc(vk, vkDevice, *uboBufferAllocs[1]);
335 
336         *((tcu::Vec4 *)pPosSsbos[0]) = testColors[0];
337         *((tcu::Vec4 *)pPosSsbos[1]) = testColors[1];
338 
339         flushAlloc(vk, vkDevice, *ssboBufferAllocs[0]);
340         flushAlloc(vk, vkDevice, *ssboBufferAllocs[1]);
341 
342         *((tcu::Vec4 *)pPosSsboResult) = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
343 
344         flushAlloc(vk, vkDevice, *ssboBufferAllocResult);
345     }
346 
347     if (m_params.m_testType == TestType::InputAttachments)
348     {
349         for (uint32_t image = 0; image < 2; image++)
350         {
351             images.push_back(*inputImages[image]);
352             attachmentImages.push_back(*inputImageViews[image]);
353         }
354     }
355 
356     images.push_back(*colorImage);
357     attachmentImages.push_back(*colorImageView);
358 
359     // Result image buffer for fragment shader run
360     const VkDeviceSize resultImageBufferSizeBytes =
361         tcu::getPixelSize(mapVkFormat(colorFormat)) * m_params.m_framebufferSize.x() * m_params.m_framebufferSize.y();
362     const Move<VkBuffer> resultImageBuffer(
363         makeBuffer(vk, vkDevice, resultImageBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
364     const de::MovePtr<Allocation> resultImageBufferAlloc(
365         bindBuffer(vk, vkDevice, allocator, *resultImageBuffer, MemoryRequirement::HostVisible));
366 
367     // Create vertex buffer
368     const uint32_t numVertices               = 6;
369     const VkDeviceSize vertexBufferSizeBytes = 256;
370     Move<VkBuffer> vertexBuffer = (makeBuffer(vk, vkDevice, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
371     de::MovePtr<Allocation> vertexBufferAlloc =
372         (bindBuffer(vk, vkDevice, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
373 
374     {
375         tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(vertexBufferAlloc->getHostPtr());
376 
377         pVertices[0] = tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f);
378         pVertices[1] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
379         pVertices[2] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
380         pVertices[3] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
381         pVertices[4] = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
382         pVertices[5] = tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f);
383 
384         flushAlloc(vk, vkDevice, *vertexBufferAlloc);
385     }
386 
387     // Descriptor pool and descriptor set
388     DescriptorPoolBuilder poolBuilder;
389 
390     // If compute pipeline is used for testing something else than SSBOs,
391     // one SSBO descriptor is still needed for writing of the test result.
392     if (m_params.m_testType != TestType::StorageBuffers && m_params.m_useCompShader)
393     {
394         poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
395     }
396 
397     if (m_params.m_testType == TestType::Samplers)
398     {
399         poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descCount);
400     }
401 
402     if (m_params.m_testType == TestType::UniformBuffers)
403     {
404         poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descCount);
405     }
406 
407     if (m_params.m_testType == TestType::StorageBuffers)
408     {
409         // We must be an extra careful here.
410         // Since the result buffer as well the input buffers are allocated from the same descriptor pool
411         // full descriptor count should be used while allocating the pool when compute shader is used.
412         poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_params.m_descCount);
413     }
414 
415     if (m_params.m_testType == TestType::SampledImages)
416     {
417         poolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, descCount);
418     }
419 
420     if (m_params.m_testType == TestType::StorageImages)
421     {
422         poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descCount);
423     }
424 
425     if (m_params.m_testType == TestType::InputAttachments)
426     {
427         poolBuilder.addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, descCount);
428     }
429 
430     const Move<VkDescriptorPool> descriptorPool = poolBuilder.build(
431         vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u + (m_params.m_useCompShader ? 1u : 0u));
432 
433     DescriptorSetLayoutBuilder layoutBuilderAttachments;
434 
435     if (m_params.m_testType == TestType::Samplers)
436     {
437         for (uint32_t i = 0; i < descCount; i++)
438         {
439             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStageFlags);
440         }
441     }
442 
443     if (m_params.m_testType == TestType::UniformBuffers)
444     {
445         for (uint32_t i = 0; i < descCount; i++)
446         {
447             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, shaderStageFlags);
448         }
449     }
450 
451     if (m_params.m_testType == TestType::StorageBuffers)
452     {
453         for (uint32_t i = 0; i < descCount; i++)
454         {
455             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, shaderStageFlags);
456         }
457     }
458 
459     if (m_params.m_testType == TestType::SampledImages)
460     {
461         for (uint32_t i = 0; i < descCount; i++)
462         {
463             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, shaderStageFlags);
464         }
465     }
466 
467     if (m_params.m_testType == TestType::StorageImages)
468     {
469         for (uint32_t i = 0; i < descCount; i++)
470         {
471             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStageFlags);
472         }
473     }
474 
475     if (m_params.m_testType == TestType::InputAttachments)
476     {
477         for (uint32_t i = 0; i < descCount; i++)
478         {
479             layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
480                                                       VK_SHADER_STAGE_FRAGMENT_BIT);
481         }
482     }
483 
484     const Move<VkDescriptorSetLayout> descriptorSetLayout = layoutBuilderAttachments.build(vk, vkDevice);
485     const Move<VkDescriptorSet> descriptorSet =
486         makeDescriptorSet(vk, vkDevice, descriptorPool.get(), descriptorSetLayout.get());
487 
488     DescriptorSetLayoutBuilder layoutBuilderAttachmentsResult;
489 
490     Move<VkDescriptorSetLayout> descriptorSetLayoutResult;
491     Move<VkDescriptorSet> descriptorSetResult;
492 
493     if (m_params.m_useCompShader)
494     {
495         layoutBuilderAttachmentsResult.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
496 
497         descriptorSetLayoutResult = layoutBuilderAttachmentsResult.build(vk, vkDevice);
498         descriptorSetResult = makeDescriptorSet(vk, vkDevice, descriptorPool.get(), descriptorSetLayoutResult.get());
499     }
500 
501     // Setup renderpass and framebuffer.
502     RenderPassWrapper renderPass;
503     if (m_params.m_testType == TestType::InputAttachments)
504         renderPass = (makeRenderPassInputAttachment(vk, vkDevice, m_params.m_pipelineConstructionType, colorFormat));
505     else
506         renderPass = (RenderPassWrapper(m_params.m_pipelineConstructionType, vk, vkDevice, colorFormat));
507 
508     renderPass.createFramebuffer(vk, vkDevice, static_cast<uint32_t>(attachmentImages.size()), images.data(),
509                                  attachmentImages.data(), m_params.m_framebufferSize.x(),
510                                  m_params.m_framebufferSize.y());
511 
512     // Command buffer
513     const Move<VkCommandPool> cmdPool(
514         createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
515     const Move<VkCommandBuffer> cmdBuffer(
516         allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
517 
518     std::vector<VkClearValue> clearColorValues;
519 
520     if (m_params.m_testType == TestType::InputAttachments)
521     {
522         clearColorValues.push_back(defaultClearValue(colorFormat));
523         clearColorValues.push_back(defaultClearValue(colorFormat));
524     }
525 
526     clearColorValues.push_back(defaultClearValue(colorFormat));
527 
528     const VkDeviceSize vertexBufferOffset = 0ull;
529 
530     // Bind buffers
531     const vk::VkDescriptorImageInfo imageInfos[2] = {
532         makeDescriptorImageInfo(*samplers[0], *inputImageViews[0],
533                                 m_params.m_testType == TestType::StorageImages ?
534                                     VK_IMAGE_LAYOUT_GENERAL :
535                                     VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
536         makeDescriptorImageInfo(*samplers[1], *inputImageViews[1],
537                                 m_params.m_testType == TestType::StorageImages ?
538                                     VK_IMAGE_LAYOUT_GENERAL :
539                                     VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)};
540 
541     const vk::VkDescriptorBufferInfo uboInfos[2] = {makeDescriptorBufferInfo(*uboBuffers[0], 0u, bufferElementSize),
542                                                     makeDescriptorBufferInfo(*uboBuffers[1], 0u, bufferElementSize)};
543 
544     const vk::VkDescriptorBufferInfo ssboInfos[2] = {makeDescriptorBufferInfo(*ssboBuffers[0], 0u, bufferElementSize),
545                                                      makeDescriptorBufferInfo(*ssboBuffers[1], 0u, bufferElementSize)};
546 
547     const vk::VkDescriptorBufferInfo ssboInfoResult =
548         makeDescriptorBufferInfo(*compBufferResult, 0u, bufferElementSize);
549 
550     DescriptorSetUpdateBuilder updateBuilder;
551 
552     if (m_params.m_useCompShader)
553     {
554         updateBuilder.writeSingle(*descriptorSetResult, DescriptorSetUpdateBuilder::Location::binding(0u),
555                                   VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboInfoResult);
556     }
557 
558     if (m_params.m_testType == TestType::Samplers)
559     {
560         for (uint32_t bufferID = 0; bufferID < descCount - 1u; bufferID++)
561         {
562             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
563                                       VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfos[0]);
564         }
565 
566         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
567                                   VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfos[1]);
568     }
569 
570     if (m_params.m_testType == TestType::UniformBuffers)
571     {
572         for (uint32_t bufferID = 0; bufferID < descCount - 1u; bufferID++)
573         {
574             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
575                                       VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uboInfos[0]);
576         }
577 
578         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
579                                   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uboInfos[1]);
580     }
581 
582     if (m_params.m_testType == TestType::StorageBuffers)
583     {
584         for (uint32_t bufferID = 0; bufferID < (descCount - 1u); bufferID++)
585         {
586             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
587                                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboInfos[0]);
588         }
589 
590         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
591                                   VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboInfos[1]);
592     }
593 
594     if (m_params.m_testType == TestType::SampledImages)
595     {
596         for (uint32_t bufferID = 0; bufferID < descCount - 1u; bufferID++)
597         {
598             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
599                                       VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfos[0]);
600         }
601 
602         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
603                                   VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfos[1]);
604     }
605 
606     if (m_params.m_testType == TestType::StorageImages)
607     {
608         for (uint32_t bufferID = 0; bufferID < descCount - 1u; bufferID++)
609         {
610             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
611                                       VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfos[0]);
612         }
613 
614         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
615                                   VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfos[1]);
616     }
617 
618     if (m_params.m_testType == TestType::InputAttachments)
619     {
620         for (uint32_t bufferID = 0; bufferID < descCount - 1u; bufferID++)
621         {
622             updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferID),
623                                       VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[0]);
624         }
625 
626         updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descCount - 1u),
627                                   VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[1]);
628     }
629 
630     updateBuilder.update(vk, vkDevice);
631 
632     // Create pipeline layout
633     std::vector<VkDescriptorSetLayout> descSetLayouts = {descriptorSetLayout.get()};
634 
635     if (m_params.m_useCompShader)
636     {
637         descSetLayouts.push_back(descriptorSetLayoutResult.get());
638     }
639 
640     const VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
641         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
642         DE_NULL,                                       // const void* pNext;
643         0u,                                            // VkPipelineLayoutCreateFlags flags;
644         static_cast<uint32_t>(descSetLayouts.size()),  // uint32_t descriptorSetCount;
645         descSetLayouts.data(),                         // const VkDescriptorSetLayout* pSetLayouts;
646         0u,                                            // uint32_t pushConstantRangeCount;
647         DE_NULL                                        // const VkPushDescriptorRange* pPushDescriptorRanges;
648     };
649 
650     const PipelineLayoutWrapper pipelineLayout(m_params.m_pipelineConstructionType, vk, vkDevice, &pipelineLayoutInfo);
651     Move<VkPipeline> computePipeline{};
652     GraphicsPipelineWrapper graphicsPipelineWrapper{
653         vki, vk, physicalDevice, vkDevice, m_context.getDeviceExtensions(), m_params.m_pipelineConstructionType};
654 
655     if (m_params.m_useCompShader)
656     {
657         computePipeline = (makeComputePipeline(vk, vkDevice, pipelineLayout.get(), testedShaderModule.getModule()));
658     }
659     else
660     {
661         const std::vector<VkViewport> viewports{makeViewport(m_params.m_framebufferSize)};
662         const std::vector<VkRect2D> scissors{makeRect2D(m_params.m_framebufferSize)};
663         VkSampleMask sampleMask = 0x1;
664 
665         const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{
666             VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType                            sType
667             DE_NULL,               // const void*                                pNext
668             0u,                    // VkPipelineMultisampleStateCreateFlags    flags
669             VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits                    rasterizationSamples
670             false,                 // VkBool32                                    sampleShadingEnable
671             0.0f,                  // float                                    minSampleShading
672             &sampleMask,           // const VkSampleMask*                        pSampleMask
673             false,                 // VkBool32                                    alphaToCoverageEnable
674             false,                 // VkBool32                                    alphaToOneEnable
675         };
676 
677         graphicsPipelineWrapper.setDefaultDepthStencilState()
678             .setDefaultColorBlendState()
679             .setDefaultRasterizationState()
680             .setupVertexInputState()
681             .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass.get(), 0u,
682                                               vertexShaderModule)
683             .setupFragmentShaderState(pipelineLayout, renderPass.get(), 0u, testedShaderModule, DE_NULL,
684                                       &multisampleStateCreateInfo)
685             .setupFragmentOutputState(renderPass.get(), 0u, DE_NULL, &multisampleStateCreateInfo)
686             .setMonolithicPipelineLayout(pipelineLayout)
687             .buildPipeline();
688     }
689 
690     beginCommandBuffer(vk, *cmdBuffer);
691 
692     if (m_params.m_useCompShader)
693     {
694         const std::vector<VkDescriptorSet> descSets = {descriptorSet.get(), descriptorSetResult.get()};
695 
696         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get());
697         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u,
698                                  static_cast<uint32_t>(descSets.size()), descSets.data(), 0u, DE_NULL);
699         vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
700 
701         const VkMemoryBarrier barrier = {
702             VK_STRUCTURE_TYPE_MEMORY_BARRIER, // sType
703             nullptr,                          // pNext
704             VK_ACCESS_SHADER_WRITE_BIT,       // srcAccessMask
705             VK_ACCESS_HOST_READ_BIT,          // dstAccessMask
706         };
707         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
708                               (VkDependencyFlags)0, 1, &barrier, 0, nullptr, 0, nullptr);
709     }
710     else
711     {
712         renderPass.begin(vk, *cmdBuffer,
713                          makeRect2D(0, 0, m_params.m_framebufferSize.x(), m_params.m_framebufferSize.y()),
714                          static_cast<uint32_t>(clearColorValues.size()), clearColorValues.data());
715         graphicsPipelineWrapper.bind(*cmdBuffer);
716         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
717         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
718                                  &descriptorSet.get(), 0u, DE_NULL);
719         vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
720         renderPass.end(vk, *cmdBuffer);
721         copyImageToBuffer(vk, *cmdBuffer, *colorImage, *resultImageBuffer, m_params.m_framebufferSize,
722                           VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
723     }
724 
725     endCommandBuffer(vk, *cmdBuffer);
726 
727     submitCommandsAndWait(vk, vkDevice, queue, *cmdBuffer);
728 
729     // Check results
730     if (!m_params.m_useCompShader)
731     {
732         invalidateAlloc(vk, vkDevice, *resultImageBufferAlloc);
733 
734         const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), m_params.m_framebufferSize.x(),
735                                                            m_params.m_framebufferSize.y(), 1,
736                                                            resultImageBufferAlloc->getHostPtr());
737         const tcu::TextureLevel referenceTexture =
738             generateColorImage(colorFormat, m_params.m_framebufferSize, testColors[1]);
739 
740         if (!tcu::floatThresholdCompare(log, "Compare color output", "Image result comparison",
741                                         referenceTexture.getAccess(), imagePixelAccess, tcu::Vec4(0.0f),
742                                         tcu::COMPARE_LOG_RESULT))
743             return tcu::TestStatus::fail("Rendered color image is not correct");
744     }
745     else
746     {
747         invalidateAlloc(vk, vkDevice, *ssboBufferAllocResult);
748         const tcu::Vec4 resultValue = *static_cast<tcu::Vec4 *>(ssboBufferAllocResult->getHostPtr());
749 
750         if (!(resultValue == tcu::Vec4(0.0, 1.0, 0.0, 1.0)))
751             return tcu::TestStatus::fail("Result buffer value is not correct");
752     }
753 
754     return tcu::TestStatus::pass("Success");
755 }
756 
757 class DescriptorLimitTest : public vkt::TestCase
758 {
759 public:
DescriptorLimitTest(tcu::TestContext & testContext,const std::string & name,const TestParams & params)760     DescriptorLimitTest(tcu::TestContext &testContext, const std::string &name, const TestParams &params)
761         : TestCase(testContext, name)
762         , m_params(params)
763     {
764     }
765 
~DescriptorLimitTest(void)766     virtual ~DescriptorLimitTest(void)
767     {
768     }
769 
770     virtual void initPrograms(SourceCollections &programCollection) const;
771     virtual void checkSupport(Context &context) const;
772     virtual TestInstance *createInstance(Context &context) const;
773 
774 private:
775     TestParams m_params;
776 };
777 
initPrograms(SourceCollections & sourceCollections) const778 void DescriptorLimitTest::initPrograms(SourceCollections &sourceCollections) const
779 {
780     std::ostringstream testTypeStr;
781     std::ostringstream fragResultStr;
782     std::ostringstream compResultStr;
783     const uint32_t descCount = m_params.getDescCount();
784 
785     if (m_params.m_testType == TestType::Samplers)
786     {
787         testTypeStr << "layout(set = 0, binding = " << descCount - 1u << ") uniform sampler2D texSamplerInput;\n";
788 
789         fragResultStr << "    const vec2 coords = vec2(0, 0);\n"
790                       << "    fragColor = texture(texSamplerInput, coords);\n";
791 
792         compResultStr << "    const vec2 coords = vec2(0, 0);\n"
793                       << "    outputData.color = texture(texSamplerInput, coords);\n";
794     }
795 
796     if (m_params.m_testType == TestType::UniformBuffers)
797     {
798         testTypeStr << "layout(set = 0, binding = " << descCount - 1u << ") uniform uboInput\n"
799                     << "{\n"
800                     << "    vec4 color;\n"
801                     << "} inputData;\n"
802                     << "\n";
803 
804         fragResultStr << "    fragColor = inputData.color;\n";
805         compResultStr << "    outputData.color = inputData.color;\n";
806     }
807 
808     if (m_params.m_testType == TestType::StorageBuffers)
809     {
810         testTypeStr << "layout(set = 0, binding = " << (descCount - 1u) << ") readonly buffer ssboInput\n"
811                     << "{\n"
812                     << "    vec4 color;\n"
813                     << "} inputData;\n"
814                     << "\n";
815 
816         fragResultStr << "    fragColor = inputData.color;\n";
817         compResultStr << "    outputData.color = inputData.color;\n";
818     }
819 
820     if (m_params.m_testType == TestType::SampledImages)
821     {
822         testTypeStr << "#extension GL_EXT_samplerless_texture_functions : enable\n"
823                     << "layout(set = 0, binding = " << descCount - 1u << ") uniform texture2D imageInput;\n";
824 
825         fragResultStr << "    fragColor = texelFetch(imageInput, ivec2(gl_FragCoord.xy), 0);\n";
826         compResultStr << "    const ivec2 coords = ivec2(0, 0);\n"
827                       << "    outputData.color = texelFetch(imageInput, coords, 0);\n";
828     }
829 
830     if (m_params.m_testType == TestType::StorageImages)
831     {
832         testTypeStr << "#extension GL_EXT_samplerless_texture_functions : enable\n"
833                     << "layout(set = 0, binding = " << descCount - 1u << ", rgba8) uniform image2D imageInput;\n";
834 
835         fragResultStr << "    fragColor = imageLoad(imageInput, ivec2(gl_FragCoord.xy));\n";
836         compResultStr << "    const ivec2 coords = ivec2(0, 0);\n"
837                       << "    outputData.color = imageLoad(imageInput, coords);\n";
838     }
839 
840     if (m_params.m_testType == TestType::InputAttachments)
841     {
842         testTypeStr << "layout (input_attachment_index = 1, set = 0, binding = " << descCount - 1u
843                     << ") uniform subpassInput imageInput;\n";
844 
845         fragResultStr << "    fragColor = subpassLoad(imageInput);\n";
846         compResultStr << "    outputData.color = vec4(0.0, 0.0, 0.0, 1.0);\n";
847     }
848 
849     std::ostringstream vertexSrc;
850     vertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
851               << "\n"
852               << "layout(location = 0) in vec4 position;\n"
853               << "\n"
854               << "void main (void)\n"
855               << "{\n"
856               << "    gl_Position = position;\n"
857               << "}\n";
858 
859     sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSrc.str());
860 
861     std::ostringstream testSrc;
862 
863     if (!m_params.m_useCompShader)
864     {
865         testSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
866                 << "\n"
867                 << "layout(location = 0) out vec4 fragColor;\n"
868                 << "\n"
869                 << testTypeStr.str() << "void main (void)\n"
870                 << "{\n"
871                 << fragResultStr.str() << "}\n";
872 
873         sourceCollections.glslSources.add("test") << glu::FragmentSource(testSrc.str());
874     }
875     else
876     {
877         testSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
878                 << "\n"
879                 // Input attachments are not supported by compute shaders.
880                 << (m_params.m_testType != TestType::InputAttachments ? testTypeStr.str() : "")
881                 << "layout(set = 1, binding = 0) buffer ssboOutput\n"
882                 << "{\n"
883                 << "    vec4 color;\n"
884                 << "} outputData;\n"
885                 << "\n"
886                 << "void main (void)\n"
887                 << "{\n"
888                 << compResultStr.str() << "}\n";
889 
890         sourceCollections.glslSources.add("test") << glu::ComputeSource(testSrc.str());
891     }
892 }
893 
checkSupport(Context & context) const894 void DescriptorLimitTest::checkSupport(Context &context) const
895 {
896     const InstanceInterface &vki        = context.getInstanceInterface();
897     const VkPhysicalDevice physDevice   = context.getPhysicalDevice();
898     const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
899 #ifdef CTS_USES_VULKANSC
900     const VkPhysicalDeviceVulkanSC10Properties scProps = getPhysicalDeviceVulkanSC10Properties(vki, physDevice);
901 
902     if (m_params.m_descCount > scProps.maxDescriptorSetLayoutBindings)
903         TCU_THROW(NotSupportedError,
904                   "maxDescriptorSetLayoutBindings (" + std::to_string(scProps.maxDescriptorSetLayoutBindings) + ")");
905 #endif // CTS_USES_VULKANSC
906 
907     // We have to make sure, that we don't bind anything outside of valid descriptor binding locations determined by maxPerStageResources.
908     if (m_params.m_descCount > limits.maxPerStageResources - 1u)
909         TCU_THROW(NotSupportedError, "maxPerStageResources (" + std::to_string(limits.maxPerStageResources) + ")");
910 
911     if (m_params.m_testType == TestType::Samplers)
912     {
913         if (m_params.m_descCount > limits.maxPerStageDescriptorSamplers)
914             TCU_THROW(NotSupportedError,
915                       "maxPerStageDescriptorSamplers (" + std::to_string(limits.maxPerStageDescriptorSamplers) + ")");
916     }
917 
918     if (m_params.m_testType == TestType::UniformBuffers)
919     {
920         if (m_params.m_descCount > limits.maxPerStageDescriptorUniformBuffers)
921             TCU_THROW(NotSupportedError, "maxPerStageDescriptorUniformBuffers (" +
922                                              std::to_string(limits.maxPerStageDescriptorUniformBuffers) + ")");
923     }
924 
925     if (m_params.m_testType == TestType::StorageBuffers)
926     {
927         if (m_params.m_descCount > limits.maxPerStageDescriptorStorageBuffers)
928             TCU_THROW(NotSupportedError, "maxPerStageDescriptorStorageBuffers (" +
929                                              std::to_string(limits.maxPerStageDescriptorStorageBuffers) + ")");
930     }
931 
932     if (m_params.m_testType == TestType::SampledImages)
933     {
934         if (m_params.m_descCount > limits.maxPerStageDescriptorSampledImages)
935             TCU_THROW(NotSupportedError, "maxPerStageDescriptorSampledImages (" +
936                                              std::to_string(limits.maxPerStageDescriptorSampledImages) + ")");
937     }
938 
939     if (m_params.m_testType == TestType::StorageImages)
940     {
941         if (m_params.m_descCount > limits.maxPerStageDescriptorStorageImages)
942             TCU_THROW(NotSupportedError, "maxPerStageDescriptorStorageImages (" +
943                                              std::to_string(limits.maxPerStageDescriptorStorageImages) + ")");
944     }
945 
946     if (m_params.m_testType == TestType::InputAttachments)
947     {
948         if (m_params.m_descCount > limits.maxPerStageDescriptorInputAttachments)
949             TCU_THROW(NotSupportedError, "maxPerStageDescriptorInputAttachments (" +
950                                              std::to_string(limits.maxPerStageDescriptorInputAttachments) + ")");
951     }
952 
953     checkPipelineConstructionRequirements(vki, physDevice, m_params.m_pipelineConstructionType);
954 }
955 
createInstance(Context & context) const956 TestInstance *DescriptorLimitTest::createInstance(Context &context) const
957 {
958     return new DescriptorLimitTestInstance(context, m_params);
959 }
960 
961 } // namespace
962 
createDescriptorLimitsTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)963 tcu::TestCaseGroup *createDescriptorLimitsTests(tcu::TestContext &testCtx,
964                                                 PipelineConstructionType pipelineConstructionType)
965 {
966     de::MovePtr<tcu::TestCaseGroup> descriptorLimitTestGroup(new tcu::TestCaseGroup(testCtx, "descriptor_limits"));
967     const tcu::IVec2 frameBufferSize = tcu::IVec2(32, 32);
968 
969     const std::vector<uint32_t> numDescriptors = {3u,   4u,   5u,    6u,    7u,    8u,    9u,     10u,    11u,
970                                                   12u,  13u,  14u,   15u,   16u,   17u,   18u,    19u,    20u,
971                                                   31u,  32u,  63u,   64u,   100u,  127u,  128u,   199u,   200u,
972                                                   256u, 512u, 1024u, 2048u, 4096u, 8192u, 16384u, 32768u, 65535u};
973 
974     if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
975     {
976         de::MovePtr<tcu::TestCaseGroup> computeShaderGroup(new tcu::TestCaseGroup(testCtx, "compute_shader"));
977 
978         for (const auto &descId : numDescriptors)
979         {
980             const uint32_t testValue = descId;
981 
982             {
983                 TestParams params(pipelineConstructionType, TestType::Samplers, true, frameBufferSize, testValue);
984                 computeShaderGroup->addChild(
985                     new DescriptorLimitTest(testCtx, "samplers_" + std::to_string(testValue), params));
986             }
987 
988             {
989                 TestParams params(pipelineConstructionType, TestType::UniformBuffers, true, frameBufferSize, testValue);
990                 computeShaderGroup->addChild(
991                     new DescriptorLimitTest(testCtx, "uniform_buffers_" + std::to_string(testValue), params));
992             }
993 
994             {
995                 TestParams params(pipelineConstructionType, TestType::StorageBuffers, true, frameBufferSize, testValue);
996                 computeShaderGroup->addChild(
997                     new DescriptorLimitTest(testCtx, "storage_buffers_" + std::to_string(testValue), params));
998             }
999 
1000             {
1001                 TestParams params(pipelineConstructionType, TestType::SampledImages, true, frameBufferSize, testValue);
1002                 computeShaderGroup->addChild(
1003                     new DescriptorLimitTest(testCtx, "sampled_images_" + std::to_string(testValue), params));
1004             }
1005 
1006             {
1007                 TestParams params(pipelineConstructionType, TestType::StorageImages, true, frameBufferSize, testValue);
1008                 computeShaderGroup->addChild(
1009                     new DescriptorLimitTest(testCtx, "storage_images_" + std::to_string(testValue), params));
1010             }
1011         }
1012 
1013         descriptorLimitTestGroup->addChild(computeShaderGroup.release());
1014     }
1015 
1016     de::MovePtr<tcu::TestCaseGroup> fragmentShaderGroup(new tcu::TestCaseGroup(testCtx, "fragment_shader"));
1017 
1018     for (const auto &descId : numDescriptors)
1019     {
1020         const uint32_t testValue = descId;
1021 
1022         {
1023             TestParams params(pipelineConstructionType, TestType::Samplers, false, frameBufferSize, testValue);
1024             fragmentShaderGroup->addChild(
1025                 new DescriptorLimitTest(testCtx, "samplers_" + std::to_string(testValue), params));
1026         }
1027 
1028         {
1029             TestParams params(pipelineConstructionType, TestType::UniformBuffers, false, frameBufferSize, testValue);
1030             fragmentShaderGroup->addChild(
1031                 new DescriptorLimitTest(testCtx, "uniform_buffers_" + std::to_string(testValue), params));
1032         }
1033 
1034         {
1035             TestParams params(pipelineConstructionType, TestType::StorageBuffers, false, frameBufferSize, testValue);
1036             fragmentShaderGroup->addChild(
1037                 new DescriptorLimitTest(testCtx, "storage_buffers_" + std::to_string(testValue), params));
1038         }
1039 
1040         {
1041             TestParams params(pipelineConstructionType, TestType::SampledImages, false, frameBufferSize, testValue);
1042             fragmentShaderGroup->addChild(
1043                 new DescriptorLimitTest(testCtx, "sampled_images_" + std::to_string(testValue), params));
1044         }
1045 
1046         {
1047             TestParams params(pipelineConstructionType, TestType::StorageImages, false, frameBufferSize, testValue);
1048             fragmentShaderGroup->addChild(
1049                 new DescriptorLimitTest(testCtx, "storage_images_" + std::to_string(testValue), params));
1050         }
1051 
1052         if (!vk::isConstructionTypeShaderObject(pipelineConstructionType))
1053         {
1054             TestParams params(pipelineConstructionType, TestType::InputAttachments, false, frameBufferSize, testValue);
1055             fragmentShaderGroup->addChild(
1056                 new DescriptorLimitTest(testCtx, "input_attachments_" + std::to_string(testValue), params));
1057         }
1058     }
1059 
1060     descriptorLimitTestGroup->addChild(fragmentShaderGroup.release());
1061 
1062     return descriptorLimitTestGroup.release();
1063 }
1064 
1065 } // namespace pipeline
1066 } // namespace vkt
1067