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