1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 Google 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 Tests for descriptor updates.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktBindingDescriptorUpdateTests.hpp"
25 #ifndef CTS_USES_VULKANSC
26 #include "vktBindingDescriptorUpdateASTests.hpp"
27 #endif // CTS_USES_VULKANSC
28 
29 #include "vktTestCase.hpp"
30 #include "vktTestCaseUtil.hpp"
31 
32 #include "vkRefUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkObjUtil.hpp"
38 #include "vkCmdUtil.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkBarrierUtil.hpp"
41 #include "vkImageWithMemory.hpp"
42 #include "vkBufferWithMemory.hpp"
43 
44 #include "tcuTexture.hpp"
45 #include "tcuTestLog.hpp"
46 
47 #include "deRandom.hpp"
48 
49 #include <string>
50 #include <vector>
51 #include <utility>
52 #include <memory>
53 #include <math.h>
54 
55 namespace vkt
56 {
57 namespace BindingModel
58 {
59 namespace
60 {
61 
62 // Test matches VkPositiveLayerTest.EmptyDescriptorUpdateTest
EmptyDescriptorUpdateCase(Context & context)63 tcu::TestStatus EmptyDescriptorUpdateCase(Context &context)
64 {
65     const vk::DeviceInterface &vki = context.getDeviceInterface();
66     const vk::VkDevice device      = context.getDevice();
67     vk::Allocator &allocator       = context.getDefaultAllocator();
68 
69     // Create layout with two uniform buffer descriptors w/ empty binding between them
70     vk::DescriptorSetLayoutBuilder builder;
71 
72     builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
73     builder.addBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, (vk::VkShaderStageFlags)0, DE_NULL);
74     builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
75 
76     vk::Unique<vk::VkDescriptorSetLayout> layout(builder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0));
77 
78     // Create descriptor pool
79     vk::Unique<vk::VkDescriptorPool> descriptorPool(
80         vk::DescriptorPoolBuilder()
81             .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2)
82             .build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
83 
84     // Create descriptor set
85     const vk::VkDescriptorSetAllocateInfo setAllocateInfo = {
86         vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType                sType
87         DE_NULL,                                            // const void*                    pNext
88         *descriptorPool,                                    // VkDescriptorPool                descriptorPool
89         1,                                                  // uint32_t                        descriptorSetCount
90         &layout.get()                                       // const VkDescriptorSetLayout*    pSetLayouts
91     };
92 
93     vk::Unique<vk::VkDescriptorSet> descriptorSet(allocateDescriptorSet(vki, device, &setAllocateInfo));
94 
95     // Create a buffer to be used for update
96     const vk::VkBufferCreateInfo bufferCreateInfo = {
97         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType        sType
98         DE_NULL,                                  // const void*            pNext
99         (vk::VkBufferCreateFlags)DE_NULL,         // VkBufferCreateFlags    flags
100         256,                                      // VkDeviceSize            size
101         vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,   // VkBufferUsageFlags    usage
102         vk::VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode
103         0,                                        // uint32_t                queueFamilyIndexCount
104         DE_NULL                                   // const uint32_t*        pQueueFamilyIndices
105     };
106 
107     vk::Unique<vk::VkBuffer> buffer(createBuffer(vki, device, &bufferCreateInfo));
108     const vk::VkMemoryRequirements requirements = vk::getBufferMemoryRequirements(vki, device, *buffer);
109     de::MovePtr<vk::Allocation> allocation      = allocator.allocate(requirements, vk::MemoryRequirement::Any);
110 
111     VK_CHECK(vki.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
112 
113     // Only update the descriptor at binding 2
114     const vk::VkDescriptorBufferInfo descriptorInfo = {
115         *buffer,      // VkBuffer        buffer
116         0,            // VkDeviceSize    offset
117         VK_WHOLE_SIZE // VkDeviceSize    range
118     };
119 
120     const vk::VkWriteDescriptorSet descriptorWrite = {
121         vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureTypes                    Type
122         DE_NULL,                                    // const void*                        pNext
123         *descriptorSet,                             // VkDescriptorSet                    dstSet
124         2,                                          // uint32_t                            dstBinding
125         0,                                          // uint32_t                            dstArrayElement
126         1,                                          // uint32_t                            descriptorCount
127         vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,      // VkDescriptorType                    descriptorType
128         DE_NULL,                                    // const VkDescriptorImageInfo*        pImageInfo
129         &descriptorInfo,                            // const VkDescriptorBufferInfo*    pBufferInfo
130         DE_NULL                                     // const VkBufferView*                pTexelBufferView
131     };
132 
133     vki.updateDescriptorSets(device, 1, &descriptorWrite, 0, DE_NULL);
134 
135     // Test should always pass
136     return tcu::TestStatus::pass("Pass");
137 }
138 
createEmptyDescriptorUpdateTests(tcu::TestContext & testCtx)139 tcu::TestCaseGroup *createEmptyDescriptorUpdateTests(tcu::TestContext &testCtx)
140 {
141     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "empty_descriptor"));
142 
143     addFunctionCase(group.get(), "uniform_buffer", EmptyDescriptorUpdateCase);
144 
145     return group.release();
146 }
147 
148 enum class PointerCase
149 {
150     ZERO = 0,
151     ONE,
152     DESTROYED,
153 };
154 
155 struct SamplerlessParams
156 {
157     vk::VkDescriptorType type;
158     PointerCase pointer;
159     uint32_t descriptorSet;
160 };
161 
162 class SamplerlessDescriptorWriteTestCase : public vkt::TestCase
163 {
164 public:
165     SamplerlessDescriptorWriteTestCase(tcu::TestContext &testCtx, const std::string &name,
166                                        const SamplerlessParams &params);
~SamplerlessDescriptorWriteTestCase(void)167     virtual ~SamplerlessDescriptorWriteTestCase(void)
168     {
169     }
170 
171     virtual void initPrograms(vk::SourceCollections &programCollection) const;
172     virtual vkt::TestInstance *createInstance(Context &context) const;
173     virtual void checkSupport(Context &context) const;
174 
175     vk::VkFormatFeatureFlagBits getMainImageFeature(void) const;
176 
177     static const vk::VkFormat kImageFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
178 
179 private:
180     SamplerlessParams m_params;
181 };
182 
183 class SamplerlessDescriptorWriteTestInstance : public vkt::TestInstance
184 {
185 public:
186     SamplerlessDescriptorWriteTestInstance(Context &context, const SamplerlessParams &params);
~SamplerlessDescriptorWriteTestInstance(void)187     virtual ~SamplerlessDescriptorWriteTestInstance(void)
188     {
189     }
190 
191     vk::VkSampler getSamplerHandle(void) const;
192     virtual tcu::TestStatus iterate(void);
193 
194     vk::VkExtent3D getMainImageExtent(void) const;
195     vk::VkImageUsageFlags getMainImageUsage(void) const;
196     vk::VkImageLayout getMainImageShaderLayout(void) const;
197 
198     static const vk::VkFormat kImageFormat = SamplerlessDescriptorWriteTestCase::kImageFormat;
199     static const vk::VkExtent3D kFramebufferExtent;
200     static const vk::VkExtent3D kMinimumExtent;
201     static const tcu::Vec4 kDescriptorColor;
202 
203 private:
204     SamplerlessParams m_params;
205 };
206 
207 const vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::kFramebufferExtent = vk::makeExtent3D(64u, 64u, 1u);
208 const vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::kMinimumExtent     = vk::makeExtent3D(1u, 1u, 1u);
209 const tcu::Vec4 SamplerlessDescriptorWriteTestInstance::kDescriptorColor{0.0f, 1.0f, 0.0f, 1.0f};
210 
SamplerlessDescriptorWriteTestCase(tcu::TestContext & testCtx,const std::string & name,const SamplerlessParams & params)211 SamplerlessDescriptorWriteTestCase::SamplerlessDescriptorWriteTestCase(tcu::TestContext &testCtx,
212                                                                        const std::string &name,
213                                                                        const SamplerlessParams &params)
214     : vkt::TestCase{testCtx, name}
215     , m_params(params)
216 {
217 }
218 
initPrograms(vk::SourceCollections & programCollection) const219 void SamplerlessDescriptorWriteTestCase::initPrograms(vk::SourceCollections &programCollection) const
220 {
221     const std::string vertexShader = "#version 450\n"
222                                      "layout(location=0) in vec4 position;\n"
223                                      "void main() { gl_Position = position; }\n";
224 
225     programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader);
226 
227     std::string descriptorDecl;
228     std::string readOp;
229     std::string extensions;
230 
231     switch (m_params.type)
232     {
233     case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
234         extensions     = "#extension GL_EXT_samplerless_texture_functions : require\n";
235         descriptorDecl = "layout(set=" + std::to_string(m_params.descriptorSet) + ", binding=0) uniform texture2D img;";
236         readOp         = "texelFetch(img, ivec2(0, 0), 0)";
237         break;
238     case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
239         descriptorDecl =
240             "layout(rgba8, set=" + std::to_string(m_params.descriptorSet) + ", binding=0) uniform image2D img;";
241         readOp = "imageLoad(img, ivec2(0, 0))";
242         break;
243     case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
244         descriptorDecl = "layout(input_attachment_index=0, set=" + std::to_string(m_params.descriptorSet) +
245                          ", binding=0) uniform subpassInput img;";
246         readOp = "subpassLoad(img)";
247         break;
248     default:
249         DE_ASSERT(false);
250         break;
251     }
252 
253     std::ostringstream fragmentShader;
254 
255     fragmentShader << "#version 450\n"
256                    << extensions << descriptorDecl << "\n"
257                    << "layout(location = 0) out vec4 color_out;\n"
258                    << "void main()\n"
259                    << "{\n"
260                    << "    color_out = " << readOp << ";\n"
261                    << "}\n";
262 
263     programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentShader.str());
264 }
265 
getMainImageFeature(void) const266 vk::VkFormatFeatureFlagBits SamplerlessDescriptorWriteTestCase::getMainImageFeature(void) const
267 {
268     vk::VkFormatFeatureFlagBits feature = static_cast<vk::VkFormatFeatureFlagBits>(0);
269 
270     switch (m_params.type)
271     {
272     case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
273         feature = vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
274         break;
275     case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
276         feature = vk::VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
277         break;
278     case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
279         feature = vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
280         break;
281     default:
282         DE_ASSERT(false);
283         break;
284     }
285 
286     return feature;
287 }
288 
checkSupport(Context & context) const289 void SamplerlessDescriptorWriteTestCase::checkSupport(Context &context) const
290 {
291     const auto &vki           = context.getInstanceInterface();
292     const auto physicalDevice = context.getPhysicalDevice();
293     const auto mainFeature    = getMainImageFeature();
294 
295     const vk::VkFormatFeatureFlags features =
296         (vk::VK_FORMAT_FEATURE_TRANSFER_DST_BIT |     // For color clearing.
297          vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | // For the separate frame buffer image (uses the same format).
298          mainFeature);
299 
300     const auto props = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
301     if ((props.optimalTilingFeatures & features) != features)
302         TCU_THROW(NotSupportedError, "Image format does not support the required features");
303 }
304 
createInstance(Context & context) const305 vkt::TestInstance *SamplerlessDescriptorWriteTestCase::createInstance(Context &context) const
306 {
307     return new SamplerlessDescriptorWriteTestInstance{context, m_params};
308 }
309 
SamplerlessDescriptorWriteTestInstance(Context & context,const SamplerlessParams & params)310 SamplerlessDescriptorWriteTestInstance::SamplerlessDescriptorWriteTestInstance(Context &context,
311                                                                                const SamplerlessParams &params)
312     : vkt::TestInstance{context}
313     , m_params(params)
314 {
315 }
316 
317 struct DestroyedSampler
318 {
319     vk::VkSampler sampler;
320 
DestroyedSamplervkt::BindingModel::__anonb78fb2740111::DestroyedSampler321     DestroyedSampler(Context &context) : sampler{DE_NULL}
322     {
323         const vk::VkSamplerCreateInfo createInfo = {
324             vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // VkStructureType sType;
325             nullptr,                                     // const void* pNext;
326             0u,                                          // VkSamplerCreateFlags flags;
327             vk::VK_FILTER_NEAREST,                       // VkFilter magFilter;
328             vk::VK_FILTER_NEAREST,                       // VkFilter minFilter;
329             vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,          // VkSamplerMipmapMode mipmapMode;
330             vk::VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeU;
331             vk::VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeV;
332             vk::VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeW;
333             0.0f,                                        // float mipLodBias;
334             VK_FALSE,                                    // VkBool32 anisotropyEnable;
335             1.0f,                                        // float maxAnisotropy;
336             VK_FALSE,                                    // VkBool32 compareEnable;
337             vk::VK_COMPARE_OP_NEVER,                     // VkCompareOp compareOp;
338             0.0f,                                        // float minLod;
339             0.0f,                                        // float maxLod;
340             vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
341             VK_FALSE,                                    // VkBool32 unnormalizedCoordinates;
342         };
343         const auto newSampler = vk::createSampler(context.getDeviceInterface(), context.getDevice(), &createInfo);
344         sampler               = newSampler.get();
345         // newSampler will be destroyed here and sampler will hold the former handle.
346     }
347 };
348 
getSamplerHandle(void) const349 vk::VkSampler SamplerlessDescriptorWriteTestInstance::getSamplerHandle(void) const
350 {
351     if (m_params.pointer == PointerCase::ZERO)
352         return vk::VkSampler{DE_NULL};
353     if (m_params.pointer == PointerCase::ONE)
354         return vk::VkSampler{1};
355     DestroyedSampler destroyedSampler{m_context};
356     return destroyedSampler.sampler;
357 }
358 
getMainImageExtent(void) const359 vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::getMainImageExtent(void) const
360 {
361     const vk::VkExtent3D *extent = nullptr;
362 
363     switch (m_params.type)
364     {
365     case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: // fallthrough
366     case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
367         extent = &kMinimumExtent;
368         break;
369     case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
370         extent = &kFramebufferExtent;
371         break;
372     default:
373         DE_ASSERT(false);
374         break;
375     }
376 
377     return *extent;
378 }
379 
getMainImageUsage(void) const380 vk::VkImageUsageFlags SamplerlessDescriptorWriteTestInstance::getMainImageUsage(void) const
381 {
382     vk::VkImageUsageFlags usage = vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT; // Used when clearing the image.
383 
384     switch (m_params.type)
385     {
386     case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
387         usage |= vk::VK_IMAGE_USAGE_SAMPLED_BIT;
388         break;
389     case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
390         usage |= vk::VK_IMAGE_USAGE_STORAGE_BIT;
391         break;
392     case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
393         usage |= vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
394         break;
395     default:
396         DE_ASSERT(false);
397         break;
398     }
399 
400     return usage;
401 }
402 
getMainImageShaderLayout(void) const403 vk::VkImageLayout SamplerlessDescriptorWriteTestInstance::getMainImageShaderLayout(void) const
404 {
405     vk::VkImageLayout layout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
406 
407     switch (m_params.type)
408     {
409     case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: // fallthrough
410     case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
411         layout = vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
412         break;
413     case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
414         layout = vk::VK_IMAGE_LAYOUT_GENERAL;
415         break;
416     default:
417         DE_ASSERT(false);
418         break;
419     }
420 
421     return layout;
422 }
423 
iterate(void)424 tcu::TestStatus SamplerlessDescriptorWriteTestInstance::iterate(void)
425 {
426     const auto &vkd       = m_context.getDeviceInterface();
427     const auto device     = m_context.getDevice();
428     auto &allocator       = m_context.getDefaultAllocator();
429     const auto queue      = m_context.getUniversalQueue();
430     const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
431     const auto tcuFormat  = vk::mapVkFormat(kImageFormat);
432 
433     const vk::VkImageCreateInfo mainImgCreateInfo = {
434         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
435         nullptr,                                 // const void* pNext;
436         0u,                                      // VkImageCreateFlags flags;
437         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
438         kImageFormat,                            // VkFormat format;
439         getMainImageExtent(),                    // VkExtent3D extent;
440         1u,                                      // uint32_t mipLevels;
441         1u,                                      // uint32_t arrayLayers;
442         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
443         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
444         getMainImageUsage(),                     // VkImageUsageFlags usage;
445         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
446         1u,                                      // uint32_t queueFamilyIndexCount;
447         &queueIndex,                             // const uint32_t* pQueueFamilyIndices;
448         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
449     };
450 
451     const vk::VkImageCreateInfo fbImgCreateInfo = {
452         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,   // VkStructureType sType;
453         nullptr,                                   // const void* pNext;
454         0u,                                        // VkImageCreateFlags flags;
455         vk::VK_IMAGE_TYPE_2D,                      // VkImageType imageType;
456         kImageFormat,                              // VkFormat format;
457         kFramebufferExtent,                        // VkExtent3D extent;
458         1u,                                        // uint32_t mipLevels;
459         1u,                                        // uint32_t arrayLayers;
460         vk::VK_SAMPLE_COUNT_1_BIT,                 // VkSampleCountFlagBits samples;
461         vk::VK_IMAGE_TILING_OPTIMAL,               // VkImageTiling tiling;
462         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | // VkImageUsageFlags usage;
463          vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT),     // Used when verifying the image.
464         vk::VK_SHARING_MODE_EXCLUSIVE,             // VkSharingMode sharingMode;
465         1u,                                        // uint32_t queueFamilyIndexCount;
466         &queueIndex,                               // const uint32_t* pQueueFamilyIndices;
467         vk::VK_IMAGE_LAYOUT_UNDEFINED,             // VkImageLayout initialLayout;
468     };
469 
470     // Create main and framebuffer images.
471     const vk::ImageWithMemory mainImage{vkd, device, allocator, mainImgCreateInfo, vk::MemoryRequirement::Any};
472     const vk::ImageWithMemory fbImage{vkd, device, allocator, fbImgCreateInfo, vk::MemoryRequirement::Any};
473 
474     // Corresponding image views.
475     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
476     const auto mainView =
477         vk::makeImageView(vkd, device, mainImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, colorSubresourceRange);
478     const auto fbView =
479         vk::makeImageView(vkd, device, fbImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, colorSubresourceRange);
480 
481     // Buffer to copy rendering result to.
482     const vk::VkDeviceSize resultsBufferSize =
483         static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * kFramebufferExtent.width *
484                                       kFramebufferExtent.height * kFramebufferExtent.depth);
485     const auto resultsBufferInfo = vk::makeBufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
486     const vk::BufferWithMemory resultsBuffer{vkd, device, allocator, resultsBufferInfo,
487                                              vk::MemoryRequirement::HostVisible};
488 
489     const std::vector<tcu::Vec4> fullScreenQuad = {
490         {-1.f, -1.f, 0.f, 1.f}, {1.f, -1.f, 0.f, 1.f}, {-1.f, 1.f, 0.f, 1.f},
491         {-1.f, 1.f, 0.f, 1.f},  {1.f, -1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 1.f},
492     };
493 
494     // Vertex buffer.
495     const vk::VkDeviceSize vertexBufferSize =
496         static_cast<vk::VkDeviceSize>(fullScreenQuad.size() * sizeof(decltype(fullScreenQuad)::value_type));
497     const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
498     const vk::BufferWithMemory vertexBuffer{vkd, device, allocator, vertexBufferInfo,
499                                             vk::MemoryRequirement::HostVisible};
500 
501     // Copy data to vertex buffer.
502     const auto &vertexAlloc  = vertexBuffer.getAllocation();
503     const auto vertexDataPtr = reinterpret_cast<char *>(vertexAlloc.getHostPtr()) + vertexAlloc.getOffset();
504     deMemcpy(vertexDataPtr, fullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
505     vk::flushAlloc(vkd, device, vertexAlloc);
506 
507     // Descriptor set layouts.
508     vk::DescriptorSetLayoutBuilder layoutBuilder;
509     std::vector<vk::Move<vk::VkDescriptorSetLayout>> descriptorSetLayouts;
510     // Create layouts for required amount of empty descriptor sets before the one that is actually used.
511     for (uint32_t descIdx = 0u; descIdx < m_params.descriptorSet; descIdx++)
512     {
513         descriptorSetLayouts.push_back(layoutBuilder.build(vkd, device));
514     }
515     // Create a layout for the descriptor set that is actually used.
516     layoutBuilder.addSingleBinding(m_params.type, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
517     descriptorSetLayouts.push_back(layoutBuilder.build(vkd, device));
518 
519     // Descriptor pool.
520     vk::DescriptorPoolBuilder poolBuilder;
521     poolBuilder.addType(m_params.type);
522     const auto descriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
523                                                   m_params.descriptorSet + 1);
524 
525     // Descriptor sets.
526     std::vector<vk::Move<vk::VkDescriptorSet>> descriptorSets;
527     for (uint32_t descIdx = 0u; descIdx < m_params.descriptorSet; descIdx++)
528     {
529         descriptorSets.push_back(
530             vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayouts[descIdx].get()));
531     }
532     descriptorSets.push_back(
533         vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayouts[m_params.descriptorSet].get()));
534 
535     // Update descriptor set with the descriptor.
536     // IMPORTANT: the chosen sampler handle is used here.
537     vk::DescriptorSetUpdateBuilder updateBuilder;
538     const auto descriptorImageInfo =
539         vk::makeDescriptorImageInfo(getSamplerHandle(), mainView.get(), getMainImageShaderLayout());
540     updateBuilder.writeSingle(descriptorSets[m_params.descriptorSet].get(),
541                               vk::DescriptorSetUpdateBuilder::Location::binding(0u), m_params.type,
542                               &descriptorImageInfo);
543     updateBuilder.update(vkd, device);
544 
545     // Shader modules.
546     const auto vertexModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
547     const auto fragModule   = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
548 
549     // Render pass.
550     const vk::VkAttachmentDescription fbAttachment = {
551         0u,                                           // VkAttachmentDescriptionFlags flags;
552         kImageFormat,                                 // VkFormat format;
553         vk::VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
554         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
555         vk::VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
556         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
557         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
558         vk::VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
559         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
560     };
561 
562     std::vector<vk::VkAttachmentDescription> attachmentDescs;
563     attachmentDescs.push_back(fbAttachment);
564 
565     if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
566     {
567         // Add it as a frame buffer attachment.
568         const vk::VkAttachmentDescription inputAttachment = {
569             0u,                                   // VkAttachmentDescriptionFlags flags;
570             kImageFormat,                         // VkFormat format;
571             vk::VK_SAMPLE_COUNT_1_BIT,            // VkSampleCountFlagBits samples;
572             vk::VK_ATTACHMENT_LOAD_OP_LOAD,       // VkAttachmentLoadOp loadOp;
573             vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
574             vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp stencilLoadOp;
575             vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
576             getMainImageShaderLayout(),           // VkImageLayout initialLayout;
577             getMainImageShaderLayout(),           // VkImageLayout finalLayout;
578         };
579 
580         attachmentDescs.push_back(inputAttachment);
581     }
582 
583     std::vector<vk::VkAttachmentReference> inputAttachments;
584     if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
585     {
586         const vk::VkAttachmentReference inputRef = {
587             1u,                         // uint32_t attachment;
588             getMainImageShaderLayout(), // VkImageLayout layout;
589         };
590 
591         inputAttachments.push_back(inputRef);
592     }
593 
594     const vk::VkAttachmentReference colorRef = {
595         0u,                                           // uint32_t attachment;
596         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
597     };
598     const std::vector<vk::VkAttachmentReference> colorAttachments(1u, colorRef);
599 
600     const vk::VkSubpassDescription subpass = {
601         0u,                                             // VkSubpassDescriptionFlags flags;
602         vk::VK_PIPELINE_BIND_POINT_GRAPHICS,            // VkPipelineBindPoint pipelineBindPoint;
603         static_cast<uint32_t>(inputAttachments.size()), // uint32_t inputAttachmentCount;
604         (inputAttachments.empty() ? nullptr :
605                                     inputAttachments.data()), // const VkAttachmentReference* pInputAttachments;
606         static_cast<uint32_t>(colorAttachments.size()),       // uint32_t colorAttachmentCount;
607         colorAttachments.data(),                              // const VkAttachmentReference* pColorAttachments;
608         0u,                                                   // const VkAttachmentReference* pResolveAttachments;
609         nullptr,                                              // const VkAttachmentReference* pDepthStencilAttachment;
610         0u,                                                   // uint32_t preserveAttachmentCount;
611         nullptr,                                              // const uint32_t* pPreserveAttachments;
612     };
613     const std::vector<vk::VkSubpassDescription> subpasses(1u, subpass);
614 
615     const vk::VkRenderPassCreateInfo renderPassInfo = {
616         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
617         nullptr,                                       // const void* pNext;
618         0u,                                            // VkRenderPassCreateFlags flags;
619         static_cast<uint32_t>(attachmentDescs.size()), // uint32_t attachmentCount;
620         attachmentDescs.data(),                        // const VkAttachmentDescription* pAttachments;
621         static_cast<uint32_t>(subpasses.size()),       // uint32_t subpassCount;
622         subpasses.data(),                              // const VkSubpassDescription* pSubpasses;
623         0u,                                            // uint32_t dependencyCount;
624         nullptr,                                       // const VkSubpassDependency* pDependencies;
625     };
626     const auto renderPass = vk::createRenderPass(vkd, device, &renderPassInfo);
627 
628     // Framebuffer.
629     std::vector<vk::VkImageView> attachments;
630     attachments.push_back(fbView.get());
631     if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
632         attachments.push_back(mainView.get());
633     const auto framebuffer = vk::makeFramebuffer(
634         vkd, device, renderPass.get(), static_cast<uint32_t>(attachments.size()), attachments.data(),
635         kFramebufferExtent.width, kFramebufferExtent.height, kFramebufferExtent.depth);
636 
637     // Pipeline layout.
638     const auto pipelineLayout = vk::makePipelineLayout(vkd, device, descriptorSetLayouts);
639 
640     // Graphics pipeline.
641     const std::vector<vk::VkViewport> viewports(1u, vk::makeViewport(kFramebufferExtent));
642     const std::vector<vk::VkRect2D> scissors(1u, vk::makeRect2D(kFramebufferExtent));
643 
644     const auto pipeline =
645         vk::makeGraphicsPipeline(vkd, device, pipelineLayout.get(), vertexModule.get(), DE_NULL, DE_NULL, DE_NULL,
646                                  fragModule.get(), renderPass.get(), viewports, scissors);
647 
648     // Command pool and command buffer.
649     const auto cmdPool =
650         vk::createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueIndex);
651     const auto cmdBufferPtr =
652         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
653     const auto cmdBuffer = cmdBufferPtr.get();
654 
655     // Draw quad.
656     const vk::VkRect2D renderArea = vk::makeRect2D(kFramebufferExtent);
657     const tcu::Vec4 clearFbColor(0.0f, 0.0f, 0.0f, 1.0f);
658     const vk::VkDeviceSize vertexBufferOffset = 0ull;
659 
660     const auto vtxBufferBarrier =
661         vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
662                                     vertexBuffer.get(), 0ull, vertexBufferSize);
663     const auto preClearBarrier =
664         vk::makeImageMemoryBarrier(0u, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED,
665                                    vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mainImage.get(), colorSubresourceRange);
666     const auto postClearBarrier = vk::makeImageMemoryBarrier(
667         vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
668         vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, getMainImageShaderLayout(), mainImage.get(), colorSubresourceRange);
669     const auto clearDescColor = vk::makeClearValueColor(kDescriptorColor);
670 
671     vk::beginCommandBuffer(vkd, cmdBuffer);
672 
673     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0u, 0u,
674                            nullptr, 1u, &vtxBufferBarrier, 0u, nullptr);
675     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
676                            nullptr, 0u, nullptr, 1u, &preClearBarrier);
677     vkd.cmdClearColorImage(cmdBuffer, mainImage.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDescColor.color,
678                            1u, &colorSubresourceRange);
679     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
680                            vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
681                                vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
682                            0u, 0u, nullptr, 0u, nullptr, 1u, &postClearBarrier);
683 
684     vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea, clearFbColor);
685     vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
686     vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(),
687                               m_params.descriptorSet, 1u, &descriptorSets[m_params.descriptorSet].get(), 0u, nullptr);
688     vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
689     vkd.cmdDraw(cmdBuffer, static_cast<uint32_t>(fullScreenQuad.size()), 1u, 0u, 0u);
690     vk::endRenderPass(vkd, cmdBuffer);
691 
692     const tcu::IVec2 copySize{static_cast<int>(kFramebufferExtent.width), static_cast<int>(kFramebufferExtent.height)};
693     vk::copyImageToBuffer(vkd, cmdBuffer, fbImage.get(), resultsBuffer.get(), copySize);
694 
695     vk::endCommandBuffer(vkd, cmdBuffer);
696     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
697     m_context.resetCommandPoolForVKSC(device, *cmdPool);
698 
699     // Check results.
700     const auto &resultsBufferAlloc = resultsBuffer.getAllocation();
701     vk::invalidateAlloc(vkd, device, resultsBufferAlloc);
702 
703     const auto resultsBufferPtr =
704         reinterpret_cast<const char *>(resultsBufferAlloc.getHostPtr()) + resultsBufferAlloc.getOffset();
705     const tcu::ConstPixelBufferAccess resultPixels{tcuFormat, copySize[0], copySize[1], 1, resultsBufferPtr};
706 
707     bool pass = true;
708     for (int x = 0; pass && x < resultPixels.getWidth(); ++x)
709         for (int y = 0; pass && y < resultPixels.getHeight(); ++y)
710             for (int z = 0; pass && z < resultPixels.getDepth(); ++z)
711             {
712                 const auto pixel = resultPixels.getPixel(x, y, z);
713                 pass             = (pixel == kDescriptorColor);
714             }
715 
716     tcu::TestStatus status = tcu::TestStatus::pass("Pass");
717     if (!pass)
718     {
719         auto &log = m_context.getTestContext().getLog();
720         log << tcu::TestLog::Image("color", "Rendered image", resultPixels);
721         status = tcu::TestStatus::fail("Pixel mismatch; please check the rendered image");
722     }
723 
724     return status;
725 }
726 
createSamplerlessWriteTests(tcu::TestContext & testCtx)727 tcu::TestCaseGroup *createSamplerlessWriteTests(tcu::TestContext &testCtx)
728 {
729     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "samplerless"));
730 
731     const std::vector<std::pair<vk::VkDescriptorType, std::string>> descriptorTypes = {
732         std::make_pair(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_img"),
733         std::make_pair(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_img"),
734         std::make_pair(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment"),
735     };
736 
737     const std::vector<std::pair<PointerCase, std::string>> pointerCases = {
738         std::make_pair(PointerCase::ZERO, "sampler_zero"),
739         std::make_pair(PointerCase::ONE, "sampler_one"),
740         std::make_pair(PointerCase::DESTROYED, "sampler_destroyed"),
741     };
742 
743     for (const auto &typeCase : descriptorTypes)
744         for (const auto &pointerCase : pointerCases)
745             for (uint32_t descriptorSet = 0u; descriptorSet < 2u; descriptorSet++)
746             {
747                 std::string caseName = typeCase.second + "_" + pointerCase.second;
748                 SamplerlessParams params{typeCase.first, pointerCase.first, descriptorSet};
749                 if (descriptorSet > 0u)
750                 {
751                     caseName += "_set_" + std::to_string(descriptorSet);
752                 }
753 
754                 group->addChild(new SamplerlessDescriptorWriteTestCase(testCtx, caseName, params));
755             }
756 
757     return group.release();
758 }
759 
760 class RandomDescriptorUpdateTestCase : public vkt::TestCase
761 {
762 public:
763     RandomDescriptorUpdateTestCase(tcu::TestContext &testCtx, const std::string &name);
~RandomDescriptorUpdateTestCase(void)764     virtual ~RandomDescriptorUpdateTestCase(void)
765     {
766     }
767 
768     virtual void initPrograms(vk::SourceCollections &programCollection) const;
769     virtual vkt::TestInstance *createInstance(Context &context) const;
770 
771 private:
772 };
773 
774 class RandomDescriptorUpdateTestInstance : public vkt::TestInstance
775 {
776 public:
777     RandomDescriptorUpdateTestInstance(Context &context);
~RandomDescriptorUpdateTestInstance(void)778     virtual ~RandomDescriptorUpdateTestInstance(void)
779     {
780     }
781 
782     virtual tcu::TestStatus iterate(void);
783 
784     static const vk::VkExtent3D kFramebufferExtent;
785     static const vk::VkFormat kImageFormat;
786     static const uint32_t kNumBuffers;
787     static const uint32_t kNumOffsets;
788     static const uint32_t kNumIterations;
789 
790 private:
791     deRandom m_random;
792 };
793 
794 const vk::VkExtent3D RandomDescriptorUpdateTestInstance::kFramebufferExtent = vk::makeExtent3D(64u, 64u, 1u);
795 const vk::VkFormat RandomDescriptorUpdateTestInstance::kImageFormat         = vk::VK_FORMAT_R16G16B16A16_SFLOAT;
796 const uint32_t RandomDescriptorUpdateTestInstance::kNumBuffers              = 3u;
797 const uint32_t RandomDescriptorUpdateTestInstance::kNumOffsets              = 5u;
798 const uint32_t RandomDescriptorUpdateTestInstance::kNumIterations           = 1000u;
799 
RandomDescriptorUpdateTestCase(tcu::TestContext & testCtx,const std::string & name)800 RandomDescriptorUpdateTestCase::RandomDescriptorUpdateTestCase(tcu::TestContext &testCtx, const std::string &name)
801     : vkt::TestCase(testCtx, name)
802 {
803 }
804 
initPrograms(vk::SourceCollections & programCollection) const805 void RandomDescriptorUpdateTestCase::initPrograms(vk::SourceCollections &programCollection) const
806 {
807     const std::string vertexShader = "#version 450\n"
808                                      "layout(location=0) in vec4 position;\n"
809                                      "void main() { gl_Position = position; }\n";
810 
811     programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader);
812 
813     std::ostringstream fragmentShader;
814 
815     fragmentShader << "#version 450\n"
816                    << "layout(location = 0) out vec4 color_out;\n"
817                    << "layout(set = 0, binding = 0) uniform buf\n"
818                    << "{\n"
819                    << "    vec4 data0;\n"
820                    << "    vec4 data1;\n"
821                    << "};\n"
822                    << "void main()\n"
823                    << "{\n"
824                    << "    color_out = data0 + data1;\n"
825                    << "}\n";
826 
827     programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentShader.str());
828 }
829 
createInstance(Context & context) const830 vkt::TestInstance *RandomDescriptorUpdateTestCase::createInstance(Context &context) const
831 {
832     return new RandomDescriptorUpdateTestInstance(context);
833 }
834 
RandomDescriptorUpdateTestInstance(Context & context)835 RandomDescriptorUpdateTestInstance::RandomDescriptorUpdateTestInstance(Context &context) : vkt::TestInstance(context)
836 {
837     deRandom_init(&m_random, 0);
838 }
839 
iterate()840 tcu::TestStatus RandomDescriptorUpdateTestInstance::iterate()
841 {
842     const auto &vkd       = m_context.getDeviceInterface();
843     const auto device     = m_context.getDevice();
844     auto &allocator       = m_context.getDefaultAllocator();
845     const auto queue      = m_context.getUniversalQueue();
846     const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
847     const auto tcuFormat  = vk::mapVkFormat(kImageFormat);
848     vk::DescriptorSetLayoutBuilder builder;
849 
850     builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
851 
852     vk::Unique<vk::VkDescriptorSetLayout> layout(builder.build(vkd, device, (vk::VkDescriptorSetLayoutCreateFlags)0));
853 
854     // Create descriptor pool
855     vk::Unique<vk::VkDescriptorPool> descriptorPool(
856         vk::DescriptorPoolBuilder()
857             .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
858             .build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
859 
860     // Create descriptor set
861     const vk::VkDescriptorSetAllocateInfo setAllocateInfo = {
862         vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType                sType
863         DE_NULL,                                            // const void*                    pNext
864         *descriptorPool,                                    // VkDescriptorPool                descriptorPool
865         1u,                                                 // uint32_t                        descriptorSetCount
866         &layout.get()                                       // const VkDescriptorSetLayout*    pSetLayouts
867     };
868 
869     vk::Unique<vk::VkDescriptorSet> descriptorSet(allocateDescriptorSet(vkd, device, &setAllocateInfo));
870 
871     // The maximum allowed buffer offset alignment is 256 bytes. Meaningful data is placed at these offsets.
872     const uint32_t bufferSize = 256u * kNumOffsets;
873 
874     float bufferContents[kNumBuffers][bufferSize / 4];
875     float counter            = 1.0f;
876     float sign               = 1.0f;
877     uint32_t offset          = 0;
878     uint32_t channelSelector = 0;
879 
880     // The buffers are filled with a running counter in one of the channels.
881     // Both signed and unsigned values are used for each counter. Two vec4s
882     // are initialized at offsets of 256 bytes (the maximum allowed alignment).
883     // Everythin else is left as zero.
884     for (uint32_t b = 0; b < kNumBuffers; b++)
885     {
886         deMemset(bufferContents[b], 0, bufferSize);
887 
888         for (uint32_t o = 0; o < kNumOffsets; o++)
889         {
890             offset = o * 64;
891 
892             // Two vectors at every offset.
893             for (uint32_t v = 0; v < 2; v++)
894             {
895                 // Only RGB channels are being tested.
896                 for (uint32_t c = 0; c < 3; c++)
897                 {
898                     if (c == channelSelector)
899                     {
900                         bufferContents[b][offset++] = sign * counter;
901                     }
902                     else
903                     {
904                         bufferContents[b][offset++] = 0.0f;
905                     }
906                 }
907                 // Keep alpha at one.
908                 bufferContents[b][offset++] = 1.0f;
909 
910                 channelSelector = channelSelector + 1;
911 
912                 // All three channels have been filled in. Switch a sign or increase the counter.
913                 if (channelSelector == 3)
914                 {
915                     channelSelector = 0;
916                     if (sign == 1.0f)
917                     {
918                         sign = -1.0f;
919                     }
920                     else
921                     {
922                         sign = 1.0f;
923                         counter += 1.0f;
924                     }
925                 }
926             }
927         }
928     }
929 
930     const auto bufferInfo = vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
931     std::vector<std::shared_ptr<vk::BufferWithMemory>> buffers;
932 
933     for (const auto &contents : bufferContents)
934     {
935         buffers.emplace_back(std::make_shared<vk::BufferWithMemory>(vkd, device, allocator, bufferInfo,
936                                                                     vk::MemoryRequirement::HostVisible));
937         const auto &bufferAlloc = buffers.back()->getAllocation();
938         const auto bufferPtr    = reinterpret_cast<char *>(bufferAlloc.getHostPtr()) + bufferAlloc.getOffset();
939         deMemcpy(bufferPtr, contents, bufferSize);
940         vk::flushAlloc(vkd, device, bufferAlloc);
941     }
942 
943     // Create framebuffer image and view.
944     const vk::VkImageCreateInfo fbImgCreateInfo = {
945         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,   // VkStructureType            sType
946         DE_NULL,                                   // const void*                pNext
947         0u,                                        // VkImageCreateFlags        flags
948         vk::VK_IMAGE_TYPE_2D,                      // VkImageType                imageType
949         kImageFormat,                              // VkFormat                    format
950         kFramebufferExtent,                        // VkExtent3D                extent
951         1u,                                        // uint32_t                    mipLevels
952         1u,                                        // uint32_t                    arrayLayers
953         vk::VK_SAMPLE_COUNT_1_BIT,                 // VkSampleCountFlagBits    samples
954         vk::VK_IMAGE_TILING_OPTIMAL,               // VkImageTiling            tiling
955         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | // VkImageUsageFlags        usage
956          vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
957         vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode            sharingMode
958         1u,                            // uint32_t                    queueFamilyIndexCount
959         &queueIndex,                   // const uint32_t*            pQueueFamilyIndices
960         vk::VK_IMAGE_LAYOUT_UNDEFINED  // VkImageLayout            initialLayout
961     };
962 
963     const vk::ImageWithMemory fbImage(vkd, device, allocator, fbImgCreateInfo, vk::MemoryRequirement::Any);
964     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
965     const auto fbView =
966         vk::makeImageView(vkd, device, fbImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, colorSubresourceRange);
967 
968     // Buffer to copy rendering result to.
969     const vk::VkDeviceSize resultsBufferSize =
970         static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * kFramebufferExtent.width *
971                                       kFramebufferExtent.height * kFramebufferExtent.depth);
972     const auto resultsBufferInfo = vk::makeBufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
973     const vk::BufferWithMemory resultsBuffer(vkd, device, allocator, resultsBufferInfo,
974                                              vk::MemoryRequirement::HostVisible);
975 
976     const std::vector<tcu::Vec4> fullScreenQuad = {{-1.f, -1.f, 0.f, 1.f}, {1.f, -1.f, 0.f, 1.f}, {-1.f, 1.f, 0.f, 1.f},
977                                                    {-1.f, 1.f, 0.f, 1.f},  {1.f, -1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 1.f}};
978 
979     // Vertex buffer.
980     const vk::VkDeviceSize vertexBufferSize =
981         static_cast<vk::VkDeviceSize>(fullScreenQuad.size() * sizeof(decltype(fullScreenQuad)::value_type));
982     const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
983     const vk::BufferWithMemory vertexBuffer(vkd, device, allocator, vertexBufferInfo,
984                                             vk::MemoryRequirement::HostVisible | vk::MemoryRequirement::Coherent);
985 
986     // Copy data to vertex buffer.
987     const auto &vertexAlloc  = vertexBuffer.getAllocation();
988     const auto vertexDataPtr = reinterpret_cast<char *>(vertexAlloc.getHostPtr()) + vertexAlloc.getOffset();
989     deMemcpy(vertexDataPtr, fullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
990     vk::flushAlloc(vkd, device, vertexAlloc);
991 
992     // Shader modules.
993     const auto vertexModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
994     const auto fragModule   = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
995 
996     // Render pass.
997     const vk::VkAttachmentDescription fbAttachment = {
998         0u,                                           // VkAttachmentDescriptionFlags        flags
999         kImageFormat,                                 // VkFormat                            format
1000         vk::VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits            samples
1001         vk::VK_ATTACHMENT_LOAD_OP_LOAD,               // VkAttachmentLoadOp                loadOp
1002         vk::VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp                storeOp
1003         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp                stencilLoadOp
1004         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp                stencilStoreOp
1005         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                    initialLayout
1006         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL  // VkImageLayout                    finalLayout
1007     };
1008 
1009     std::vector<vk::VkAttachmentDescription> attachmentDescs;
1010     attachmentDescs.push_back(fbAttachment);
1011 
1012     const vk::VkAttachmentReference colorRef = {
1013         0u,                                           // uint32_t            attachment
1014         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout    layout
1015     };
1016     const std::vector<vk::VkAttachmentReference> colorAttachments(1u, colorRef);
1017 
1018     const vk::VkSubpassDescription subpass = {
1019         0u,                                             // VkSubpassDescriptionFlags        flags
1020         vk::VK_PIPELINE_BIND_POINT_GRAPHICS,            // VkPipelineBindPoint                pipelineBindPoint
1021         0u,                                             // uint32_t                            inputAttachmentCount
1022         DE_NULL,                                        // const VkAttachmentReference*        pInputAttachments
1023         static_cast<uint32_t>(colorAttachments.size()), // uint32_t                            colorAttachmentCount
1024         colorAttachments.data(),                        // const VkAttachmentReference*        pColorAttachments
1025         0u,                                             // const VkAttachmentReference*        pResolveAttachments
1026         DE_NULL,                                        // const VkAttachmentReference*        pDepthStencilAttachment
1027         0u,                                             // uint32_t                            preserveAttachmentCount
1028         DE_NULL                                         // const uint32_t*                    pPreserveAttachments
1029     };
1030     const std::vector<vk::VkSubpassDescription> subpasses(1u, subpass);
1031 
1032     const vk::VkRenderPassCreateInfo renderPassInfo = {
1033         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                    sType
1034         DE_NULL,                                       // const void*                        pNext
1035         0u,                                            // VkRenderPassCreateFlags            flags
1036         static_cast<uint32_t>(attachmentDescs.size()), // uint32_t                            attachmentCount
1037         attachmentDescs.data(),                        // const VkAttachmentDescription*    pAttachments
1038         static_cast<uint32_t>(subpasses.size()),       // uint32_t                            subpassCount
1039         subpasses.data(),                              // const VkSubpassDescription*        pSubpasses
1040         0u,                                            // uint32_t                            dependencyCount
1041         DE_NULL,                                       // const VkSubpassDependency*        pDependencies
1042     };
1043     const auto renderPass = vk::createRenderPass(vkd, device, &renderPassInfo);
1044 
1045     // Framebuffer.
1046     std::vector<vk::VkImageView> attachments;
1047     attachments.push_back(fbView.get());
1048     const auto framebuffer = vk::makeFramebuffer(
1049         vkd, device, renderPass.get(), static_cast<uint32_t>(attachments.size()), attachments.data(),
1050         kFramebufferExtent.width, kFramebufferExtent.height, kFramebufferExtent.depth);
1051 
1052     // Pipeline layout.
1053     const auto pipelineLayout = vk::makePipelineLayout(vkd, device, layout.get());
1054 
1055     // Graphics pipeline.
1056     const std::vector<vk::VkViewport> viewports(1u, vk::makeViewport(kFramebufferExtent));
1057     const std::vector<vk::VkRect2D> scissors(1u, vk::makeRect2D(kFramebufferExtent));
1058 
1059     // Use additive alpha blending to accumulate results from all iterations.
1060     const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1061         VK_TRUE,                     // VkBool32                    blendEnable
1062         vk::VK_BLEND_FACTOR_ONE,     // VkBlendFactor            srcColorBlendFactor
1063         vk::VK_BLEND_FACTOR_ONE,     // VkBlendFactor            dstColorBlendFactor
1064         vk::VK_BLEND_OP_ADD,         // VkBlendOp                colorBlendOp
1065         vk::VK_BLEND_FACTOR_ONE,     // VkBlendFactor            srcAlphaBlendFactor
1066         vk::VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            dstAlphaBlendFactor
1067         vk::VK_BLEND_OP_ADD,         // VkBlendOp                alphaBlendOp
1068         vk::VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags    colorWriteMask
1069             | vk::VK_COLOR_COMPONENT_G_BIT | vk::VK_COLOR_COMPONENT_B_BIT | vk::VK_COLOR_COMPONENT_A_BIT};
1070 
1071     const vk::VkPipelineColorBlendStateCreateInfo colorBlendState = {
1072         vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                                sType
1073         DE_NULL,                    // const void*                                    pNext
1074         0u,                         // VkPipelineColorBlendStateCreateFlags            flags
1075         VK_FALSE,                   // VkBool32                                        logicOpEnable
1076         vk::VK_LOGIC_OP_CLEAR,      // VkLogicOp                                    logicOp
1077         1u,                         // uint32_t                                        attachmentCount
1078         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState*    pAttachments
1079         {1.0f, 1.0f, 1.0f, 1.0f}    // float                                        blendConstants[4]
1080     };
1081 
1082     const auto pipeline = vk::makeGraphicsPipeline(vkd, device, pipelineLayout.get(), vertexModule.get(), DE_NULL,
1083                                                    DE_NULL, DE_NULL, fragModule.get(), renderPass.get(), viewports,
1084                                                    scissors, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, DE_NULL,
1085                                                    DE_NULL, DE_NULL, DE_NULL, &colorBlendState);
1086 
1087     // Command pool and command buffer.
1088     const auto cmdPool =
1089         vk::createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueIndex);
1090     const auto cmdBufferPtr =
1091         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1092     const auto cmdBuffer = cmdBufferPtr.get();
1093 
1094     const vk::VkRect2D renderArea             = vk::makeRect2D(kFramebufferExtent);
1095     const vk::VkDeviceSize vertexBufferOffset = 0ull;
1096 
1097     const auto vtxBufferBarrier =
1098         vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
1099                                     vertexBuffer.get(), 0ull, vertexBufferSize);
1100     const auto fbBarrier =
1101         vk::makeImageMemoryBarrier(0u, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED,
1102                                    vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, fbImage.get(), colorSubresourceRange);
1103 
1104     vk::VkClearValue clearValue;
1105     clearValue.color.float32[0] = 0.0f;
1106     clearValue.color.float32[1] = 0.0f;
1107     clearValue.color.float32[2] = 0.0f;
1108     clearValue.color.float32[3] = 1.0f;
1109 
1110     const vk::VkClearAttachment clearAttachment = {
1111         vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1112         0u,                            // uint32_t                colorAttachment
1113         clearValue                     // VkClearValue            clearValue
1114     };
1115 
1116     const vk::VkClearRect clearRect = {
1117         vk::makeRect2D(kFramebufferExtent), // VkRect2D    rect
1118         0u,                                 // uint32_t    baseArrayLayer
1119         1u                                  // uint32_t    layerCount
1120     };
1121 
1122     vk::beginCommandBuffer(vkd, cmdBuffer);
1123     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0u, 0u,
1124                            DE_NULL, 1u, &vtxBufferBarrier, 0u, DE_NULL);
1125     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1126                            vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
1127                            &fbBarrier);
1128     vk::endCommandBuffer(vkd, cmdBuffer);
1129     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1130     m_context.resetCommandPoolForVKSC(device, *cmdPool);
1131 
1132     struct DescriptorWrite
1133     {
1134         uint32_t bufferId;       // Which buffer to use for the descriptor update.
1135         vk::VkDeviceSize offset; // The offset for the descriptor update.
1136         vk::VkDeviceSize range;  // The range for the descriptor update.
1137     };
1138 
1139     // Each iteration operates on a descriptor mutation which decides the source of the descriptor update.
1140     struct DescriptorMutation
1141     {
1142         bool update;                         // Determines if a descriptor update is performed.
1143         uint32_t numDraws;                   // The number of consecutive draw calls in a loop.
1144         std::vector<DescriptorWrite> writes; // Multiple redundant writes can be performed.
1145                                              // Other ideas to implement:
1146                                              // - Sometimes also update the buffer contents.
1147                                              // - Multiple descriptor sets.
1148     };
1149 
1150     std::vector<DescriptorMutation> descriptorMutations;
1151 
1152     // Keep track of the expected result while generating the mutations.
1153     tcu::Vec4 uboValue0;
1154     tcu::Vec4 uboValue1;
1155     tcu::Vec4 expectedColor(0.0f, 0.0f, 0.0f, 1.0f);
1156     DescriptorWrite descWrite = {0u, 0u, 32u};
1157 
1158     for (uint32_t i = 0; i < kNumIterations; i++)
1159     {
1160         while (true)
1161         {
1162             tcu::Vec4 val0 = uboValue0;
1163             tcu::Vec4 val1 = uboValue1;
1164 
1165             uint32_t numWrites = 1u;
1166 
1167             // Sometimes do redundant descriptor writes.
1168             if (deRandom_getUint32(&m_random) % 10 == 0)
1169                 numWrites = deRandom_getUint32(&m_random) % 20 + 1;
1170 
1171             std::vector<DescriptorWrite> writes;
1172 
1173             for (uint32_t w = 0; w < numWrites; w++)
1174             {
1175                 // The first half: Most of the times change the offset but sometimes the buffer.
1176                 // The second half: Most of the times change the buffer but sometimes change the offset.
1177                 bool firstHalf = i < kNumIterations / 2;
1178                 bool rare      = (deRandom_getUint32(&m_random) % 100u >= (firstHalf ? 98u : 80u));
1179 
1180                 // firstHalf     rare      change
1181                 // --------------------------------
1182                 //     1          0        Offset
1183                 //     1          1        Buffer
1184                 //     0          0        Buffer
1185                 //     0          1        Offset
1186                 //
1187                 // This has a XOR pattern
1188 
1189                 if (firstHalf ^ rare)
1190                     descWrite.offset = (deRandom_getUint32(&m_random) % kNumOffsets) * 256u;
1191                 else
1192                     descWrite.bufferId = deRandom_getUint32(&m_random) % kNumBuffers;
1193 
1194                 writes.push_back(descWrite);
1195             }
1196 
1197             DescriptorMutation mutation = {i == 0 ? true : deRandom_getBool(&m_random),
1198                                            deRandom_getUint32(&m_random) % 10u, writes};
1199 
1200             const auto &lastWrite = mutation.writes.back();
1201             if (mutation.update)
1202             {
1203                 for (int c = 0; c < 3; c++)
1204                 {
1205                     val0[c] = bufferContents[lastWrite.bufferId][lastWrite.offset / 4 + c];
1206                     val1[c] = bufferContents[lastWrite.bufferId][lastWrite.offset / 4 + 4 + c];
1207 
1208                     // Quick check we are reading expected values.
1209                     DE_ASSERT(val0[c] >= -counter && val0[c] <= counter);
1210                     DE_ASSERT(val1[c] >= -counter && val1[c] <= counter);
1211                 }
1212             }
1213 
1214             tcu::Vec4 color = expectedColor + (val0 + val1) * tcu::Vec4(static_cast<float>(mutation.numDraws));
1215 
1216             // 16-bit float can precisely present integers from -2048..2048. Continue randomizing the mutation
1217             // until we stay in this range.
1218             if (color[0] >= -2048.0f && color[0] <= 2048.0f && color[1] >= -2048.0f && color[1] <= 2048.0f &&
1219                 color[2] >= -2048.0f && color[2] <= 2048.0f)
1220             {
1221                 descriptorMutations.push_back(mutation);
1222                 uboValue0     = val0;
1223                 uboValue1     = val1;
1224                 expectedColor = color;
1225                 break;
1226             }
1227             else
1228             {
1229                 // Randomize both buffer and offset for a better chance to hit a
1230                 // mutation that pushes the values back to the desired range.
1231                 descWrite.offset   = (deRandom_getUint32(&m_random) % kNumOffsets) * 256u;
1232                 descWrite.bufferId = deRandom_getUint32(&m_random) % kNumBuffers;
1233             }
1234         }
1235     }
1236 
1237     bool first = true;
1238 
1239     for (auto mutation : descriptorMutations)
1240     {
1241         if (mutation.update)
1242         {
1243             for (const auto &write : mutation.writes)
1244             {
1245                 const vk::VkDescriptorBufferInfo descriptorInfo = {
1246                     buffers[write.bufferId]->get(), // VkBuffer        buffer
1247                     write.offset,                   // VkDeviceSize    offset
1248                     write.range                     // VkDeviceSize    range
1249                 };
1250 
1251                 const vk::VkWriteDescriptorSet descriptorWrite = {
1252                     vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureTypes                    Type
1253                     DE_NULL,                                    // const void*                        pNext
1254                     *descriptorSet,                             // VkDescriptorSet                    dstSet
1255                     0,                                          // uint32_t                            dstBinding
1256                     0,                                          // uint32_t                            dstArrayElement
1257                     1u,                                         // uint32_t                            descriptorCount
1258                     vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,      // VkDescriptorType                    descriptorType
1259                     DE_NULL,                                    // const VkDescriptorImageInfo*        pImageInfo
1260                     &descriptorInfo,                            // const VkDescriptorBufferInfo*    pBufferInfo
1261                     DE_NULL                                     // const VkBufferView*                pTexelBufferView
1262                 };
1263 
1264                 vkd.updateDescriptorSets(device, 1, &descriptorWrite, 0, DE_NULL);
1265             }
1266         }
1267 
1268         vk::beginCommandBuffer(vkd, cmdBuffer);
1269 
1270         vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea);
1271         vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
1272         // Clear the frame buffer during the first iteration.
1273         if (first)
1274         {
1275             vkd.cmdClearAttachments(cmdBuffer, 1u, &clearAttachment, 1u, &clearRect);
1276             first = false;
1277         }
1278         vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u,
1279                                   &descriptorSet.get(), 0u, nullptr);
1280         vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1281 
1282         for (uint32_t i = 0u; i < mutation.numDraws; i++)
1283             vkd.cmdDraw(cmdBuffer, static_cast<uint32_t>(fullScreenQuad.size()), 1u, 0u, 0u);
1284 
1285         vk::endRenderPass(vkd, cmdBuffer);
1286         vk::endCommandBuffer(vkd, cmdBuffer);
1287         vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1288         m_context.resetCommandPoolForVKSC(device, *cmdPool);
1289     }
1290 
1291     vk::beginCommandBuffer(vkd, cmdBuffer);
1292     const tcu::IVec2 copySize{static_cast<int>(kFramebufferExtent.width), static_cast<int>(kFramebufferExtent.height)};
1293     vk::copyImageToBuffer(vkd, cmdBuffer, fbImage.get(), resultsBuffer.get(), copySize);
1294     vk::endCommandBuffer(vkd, cmdBuffer);
1295     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1296     m_context.resetCommandPoolForVKSC(device, *cmdPool);
1297 
1298     // Check results.
1299     const auto &resultsBufferAlloc = resultsBuffer.getAllocation();
1300     vk::invalidateAlloc(vkd, device, resultsBufferAlloc);
1301 
1302     const auto resultsBufferPtr =
1303         reinterpret_cast<const char *>(resultsBufferAlloc.getHostPtr()) + resultsBufferAlloc.getOffset();
1304     const tcu::ConstPixelBufferAccess resultPixels{tcuFormat, copySize[0], copySize[1], 1, resultsBufferPtr};
1305 
1306     // The test only operates on integers, so a tolerance of 0.5 should work.
1307     const float tolerance = 0.5f;
1308 
1309     bool pass = true;
1310     for (int x = 0; pass && x < resultPixels.getWidth(); ++x)
1311         for (int y = 0; pass && y < resultPixels.getHeight(); ++y)
1312             for (int z = 0; pass && z < resultPixels.getDepth(); ++z)
1313             {
1314                 const auto pixel = resultPixels.getPixel(x, y, z);
1315                 for (int c = 0; c < 3; c++)
1316                     if (fabs(pixel[c] - expectedColor[c]) > tolerance)
1317                         pass = false;
1318             }
1319 
1320     tcu::TestStatus status = tcu::TestStatus::pass("Pass");
1321     if (!pass)
1322     {
1323         m_context.getTestContext().getLog() << tcu::TestLog::Image("color", "Rendered image", resultPixels);
1324         status = tcu::TestStatus::fail("Pixel mismatch; please check the rendered image");
1325     }
1326 
1327     return status;
1328 }
1329 
createRandomDescriptorUpdateTests(tcu::TestContext & testCtx)1330 tcu::TestCaseGroup *createRandomDescriptorUpdateTests(tcu::TestContext &testCtx)
1331 {
1332     // Update descriptors randomly between draws
1333     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "random"));
1334 
1335     group->addChild(new RandomDescriptorUpdateTestCase(testCtx, "uniform_buffer"));
1336     return group.release();
1337 }
1338 
1339 } // namespace
1340 
createDescriptorUpdateTests(tcu::TestContext & testCtx)1341 tcu::TestCaseGroup *createDescriptorUpdateTests(tcu::TestContext &testCtx)
1342 {
1343     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "descriptor_update"));
1344 
1345     group->addChild(createEmptyDescriptorUpdateTests(testCtx));
1346     group->addChild(createSamplerlessWriteTests(testCtx));
1347     group->addChild(createRandomDescriptorUpdateTests(testCtx));
1348 #ifndef CTS_USES_VULKANSC
1349     group->addChild(createDescriptorUpdateASTests(testCtx));
1350 #endif // CTS_USES_VULKANSC
1351 
1352     return group.release();
1353 }
1354 
1355 } // namespace BindingModel
1356 } // namespace vkt
1357