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 42namespace vkt 43{ 44namespace memory 45{ 46namespace 47{ 48using namespace vk; 49using de::MovePtr; 50 51Move<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. 68std::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 79VkMemoryRequirements 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 85template<typename T> 86T nextEnum (T value) 87{ 88 return static_cast<T>(static_cast<deUint32>(value) + 1); 89} 90 91template<typename T> 92T 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 100template<typename T> 101T 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 108void 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 122void 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 189tcu::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 258void 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 272bool 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 287bool 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 438VkExtent3D 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 450bool 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 460void 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 506std::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 534struct ImageParams 535{ 536 VkImageCreateFlags flags; 537 VkImageTiling tiling; 538 bool transient; 539}; 540 541tcu::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 632void 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 709tcu::TestCaseGroup* createRequirementsTests (tcu::TestContext& testCtx) 710{ 711 return createTestGroup(testCtx, "requirements", "Buffer and image memory requirements", populateTestGroup); 712} 713 714} // memory 715} // vkt 716