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