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 ¶ms);
~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 ¶ms);
~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 ¶ms)
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 ¶ms)
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