1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group 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 Buffer and image memory requirements tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktMemoryRequirementsTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vktTestGroupUtil.hpp"
27
28 #include "vkDefs.hpp"
29 #include "vkRef.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkTypeUtil.hpp"
35
36 #include "deUniquePtr.hpp"
37 #include "deStringUtil.hpp"
38
39 #include "tcuResultCollector.hpp"
40 #include "tcuTestLog.hpp"
41
42 namespace vkt
43 {
44 namespace memory
45 {
46 namespace
47 {
48 using namespace vk;
49 using de::MovePtr;
50
makeBuffer(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize size,const VkBufferCreateFlags flags,const VkBufferUsageFlags usage)51 Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize size, const VkBufferCreateFlags flags, const VkBufferUsageFlags usage)
52 {
53 const VkBufferCreateInfo createInfo =
54 {
55 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
56 DE_NULL, // const void* pNext;
57 flags, // VkBufferCreateFlags flags;
58 size, // VkDeviceSize size;
59 usage, // VkBufferUsageFlags usage;
60 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
61 0u, // uint32_t queueFamilyIndexCount;
62 DE_NULL, // const uint32_t* pQueueFamilyIndices;
63 };
64 return createBuffer(vk, device, &createInfo);
65 }
66
67 //! Get an index of each set bit, starting from the least significant bit.
bitsToIndices(deUint32 bits)68 std::vector<deUint32> bitsToIndices (deUint32 bits)
69 {
70 std::vector<deUint32> indices;
71 for (deUint32 i = 0u; bits != 0u; ++i, bits >>= 1)
72 {
73 if (bits & 1u)
74 indices.push_back(i);
75 }
76 return indices;
77 }
78
getBufferMemoryRequirements(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize size,const VkBufferCreateFlags flags,const VkBufferUsageFlags usage)79 VkMemoryRequirements getBufferMemoryRequirements (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize size, const VkBufferCreateFlags flags, const VkBufferUsageFlags usage)
80 {
81 const Unique<VkBuffer> buffer(makeBuffer(vk, device, size, flags, usage));
82 return getBufferMemoryRequirements(vk, device, *buffer);
83 }
84
85 template<typename T>
nextEnum(T value)86 T nextEnum (T value)
87 {
88 return static_cast<T>(static_cast<deUint32>(value) + 1);
89 }
90
91 template<typename T>
nextFlag(T value)92 T nextFlag (T value)
93 {
94 if (value)
95 return static_cast<T>(static_cast<deUint32>(value) << 1);
96 else
97 return static_cast<T>(1);
98 }
99
100 template<typename T>
nextFlagExcluding(T value,T excludedFlags)101 T nextFlagExcluding (T value, T excludedFlags)
102 {
103 deUint32 tmp = static_cast<deUint32>(value);
104 while ((tmp = nextFlag(tmp)) & static_cast<deUint32>(excludedFlags));
105 return static_cast<T>(tmp);
106 }
107
requireBufferSparseFeatures(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkBufferCreateFlags flags)108 void requireBufferSparseFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkBufferCreateFlags flags)
109 {
110 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
111
112 if ((flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && !features.sparseBinding)
113 TCU_THROW(NotSupportedError, "Feature not supported: sparseBinding");
114
115 if ((flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && !features.sparseResidencyBuffer)
116 TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyBuffer");
117
118 if ((flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && !features.sparseResidencyAliased)
119 TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyAliased");
120 }
121
verifyBufferRequirements(tcu::ResultCollector & result,const VkPhysicalDeviceMemoryProperties & deviceMemoryProperties,const VkMemoryRequirements & requirements,const VkMemoryRequirements & allUsageFlagsRequirements,const VkPhysicalDeviceLimits & limits,const VkBufferCreateFlags bufferFlags,const VkBufferUsageFlags usage)122 void verifyBufferRequirements (tcu::ResultCollector& result,
123 const VkPhysicalDeviceMemoryProperties& deviceMemoryProperties,
124 const VkMemoryRequirements& requirements,
125 const VkMemoryRequirements& allUsageFlagsRequirements,
126 const VkPhysicalDeviceLimits& limits,
127 const VkBufferCreateFlags bufferFlags,
128 const VkBufferUsageFlags usage)
129 {
130 if (result.check(requirements.memoryTypeBits != 0, "VkMemoryRequirements memoryTypeBits has no bits set"))
131 {
132 typedef std::vector<deUint32>::const_iterator IndexIterator;
133 const std::vector<deUint32> usedMemoryTypeIndices = bitsToIndices(requirements.memoryTypeBits);
134 bool deviceLocalMemoryFound = false;
135 bool hostVisibleCoherentMemoryFound = false;
136
137 for (IndexIterator memoryTypeNdx = usedMemoryTypeIndices.begin(); memoryTypeNdx != usedMemoryTypeIndices.end(); ++memoryTypeNdx)
138 {
139 if (*memoryTypeNdx >= deviceMemoryProperties.memoryTypeCount)
140 {
141 result.fail("VkMemoryRequirements memoryTypeBits contains bits for non-existing memory types");
142 continue;
143 }
144
145 const VkMemoryPropertyFlags memoryPropertyFlags = deviceMemoryProperties.memoryTypes[*memoryTypeNdx].propertyFlags;
146
147 if (memoryPropertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
148 deviceLocalMemoryFound = true;
149
150 if (memoryPropertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
151 hostVisibleCoherentMemoryFound = true;
152
153 result.check((memoryPropertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) == 0u,
154 "Memory type includes VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT");
155 }
156
157 result.check(deIsPowerOfTwo64(static_cast<deUint64>(requirements.alignment)) == DE_TRUE,
158 "VkMemoryRequirements alignment isn't power of two");
159
160 if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT))
161 {
162 result.check(requirements.alignment >= limits.minTexelBufferOffsetAlignment,
163 "VkMemoryRequirements alignment doesn't respect minTexelBufferOffsetAlignment");
164 }
165
166 if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
167 {
168 result.check(requirements.alignment >= limits.minUniformBufferOffsetAlignment,
169 "VkMemoryRequirements alignment doesn't respect minUniformBufferOffsetAlignment");
170 }
171
172 if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
173 {
174 result.check(requirements.alignment >= limits.minStorageBufferOffsetAlignment,
175 "VkMemoryRequirements alignment doesn't respect minStorageBufferOffsetAlignment");
176 }
177
178 result.check(deviceLocalMemoryFound,
179 "None of the required memory types included VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
180
181 result.check((bufferFlags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) || hostVisibleCoherentMemoryFound,
182 "Required memory type doesn't include VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
183
184 result.check((requirements.memoryTypeBits & allUsageFlagsRequirements.memoryTypeBits) == allUsageFlagsRequirements.memoryTypeBits,
185 "Memory type bits aren't a superset of memory type bits for all usage flags combined");
186 }
187 }
188
testBuffer(Context & context,const VkBufferCreateFlags bufferFlags)189 tcu::TestStatus testBuffer (Context& context, const VkBufferCreateFlags bufferFlags)
190 {
191 const DeviceInterface& vk = context.getDeviceInterface();
192 const InstanceInterface& vki = context.getInstanceInterface();
193 const VkDevice device = context.getDevice();
194 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
195
196 requireBufferSparseFeatures(vki, physDevice, bufferFlags);
197
198 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice);
199 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
200 const VkBufferUsageFlags allUsageFlags = static_cast<VkBufferUsageFlags>((VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT << 1) - 1);
201 const VkMemoryRequirements allUsageFlagsRequirements = getBufferMemoryRequirements(vk, device, 1024, bufferFlags, allUsageFlags); // doesn't depend on size
202 tcu::TestLog& log = context.getTestContext().getLog();
203 bool allPass = true;
204
205 const VkDeviceSize sizeCases[] =
206 {
207 1 * 1024,
208 8 * 1024,
209 64 * 1024,
210 1024 * 1024,
211 };
212
213 for (VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; usage <= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; usage = nextFlag(usage))
214 {
215 deUint32 previousMemoryTypeBits = 0u;
216 VkDeviceSize previousAlignment = 0u;
217
218 log << tcu::TestLog::Message << "Verify a buffer with usage flags: " << de::toString(getBufferUsageFlagsStr(usage)) << tcu::TestLog::EndMessage;
219
220 for (const VkDeviceSize* pSize = sizeCases; pSize < sizeCases + DE_LENGTH_OF_ARRAY(sizeCases); ++pSize)
221 {
222 log << tcu::TestLog::Message << "- size " << *pSize << " bytes" << tcu::TestLog::EndMessage;
223
224 const VkMemoryRequirements requirements = getBufferMemoryRequirements(vk, device, *pSize, bufferFlags, usage);
225 tcu::ResultCollector result (log, "ERROR: ");
226
227 // Check:
228 // - requirements for a particular buffer usage
229 // - memoryTypeBits are a subset of bits for requirements with all usage flags combined
230 verifyBufferRequirements(result, memoryProperties, requirements, allUsageFlagsRequirements, limits, bufferFlags, usage);
231
232 // Check that for the same usage and create flags:
233 // - memoryTypeBits are the same
234 // - alignment is the same
235 if (pSize > sizeCases)
236 {
237 result.check(requirements.memoryTypeBits == previousMemoryTypeBits,
238 "memoryTypeBits differ from the ones in the previous buffer size");
239
240 result.check(requirements.alignment == previousAlignment,
241 "alignment differs from the one in the previous buffer size");
242 }
243
244 if (result.getResult() != QP_TEST_RESULT_PASS)
245 allPass = false;
246
247 previousMemoryTypeBits = requirements.memoryTypeBits;
248 previousAlignment = requirements.alignment;
249 }
250
251 if (!allPass)
252 break;
253 }
254
255 return allPass ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some memory requirements were incorrect");
256 }
257
requireImageSparseFeatures(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkImageCreateFlags createFlags)258 void requireImageSparseFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkImageCreateFlags createFlags)
259 {
260 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
261
262 if ((createFlags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) && !features.sparseBinding)
263 TCU_THROW(NotSupportedError, "Feature not supported: sparseBinding");
264
265 if ((createFlags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) && !(features.sparseResidencyImage2D || features.sparseResidencyImage3D))
266 TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyImage (2D and 3D)");
267
268 if ((createFlags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && !features.sparseResidencyAliased)
269 TCU_THROW(NotSupportedError, "Feature not supported: sparseResidencyAliased");
270 }
271
imageUsageMatchesFormatFeatures(const VkImageUsageFlags usage,const VkFormatFeatureFlags featureFlags)272 bool imageUsageMatchesFormatFeatures (const VkImageUsageFlags usage, const VkFormatFeatureFlags featureFlags)
273 {
274 if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) && (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
275 return true;
276 if ((usage & VK_IMAGE_USAGE_STORAGE_BIT) && (featureFlags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
277 return true;
278 if ((usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) && (featureFlags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
279 return true;
280 if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && (featureFlags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
281 return true;
282
283 return false;
284 }
285
286 //! This catches both invalid as well as legal but unsupported combinations of image parameters
isImageSupported(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkImageCreateInfo & info)287 bool isImageSupported (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkImageCreateInfo& info)
288 {
289 DE_ASSERT(info.extent.width >= 1u && info.extent.height >= 1u && info.extent.depth >= 1u);
290
291 if (info.imageType == VK_IMAGE_TYPE_1D)
292 {
293 DE_ASSERT(info.extent.height == 1u && info.extent.depth == 1u);
294 }
295 else if (info.imageType == VK_IMAGE_TYPE_2D)
296 {
297 DE_ASSERT(info.extent.depth == 1u);
298
299 if (info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
300 {
301 DE_ASSERT(info.extent.width == info.extent.height);
302 DE_ASSERT(info.arrayLayers >= 6u && (info.arrayLayers % 6u) == 0u);
303 }
304 }
305
306 if ((info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && info.imageType != VK_IMAGE_TYPE_2D)
307 return false;
308
309 if ((info.samples != VK_SAMPLE_COUNT_1_BIT) &&
310 (info.imageType != VK_IMAGE_TYPE_2D || (info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) || info.tiling != VK_IMAGE_TILING_OPTIMAL || info.mipLevels > 1u))
311 return false;
312
313 if ((info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) &&
314 (info.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0u)
315 return false;
316
317 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
318
319 if (info.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)
320 {
321 DE_ASSERT(info.tiling == VK_IMAGE_TILING_OPTIMAL);
322
323 if (info.imageType == VK_IMAGE_TYPE_2D && !features.sparseResidencyImage2D)
324 return false;
325 if (info.imageType == VK_IMAGE_TYPE_3D && !features.sparseResidencyImage3D)
326 return false;
327 if (info.samples == VK_SAMPLE_COUNT_2_BIT && !features.sparseResidency2Samples)
328 return false;
329 if (info.samples == VK_SAMPLE_COUNT_4_BIT && !features.sparseResidency4Samples)
330 return false;
331 if (info.samples == VK_SAMPLE_COUNT_8_BIT && !features.sparseResidency8Samples)
332 return false;
333 if (info.samples == VK_SAMPLE_COUNT_16_BIT && !features.sparseResidency16Samples)
334 return false;
335 if (info.samples == VK_SAMPLE_COUNT_32_BIT || info.samples == VK_SAMPLE_COUNT_64_BIT)
336 return false;
337 }
338
339 if (info.samples != VK_SAMPLE_COUNT_1_BIT && (info.usage & VK_IMAGE_USAGE_STORAGE_BIT) && !features.shaderStorageImageMultisample)
340 return false;
341
342 switch (info.format)
343 {
344 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
345 case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
346 case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
347 case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
348 case VK_FORMAT_BC2_UNORM_BLOCK:
349 case VK_FORMAT_BC2_SRGB_BLOCK:
350 case VK_FORMAT_BC3_UNORM_BLOCK:
351 case VK_FORMAT_BC3_SRGB_BLOCK:
352 case VK_FORMAT_BC4_UNORM_BLOCK:
353 case VK_FORMAT_BC4_SNORM_BLOCK:
354 case VK_FORMAT_BC5_UNORM_BLOCK:
355 case VK_FORMAT_BC5_SNORM_BLOCK:
356 case VK_FORMAT_BC6H_UFLOAT_BLOCK:
357 case VK_FORMAT_BC6H_SFLOAT_BLOCK:
358 case VK_FORMAT_BC7_UNORM_BLOCK:
359 case VK_FORMAT_BC7_SRGB_BLOCK:
360 if (!features.textureCompressionBC)
361 return false;
362 break;
363
364 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
365 case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
366 case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
367 case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
368 case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
369 case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
370 case VK_FORMAT_EAC_R11_UNORM_BLOCK:
371 case VK_FORMAT_EAC_R11_SNORM_BLOCK:
372 case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
373 case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
374 if (!features.textureCompressionETC2)
375 return false;
376 break;
377
378 case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
379 case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
380 case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
381 case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
382 case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
383 case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
384 case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
385 case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
386 case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
387 case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
388 case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
389 case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
390 case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
391 case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
392 case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
393 case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
394 case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
395 case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
396 case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
397 case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
398 case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
399 case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
400 case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
401 case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
402 case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
403 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
404 case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
405 case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
406 if (!features.textureCompressionASTC_LDR)
407 return false;
408 break;
409
410 default:
411 break;
412 }
413
414 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physDevice, info.format);
415 const VkFormatFeatureFlags formatFeatures = (info.tiling == VK_IMAGE_TILING_LINEAR ? formatProperties.linearTilingFeatures
416 : formatProperties.optimalTilingFeatures);
417
418 if (!imageUsageMatchesFormatFeatures(info.usage, formatFeatures))
419 return false;
420
421 VkImageFormatProperties imageFormatProperties;
422 const VkResult result = vki.getPhysicalDeviceImageFormatProperties(
423 physDevice, info.format, info.imageType, info.tiling, info.usage, info.flags, &imageFormatProperties);
424
425 if (result == VK_SUCCESS)
426 {
427 if (info.arrayLayers > imageFormatProperties.maxArrayLayers)
428 return false;
429 if (info.mipLevels > imageFormatProperties.maxMipLevels)
430 return false;
431 if ((info.samples & imageFormatProperties.sampleCounts) == 0u)
432 return false;
433 }
434
435 return result == VK_SUCCESS;
436 }
437
makeExtentForImage(const VkImageType imageType)438 VkExtent3D makeExtentForImage (const VkImageType imageType)
439 {
440 VkExtent3D extent = { 64u, 64u, 4u };
441
442 if (imageType == VK_IMAGE_TYPE_1D)
443 extent.height = extent.depth = 1u;
444 else if (imageType == VK_IMAGE_TYPE_2D)
445 extent.depth = 1u;
446
447 return extent;
448 }
449
isFormatMatchingAspect(const VkFormat format,const VkImageAspectFlags aspect)450 bool isFormatMatchingAspect (const VkFormat format, const VkImageAspectFlags aspect)
451 {
452 DE_ASSERT(aspect == VK_IMAGE_ASPECT_COLOR_BIT || aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
453
454 // D/S formats are laid out next to each other in the enum
455 const bool isDepthStencilFormat = (format >= VK_FORMAT_D16_UNORM && format <= VK_FORMAT_D32_SFLOAT_S8_UINT);
456
457 return (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == isDepthStencilFormat;
458 }
459
verifyImageRequirements(tcu::ResultCollector & result,const VkPhysicalDeviceMemoryProperties & deviceMemoryProperties,const VkMemoryRequirements & requirements,const VkImageCreateInfo & imageInfo)460 void verifyImageRequirements (tcu::ResultCollector& result,
461 const VkPhysicalDeviceMemoryProperties& deviceMemoryProperties,
462 const VkMemoryRequirements& requirements,
463 const VkImageCreateInfo& imageInfo)
464 {
465 if (result.check(requirements.memoryTypeBits != 0, "VkMemoryRequirements memoryTypeBits has no bits set"))
466 {
467 typedef std::vector<deUint32>::const_iterator IndexIterator;
468 const std::vector<deUint32> usedMemoryTypeIndices = bitsToIndices(requirements.memoryTypeBits);
469 bool deviceLocalMemoryFound = false;
470 bool hostVisibleCoherentMemoryFound = false;
471
472 for (IndexIterator memoryTypeNdx = usedMemoryTypeIndices.begin(); memoryTypeNdx != usedMemoryTypeIndices.end(); ++memoryTypeNdx)
473 {
474 if (*memoryTypeNdx >= deviceMemoryProperties.memoryTypeCount)
475 {
476 result.fail("VkMemoryRequirements memoryTypeBits contains bits for non-existing memory types");
477 continue;
478 }
479
480 const VkMemoryPropertyFlags memoryPropertyFlags = deviceMemoryProperties.memoryTypes[*memoryTypeNdx].propertyFlags;
481
482 if (memoryPropertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
483 deviceLocalMemoryFound = true;
484
485 if (memoryPropertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
486 hostVisibleCoherentMemoryFound = true;
487
488 if (memoryPropertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
489 {
490 result.check((imageInfo.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0u,
491 "Memory type includes VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT for a non-transient attachment image");
492 }
493 }
494
495 result.check(deIsPowerOfTwo64(static_cast<deUint64>(requirements.alignment)) == DE_TRUE,
496 "VkMemoryRequirements alignment isn't power of two");
497
498 result.check(deviceLocalMemoryFound,
499 "None of the required memory types included VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
500
501 result.check(imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL || hostVisibleCoherentMemoryFound,
502 "Required memory type doesn't include VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
503 }
504 }
505
getImageInfoString(const VkImageCreateInfo & imageInfo)506 std::string getImageInfoString (const VkImageCreateInfo& imageInfo)
507 {
508 std::ostringstream str;
509
510 switch (imageInfo.imageType)
511 {
512 case VK_IMAGE_TYPE_1D: str << "1D "; break;
513 case VK_IMAGE_TYPE_2D: str << "2D "; break;
514 case VK_IMAGE_TYPE_3D: str << "3D "; break;
515 default: break;
516 }
517
518 switch (imageInfo.tiling)
519 {
520 case VK_IMAGE_TILING_OPTIMAL: str << "(optimal) "; break;
521 case VK_IMAGE_TILING_LINEAR: str << "(linear) "; break;
522 default: break;
523 }
524
525 str << "extent:[" << imageInfo.extent.width << ", " << imageInfo.extent.height << ", " << imageInfo.extent.depth << "] ";
526 str << imageInfo.format << " ";
527 str << "samples:" << static_cast<deUint32>(imageInfo.samples) << " ";
528 str << "flags:" << static_cast<deUint32>(imageInfo.flags) << " ";
529 str << "usage:" << static_cast<deUint32>(imageInfo.usage) << " ";
530
531 return str.str();
532 }
533
534 struct ImageParams
535 {
536 VkImageCreateFlags flags;
537 VkImageTiling tiling;
538 bool transient;
539 };
540
testImage(Context & context,const ImageParams params)541 tcu::TestStatus testImage (Context& context, const ImageParams params)
542 {
543 const DeviceInterface& vk = context.getDeviceInterface();
544 const InstanceInterface& vki = context.getInstanceInterface();
545 const VkDevice device = context.getDevice();
546 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
547 const VkImageCreateFlags sparseFlags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT;
548 const VkImageUsageFlags transientFlags = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
549
550 requireImageSparseFeatures(vki, physDevice, params.flags);
551
552 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice);
553 const deUint32 notInitializedBits = ~0u;
554 const VkImageAspectFlags colorAspect = VK_IMAGE_ASPECT_COLOR_BIT;
555 const VkImageAspectFlags depthStencilAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
556 const VkImageAspectFlags allAspects[2] = { colorAspect, depthStencilAspect };
557 tcu::TestLog& log = context.getTestContext().getLog();
558 bool allPass = true;
559 deUint32 numCheckedImages = 0u;
560
561 log << tcu::TestLog::Message << "Verify memory requirements for the following parameter combinations:" << tcu::TestLog::EndMessage;
562
563 for (deUint32 loopAspectNdx = 0u; loopAspectNdx < DE_LENGTH_OF_ARRAY(allAspects); ++loopAspectNdx)
564 {
565 const VkImageAspectFlags aspect = allAspects[loopAspectNdx];
566 deUint32 previousMemoryTypeBits = notInitializedBits;
567
568 for (VkFormat loopFormat = VK_FORMAT_R4G4_UNORM_PACK8; loopFormat <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; loopFormat = nextEnum(loopFormat))
569 if (isFormatMatchingAspect(loopFormat, aspect))
570 {
571 // memoryTypeBits may differ between depth/stencil formats
572 if (aspect == depthStencilAspect)
573 previousMemoryTypeBits = notInitializedBits;
574
575 for (VkImageType loopImageType = VK_IMAGE_TYPE_1D; loopImageType != VK_IMAGE_TYPE_LAST; loopImageType = nextEnum(loopImageType))
576 for (VkImageCreateFlags loopCreateFlags = (VkImageCreateFlags)0; loopCreateFlags <= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; loopCreateFlags = nextFlagExcluding(loopCreateFlags, sparseFlags))
577 for (VkImageUsageFlags loopUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; loopUsageFlags <= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; loopUsageFlags = nextFlagExcluding(loopUsageFlags, transientFlags))
578 for (VkSampleCountFlagBits loopSampleCount = VK_SAMPLE_COUNT_1_BIT; loopSampleCount <= VK_SAMPLE_COUNT_16_BIT; loopSampleCount = nextFlag(loopSampleCount))
579 {
580 const VkImageCreateFlags actualCreateFlags = loopCreateFlags | params.flags;
581 const VkImageUsageFlags actualUsageFlags = loopUsageFlags | (params.transient ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : (VkImageUsageFlagBits)0);
582 const bool isCube = (actualCreateFlags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0u;
583 const VkImageCreateInfo imageInfo =
584 {
585 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
586 DE_NULL, // const void* pNext;
587 actualCreateFlags, // VkImageCreateFlags flags;
588 loopImageType, // VkImageType imageType;
589 loopFormat, // VkFormat format;
590 makeExtentForImage(loopImageType), // VkExtent3D extent;
591 1u, // uint32_t mipLevels;
592 (isCube ? 6u : 1u), // uint32_t arrayLayers;
593 loopSampleCount, // VkSampleCountFlagBits samples;
594 params.tiling, // VkImageTiling tiling;
595 actualUsageFlags, // VkImageUsageFlags usage;
596 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
597 0u, // uint32_t queueFamilyIndexCount;
598 DE_NULL, // const uint32_t* pQueueFamilyIndices;
599 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
600 };
601
602 if (!isImageSupported(vki, physDevice, imageInfo))
603 continue;
604
605 log << tcu::TestLog::Message << "- " << getImageInfoString(imageInfo) << tcu::TestLog::EndMessage;
606 ++numCheckedImages;
607
608 const Unique<VkImage> image (createImage(vk, device, &imageInfo));
609 const VkMemoryRequirements requirements = getImageMemoryRequirements(vk, device, *image);
610 tcu::ResultCollector result (log, "ERROR: ");
611
612 verifyImageRequirements(result, memoryProperties, requirements, imageInfo);
613
614 // For the same tiling, transient usage, and sparse flags, (and format, if D/S) memoryTypeBits must be the same for all images
615 result.check((previousMemoryTypeBits == notInitializedBits) || (requirements.memoryTypeBits == previousMemoryTypeBits),
616 "memoryTypeBits differ from the ones in the previous image configuration");
617
618 if (result.getResult() != QP_TEST_RESULT_PASS)
619 allPass = false;
620
621 previousMemoryTypeBits = requirements.memoryTypeBits;
622 }
623 }
624 }
625
626 if (numCheckedImages == 0u)
627 log << tcu::TestLog::Message << "NOTE: No supported image configurations -- nothing to check" << tcu::TestLog::EndMessage;
628
629 return allPass ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some memory requirements were incorrect");
630 }
631
populateTestGroup(tcu::TestCaseGroup * group)632 void populateTestGroup (tcu::TestCaseGroup* group)
633 {
634 // Buffers
635 {
636 const struct
637 {
638 VkBufferCreateFlags flags;
639 const char* const name;
640 } bufferCases[] =
641 {
642 { (VkBufferCreateFlags)0, "regular" },
643 { VK_BUFFER_CREATE_SPARSE_BINDING_BIT, "sparse" },
644 { VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, "sparse_residency" },
645 { VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, "sparse_aliased" },
646 { VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, "sparse_residency_aliased" },
647 };
648
649 de::MovePtr<tcu::TestCaseGroup> bufferGroup(new tcu::TestCaseGroup(group->getTestContext(), "buffer", ""));
650
651 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bufferCases); ++ndx)
652 addFunctionCase(bufferGroup.get(), bufferCases[ndx].name, "", testBuffer, bufferCases[ndx].flags);
653
654 group->addChild(bufferGroup.release());
655 }
656
657 // Images
658 {
659 const struct
660 {
661 VkImageCreateFlags flags;
662 bool transient;
663 const char* const name;
664 } imageFlagsCases[] =
665 {
666 { (VkImageCreateFlags)0, false, "regular" },
667 { (VkImageCreateFlags)0, true, "transient" },
668 { VK_IMAGE_CREATE_SPARSE_BINDING_BIT, false, "sparse" },
669 { VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, false, "sparse_residency" },
670 { VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT, false, "sparse_aliased" },
671 { VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT, false, "sparse_residency_aliased" },
672 };
673
674 de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(group->getTestContext(), "image", ""));
675
676 for (int flagsNdx = 0; flagsNdx < DE_LENGTH_OF_ARRAY(imageFlagsCases); ++flagsNdx)
677 for (int tilingNdx = 0; tilingNdx <= 1; ++tilingNdx)
678 {
679 ImageParams params;
680 std::ostringstream caseName;
681
682 params.flags = imageFlagsCases[flagsNdx].flags;
683 params.transient = imageFlagsCases[flagsNdx].transient;
684 caseName << imageFlagsCases[flagsNdx].name;
685
686 if (tilingNdx != 0)
687 {
688 params.tiling = VK_IMAGE_TILING_OPTIMAL;
689 caseName << "_tiling_optimal";
690 }
691 else
692 {
693 params.tiling = VK_IMAGE_TILING_LINEAR;
694 caseName << "_tiling_linear";
695 }
696
697 if ((params.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) && (params.tiling == VK_IMAGE_TILING_LINEAR))
698 continue;
699
700 addFunctionCase(imageGroup.get(), caseName.str(), "", testImage, params);
701 }
702
703 group->addChild(imageGroup.release());
704 }
705 }
706
707 } // anonymous
708
createRequirementsTests(tcu::TestContext & testCtx)709 tcu::TestCaseGroup* createRequirementsTests (tcu::TestContext& testCtx)
710 {
711 return createTestGroup(testCtx, "requirements", "Buffer and image memory requirements", populateTestGroup);
712 }
713
714 } // memory
715 } // vkt
716