| /* Copyright (c) 2015-2025 The Khronos Group Inc. |
| * Copyright (c) 2015-2025 Valve Corporation |
| * Copyright (c) 2015-2025 LunarG, Inc. |
| * Copyright (C) 2015-2024 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "stateless/stateless_validation.h" |
| #include "generated/enum_flag_bits.h" |
| #include "generated/dispatch_functions.h" |
| #include "utils/math_utils.h" |
| |
| namespace stateless { |
| |
| bool Device::manual_PreCallValidateGetMemoryFdKHR(VkDevice device, const VkMemoryGetFdInfoKHR *pGetFdInfo, int *pFd, |
| const Context &context) const { |
| constexpr auto allowed_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| if (0 == (pGetFdInfo->handleType & allowed_types)) { |
| skip |= LogError("VUID-VkMemoryGetFdInfoKHR-handleType-00672", pGetFdInfo->memory, |
| error_obj.location.dot(Field::pGetFdInfo).dot(Field::handleType), |
| "(%s) is not one of the supported handle types (%s).", |
| string_VkExternalMemoryHandleTypeFlagBits(pGetFdInfo->handleType), |
| string_VkExternalMemoryHandleTypeFlags(allowed_types).c_str()); |
| } |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetMemoryFdPropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, |
| VkMemoryFdPropertiesKHR *pMemoryFdProperties, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| if (fd < 0) { |
| skip |= LogError("VUID-vkGetMemoryFdPropertiesKHR-fd-00673", device, error_obj.location.dot(Field::fd), |
| "handle (%d) is not a valid POSIX file descriptor.", fd); |
| } |
| if (handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) { |
| skip |= LogError("VUID-vkGetMemoryFdPropertiesKHR-handleType-00674", device, error_obj.location.dot(Field::handleType), |
| "(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) is not allowed."); |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateExternalSemaphoreHandleType(VkSemaphore semaphore, const char *vuid, const Location &handle_type_loc, |
| VkExternalSemaphoreHandleTypeFlagBits handle_type, |
| VkExternalSemaphoreHandleTypeFlags allowed_types) const { |
| bool skip = false; |
| if (0 == (handle_type & allowed_types)) { |
| skip |= LogError(vuid, semaphore, handle_type_loc, "%s is not one of the supported handleTypes (%s).", |
| string_VkExternalSemaphoreHandleTypeFlagBits(handle_type), |
| string_VkExternalSemaphoreHandleTypeFlags(allowed_types).c_str()); |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateExternalFenceHandleType(VkFence fence, const char *vuid, const Location &handle_type_loc, |
| VkExternalFenceHandleTypeFlagBits handle_type, |
| VkExternalFenceHandleTypeFlags allowed_types) const { |
| bool skip = false; |
| if (0 == (handle_type & allowed_types)) { |
| skip |= LogError(vuid, fence, handle_type_loc, "%s is not one of the supported handleTypes (%s).", |
| string_VkExternalFenceHandleTypeFlagBits(handle_type), |
| string_VkExternalFenceHandleTypeFlags(allowed_types).c_str()); |
| } |
| return skip; |
| } |
| |
| static constexpr VkExternalSemaphoreHandleTypeFlags kSemFdHandleTypes = |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; |
| |
| bool Device::manual_PreCallValidateGetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR *pGetFdInfo, int *pFd, |
| const Context &context) const { |
| const auto &error_obj = context.error_obj; |
| return ValidateExternalSemaphoreHandleType(pGetFdInfo->semaphore, "VUID-VkSemaphoreGetFdInfoKHR-handleType-01136", |
| error_obj.location.dot(Field::pGetFdInfo).dot(Field::handleType), |
| pGetFdInfo->handleType, kSemFdHandleTypes); |
| } |
| |
| bool Device::manual_PreCallValidateImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| const Location info_loc = error_obj.location.dot(Field::pImportSemaphoreFdInfo); |
| skip |= |
| ValidateExternalSemaphoreHandleType(pImportSemaphoreFdInfo->semaphore, "VUID-VkImportSemaphoreFdInfoKHR-handleType-01143", |
| info_loc.dot(Field::handleType), pImportSemaphoreFdInfo->handleType, kSemFdHandleTypes); |
| |
| if (pImportSemaphoreFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT && |
| (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) == 0) { |
| skip |= LogError("VUID-VkImportSemaphoreFdInfoKHR-handleType-07307", pImportSemaphoreFdInfo->semaphore, |
| info_loc.dot(Field::handleType), |
| "is VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT so" |
| " VK_SEMAPHORE_IMPORT_TEMPORARY_BIT must be set, but flags is %s", |
| string_VkSemaphoreImportFlags(pImportSemaphoreFdInfo->flags).c_str()); |
| } |
| return skip; |
| } |
| |
| static constexpr VkExternalFenceHandleTypeFlags kFenceFdHandleTypes = |
| VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; |
| |
| bool Device::manual_PreCallValidateGetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR *pGetFdInfo, int *pFd, |
| const Context &context) const { |
| return ValidateExternalFenceHandleType(pGetFdInfo->fence, "VUID-VkFenceGetFdInfoKHR-handleType-01456", |
| context.error_obj.location.dot(Field::pGetFdInfo).dot(Field::handleType), |
| pGetFdInfo->handleType, kFenceFdHandleTypes); |
| } |
| |
| bool Device::manual_PreCallValidateImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| const Location info_loc = error_obj.location.dot(Field::pImportFenceFdInfo); |
| skip |= ValidateExternalFenceHandleType(pImportFenceFdInfo->fence, "VUID-VkImportFenceFdInfoKHR-handleType-01464", |
| info_loc.dot(Field::handleType), pImportFenceFdInfo->handleType, kFenceFdHandleTypes); |
| |
| if (pImportFenceFdInfo->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT && |
| (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) == 0) { |
| skip |= LogError("VUID-VkImportFenceFdInfoKHR-handleType-07306", pImportFenceFdInfo->fence, info_loc.dot(Field::handleType), |
| "is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT so" |
| " VK_FENCE_IMPORT_TEMPORARY_BIT must be set, but flags is %s", |
| string_VkFenceImportFlags(pImportFenceFdInfo->flags).c_str()); |
| } |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, |
| const void *pHostPointer, |
| VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| if (handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && |
| handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT) { |
| skip |= |
| LogError("VUID-vkGetMemoryHostPointerPropertiesEXT-handleType-01752", device, error_obj.location.dot(Field::handleType), |
| "is %s.", string_VkExternalMemoryHandleTypeFlagBits(handleType)); |
| } |
| |
| const VkDeviceSize host_pointer = reinterpret_cast<VkDeviceSize>(pHostPointer); |
| if (!IsIntegerMultipleOf(host_pointer, phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment)) { |
| skip |= LogError("VUID-vkGetMemoryHostPointerPropertiesEXT-pHostPointer-01753", device, |
| error_obj.location.dot(Field::pHostPointer), |
| "(0x%" PRIxLEAST64 |
| ") is not aligned " |
| "to minImportedHostPointerAlignment (%" PRIuLEAST64 ")", |
| host_pointer, phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment); |
| } |
| |
| return skip; |
| } |
| |
| #ifdef VK_USE_PLATFORM_WIN32_KHR |
| bool Device::manual_PreCallValidateGetMemoryWin32HandleKHR(VkDevice device, |
| const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo, |
| HANDLE *pHandle, const Context &context) const { |
| constexpr VkExternalMemoryHandleTypeFlags nt_handles = |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT; |
| constexpr VkExternalMemoryHandleTypeFlags global_share_handles = |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT; |
| bool skip = false; |
| if ((pGetWin32HandleInfo->handleType & (nt_handles | global_share_handles)) == 0) { |
| skip |= LogError("VUID-VkMemoryGetWin32HandleInfoKHR-handleType-00664", pGetWin32HandleInfo->memory, |
| context.error_obj.location.dot(Field::pGetWin32HandleInfo).dot(Field::handleType), |
| "(%s) is not one of the supported handle types (%s).", |
| string_VkExternalMemoryHandleTypeFlagBits(pGetWin32HandleInfo->handleType), |
| string_VkExternalMemoryHandleTypeFlags(nt_handles | global_share_handles).c_str()); |
| } |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, |
| HANDLE handle, |
| VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| if (handle == NULL || handle == INVALID_HANDLE_VALUE) { |
| static_assert(sizeof(HANDLE) == sizeof(uintptr_t)); // to use PRIxPTR for HANDLE formatting |
| skip |= LogError("VUID-vkGetMemoryWin32HandlePropertiesKHR-handle-00665", device, error_obj.location.dot(Field::handle), |
| "(0x%" PRIxPTR ") is not a valid Windows handle.", reinterpret_cast<std::uintptr_t>(handle)); |
| } |
| if (handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT || |
| handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) { |
| skip |= |
| LogError("VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666", device, error_obj.location.dot(Field::handleType), |
| "%s is not allowed.", string_VkExternalMemoryHandleTypeFlagBits(handleType)); |
| } |
| return skip; |
| } |
| |
| static constexpr VkExternalSemaphoreHandleTypeFlags kSemWin32HandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT | |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT; |
| |
| bool Device::manual_PreCallValidateImportSemaphoreWin32HandleKHR(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *info, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| |
| skip |= |
| ValidateExternalSemaphoreHandleType(info->semaphore, "VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140", |
| error_obj.location.dot(Field::pImportSemaphoreWin32HandleInfo).dot(Field::handleType), |
| info->handleType, kSemWin32HandleTypes); |
| |
| static constexpr auto kNameAllowedTypes = |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT; |
| if ((info->handleType & kNameAllowedTypes) == 0 && info->name) { |
| skip |= LogError("VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01466", info->semaphore, |
| error_obj.location.dot(Field::pImportSemaphoreWin32HandleInfo).dot(Field::name), |
| "(%p) must be NULL if handleType is %s", reinterpret_cast<const void *>(info->name), |
| string_VkExternalSemaphoreHandleTypeFlagBits(info->handleType)); |
| } |
| if (info->handle && info->name) { |
| skip |= LogError("VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01469", info->semaphore, |
| error_obj.location.dot(Field::pImportSemaphoreWin32HandleInfo), |
| "both handle (%p) and name (%p) are non-NULL", info->handle, reinterpret_cast<const void *>(info->name)); |
| } |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetSemaphoreWin32HandleKHR(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR *info, |
| HANDLE *pHandle, const Context &context) const { |
| return ValidateExternalSemaphoreHandleType(info->semaphore, "VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131", |
| context.error_obj.location.dot(Field::pGetWin32HandleInfo).dot(Field::handleType), |
| info->handleType, kSemWin32HandleTypes); |
| } |
| |
| static constexpr VkExternalFenceHandleTypeFlags kFenceWin32HandleTypes = |
| VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT | VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; |
| |
| bool Device::manual_PreCallValidateImportFenceWin32HandleKHR(VkDevice device, const VkImportFenceWin32HandleInfoKHR *info, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| skip |= ValidateExternalFenceHandleType(info->fence, "VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457", |
| error_obj.location.dot(Field::pImportFenceWin32HandleInfo).dot(Field::handleType), |
| info->handleType, kFenceWin32HandleTypes); |
| |
| static constexpr auto kNameAllowedTypes = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT; |
| if ((info->handleType & kNameAllowedTypes) == 0 && info->name) { |
| skip |= LogError("VUID-VkImportFenceWin32HandleInfoKHR-handleType-01459", info->fence, |
| error_obj.location.dot(Field::pImportFenceWin32HandleInfo).dot(Field::name), |
| "(%p) must be NULL if handleType is %s", reinterpret_cast<const void *>(info->name), |
| string_VkExternalFenceHandleTypeFlagBits(info->handleType)); |
| } |
| if (info->handle && info->name) { |
| skip |= LogError("VUID-VkImportFenceWin32HandleInfoKHR-handle-01462", info->fence, |
| error_obj.location.dot(Field::pImportFenceWin32HandleInfo), "both handle (%p) and name (%p) are non-NULL", |
| info->handle, reinterpret_cast<const void *>(info->name)); |
| } |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetFenceWin32HandleKHR(VkDevice device, const VkFenceGetWin32HandleInfoKHR *info, |
| HANDLE *pHandle, const Context &context) const { |
| const auto &error_obj = context.error_obj; |
| return ValidateExternalFenceHandleType(info->fence, "VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452", |
| error_obj.location.dot(Field::pGetWin32HandleInfo).dot(Field::handleType), |
| info->handleType, kFenceWin32HandleTypes); |
| } |
| #endif |
| |
| #ifdef VK_USE_PLATFORM_METAL_EXT |
| bool Device::ExportMetalObjectsPNextUtil(VkExportMetalObjectTypeFlagBitsEXT bit, const char *vuid, const Location &loc, |
| const char *sType, const void *pNext) const { |
| bool skip = false; |
| auto export_metal_object_info = vku::FindStructInPNextChain<VkExportMetalObjectCreateInfoEXT>(pNext); |
| while (export_metal_object_info) { |
| if (export_metal_object_info->exportObjectType != bit) { |
| skip |= LogError(vuid, device, loc, |
| "The pNext chain contains a VkExportMetalObjectCreateInfoEXT whose exportObjectType = %s, but only " |
| "VkExportMetalObjectCreateInfoEXT structs with exportObjectType of %s are allowed.", |
| string_VkExportMetalObjectTypeFlagBitsEXT(export_metal_object_info->exportObjectType), sType); |
| } |
| export_metal_object_info = vku::FindStructInPNextChain<VkExportMetalObjectCreateInfoEXT>(export_metal_object_info->pNext); |
| } |
| return skip; |
| } |
| |
| #endif // VK_USE_PLATFORM_METAL_EXT |
| |
| namespace { |
| |
| // Uses bool where the pointer is not needed to remove the ifdef macros from the core logic |
| struct ExternalOperationsInfo { |
| bool import_info_win32 = false; |
| bool import_info_win32_nv = false; |
| bool export_info_win32 = false; |
| bool export_info_win32_nv = false; |
| |
| const VkImportMemoryFdInfoKHR *import_info_fd = nullptr; |
| const VkImportMemoryHostPointerInfoEXT *import_info_host_pointer = nullptr; |
| |
| const VkExportMemoryAllocateInfo *export_info = nullptr; |
| const VkExportMemoryAllocateInfoNV *export_info_nv = nullptr; |
| |
| uint32_t total_import_ops = 0; |
| bool has_export = false; |
| }; |
| |
| // vkspec.html#memory-import-operation describes all the various ways for import operations |
| ExternalOperationsInfo GetExternalOperationsInfo(const void *pNext) { |
| ExternalOperationsInfo ext = {}; |
| |
| #ifdef VK_USE_PLATFORM_WIN32_KHR |
| // VK_KHR_external_memory_win32 |
| auto import_info_win32 = vku::FindStructInPNextChain<VkImportMemoryWin32HandleInfoKHR>(pNext); |
| ext.import_info_win32 = (import_info_win32 && import_info_win32->handleType); |
| ext.total_import_ops += ext.import_info_win32; |
| |
| auto import_info_win32_nv = vku::FindStructInPNextChain<VkImportMemoryWin32HandleInfoNV>(pNext); |
| ext.import_info_win32_nv = (import_info_win32_nv && import_info_win32_nv->handleType); |
| ext.total_import_ops += ext.import_info_win32_nv; |
| |
| ext.export_info_win32 = vku::FindStructInPNextChain<VkExportMemoryWin32HandleInfoKHR>(pNext) != nullptr; |
| |
| ext.export_info_win32_nv = vku::FindStructInPNextChain<VkExportMemoryWin32HandleInfoNV>(pNext) != nullptr; |
| #endif |
| |
| // VK_KHR_external_memory_fd |
| ext.import_info_fd = vku::FindStructInPNextChain<VkImportMemoryFdInfoKHR>(pNext); |
| ext.total_import_ops += (ext.import_info_fd && ext.import_info_fd->handleType); |
| |
| // VK_EXT_external_memory_host |
| ext.import_info_host_pointer = vku::FindStructInPNextChain<VkImportMemoryHostPointerInfoEXT>(pNext); |
| ext.total_import_ops += (ext.import_info_host_pointer && ext.import_info_host_pointer->handleType); |
| |
| // All exports need a VkExportMemoryAllocateInfo or they are ignored |
| // VK_KHR_external_memory |
| ext.export_info = vku::FindStructInPNextChain<VkExportMemoryAllocateInfo>(pNext); |
| ext.has_export |= (ext.export_info && ext.export_info->handleTypes); |
| |
| // VK_NV_external_memory |
| ext.export_info_nv = vku::FindStructInPNextChain<VkExportMemoryAllocateInfoNV>(pNext); |
| ext.has_export |= (ext.export_info_nv && ext.export_info_nv->handleTypes); |
| |
| #ifdef VK_USE_PLATFORM_ANDROID_KHR |
| // VK_ANDROID_external_memory_android_hardware_buffer |
| auto import_info_ahb = vku::FindStructInPNextChain<VkImportAndroidHardwareBufferInfoANDROID>(pNext); |
| ext.total_import_ops += (import_info_ahb && import_info_ahb->buffer); |
| #endif |
| |
| #ifdef VK_USE_PLATFORM_FUCHSIA |
| // VK_FUCHSIA_external_memory |
| auto import_info_zircon = vku::FindStructInPNextChain<VkImportMemoryZirconHandleInfoFUCHSIA>(pNext); |
| ext.total_import_ops += (import_info_zircon && import_info_zircon->handleType); |
| |
| // VK_FUCHSIA_buffer_collection |
| // NOTE: There's no handleType on VkImportMemoryBufferCollectionFUCHSIA, so we can't check that, and from the "Valid Usage |
| // (Implicit)" collection has to always be valid. |
| ext.total_import_ops += vku::FindStructInPNextChain<VkImportMemoryBufferCollectionFUCHSIA>(pNext) != nullptr; |
| #endif |
| |
| #ifdef VK_USE_PLATFORM_SCREEN_QNX |
| // VK_QNX_external_memory_screen_buffer |
| auto import_info_qnx = vku::FindStructInPNextChain<VkImportScreenBufferInfoQNX>(pNext); |
| ext.total_import_ops += (import_info_qnx && import_info_qnx->buffer); |
| #endif // VK_USE_PLATFORM_SCREEN_QNX |
| |
| #ifdef VK_USE_PLATFORM_METAL_EXT |
| // VK_EXT_external_memory_metal |
| auto import_info_metal = vku::FindStructInPNextChain<VkImportMemoryMetalHandleInfoEXT>(pNext); |
| ext.total_import_ops += (import_info_metal && import_info_metal->handle); |
| #endif // VK_USE_PLATFORM_METAL_EXT |
| |
| return ext; |
| } |
| } // namespace |
| |
| bool Device::ValidateAllocateMemoryExternal(VkDevice device, const VkMemoryAllocateInfo &allocate_info, VkMemoryAllocateFlags flags, |
| const Location &allocate_info_loc) const { |
| bool skip = false; |
| |
| // Used to remove platform ifdef logic below |
| const ExternalOperationsInfo ext = GetExternalOperationsInfo(allocate_info.pNext); |
| |
| if (!ext.has_export && ext.total_import_ops == 0 && allocate_info.allocationSize == 0) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-allocationSize-07897", device, allocate_info_loc.dot(Field::allocationSize), |
| "is 0."); |
| } |
| |
| auto opaque_alloc_info = vku::FindStructInPNextChain<VkMemoryOpaqueCaptureAddressAllocateInfo>(allocate_info.pNext); |
| if (opaque_alloc_info && opaque_alloc_info->opaqueCaptureAddress != 0) { |
| const Location address_loc = |
| allocate_info_loc.pNext(Struct::VkMemoryOpaqueCaptureAddressAllocateInfo, Field::opaqueCaptureAddress); |
| if (!(flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT)) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-opaqueCaptureAddress-03329", device, address_loc, |
| "is non-zero (%" PRIu64 |
| ") so VkMemoryAllocateFlagsInfo::flags must include " |
| "VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT.", |
| opaque_alloc_info->opaqueCaptureAddress); |
| } |
| |
| if (ext.import_info_host_pointer) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-03332", device, address_loc, |
| "is non-zero (%" PRIu64 ") but the pNext chain includes a VkImportMemoryHostPointerInfoEXT structure.", |
| opaque_alloc_info->opaqueCaptureAddress); |
| } |
| |
| if (ext.total_import_ops > 0) { |
| skip |= |
| LogError("VUID-VkMemoryAllocateInfo-opaqueCaptureAddress-03333", device, address_loc, |
| "is non-zero (%" PRIu64 ") but an import operation is defined.", opaque_alloc_info->opaqueCaptureAddress); |
| } |
| } |
| |
| if (ext.total_import_ops > 1) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-None-06657", device, allocate_info_loc, |
| "%" PRIu32 " import operations are defined", ext.total_import_ops); |
| } |
| |
| if (ext.export_info) { |
| if (ext.export_info_nv) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-00640", device, allocate_info_loc, |
| "pNext chain includes both VkExportMemoryAllocateInfo and " |
| "VkExportMemoryAllocateInfoNV"); |
| } |
| if (ext.export_info_win32_nv) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-00640", device, allocate_info_loc, |
| "pNext chain includes both VkExportMemoryAllocateInfo and " |
| "VkExportMemoryWin32HandleInfoNV"); |
| } |
| } |
| |
| if (ext.import_info_win32 && ext.import_info_win32_nv) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-00641", device, allocate_info_loc, |
| "pNext chain includes both VkImportMemoryWin32HandleInfoKHR and " |
| "VkImportMemoryWin32HandleInfoNV"); |
| } |
| |
| if (ext.import_info_fd && ext.import_info_fd->handleType != 0) { |
| if (ext.import_info_fd->fd < 0) { |
| skip |= LogError("VUID-VkImportMemoryFdInfoKHR-handleType-00670", device, |
| allocate_info_loc.pNext(Struct::VkImportMemoryFdInfoKHR, Field::fd), |
| "(%d) is not a valid POSIX file descriptor.", ext.import_info_fd->fd); |
| } |
| if (ext.import_info_fd->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT && |
| ext.import_info_fd->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) { |
| skip |= LogError("VUID-VkImportMemoryFdInfoKHR-handleType-00669", device, |
| allocate_info_loc.pNext(Struct::VkImportMemoryFdInfoKHR, Field::handleType), "%s is not allowed.", |
| string_VkExternalMemoryHandleTypeFlagBits(ext.import_info_fd->handleType)); |
| } |
| } |
| |
| if (ext.import_info_host_pointer && ext.import_info_host_pointer->handleType != 0) { |
| if (ext.import_info_host_pointer->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && |
| ext.import_info_host_pointer->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT) { |
| skip |= LogError("VUID-VkImportMemoryHostPointerInfoEXT-handleType-01748", device, |
| allocate_info_loc.pNext(Struct::VkImportMemoryHostPointerInfoEXT, Field::handleType), "is %s.", |
| string_VkExternalMemoryHandleTypeFlagBits(ext.import_info_host_pointer->handleType)); |
| } |
| |
| if (!IsPointerAligned(ext.import_info_host_pointer->pHostPointer, |
| phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment)) { |
| skip |= LogError("VUID-VkImportMemoryHostPointerInfoEXT-pHostPointer-01749", device, |
| allocate_info_loc.pNext(Struct::VkImportMemoryHostPointerInfoEXT, Field::pHostPointer), |
| "(%p) is not aligned " |
| "to minImportedHostPointerAlignment (%" PRIuLEAST64 ")", |
| ext.import_info_host_pointer->pHostPointer, |
| phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment); |
| } |
| |
| if (!IsIntegerMultipleOf(allocate_info.allocationSize, |
| phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment)) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-allocationSize-01745", device, allocate_info_loc.dot(Field::allocationSize), |
| "(%" PRIuLEAST64 ") is not a multiple of minImportedHostPointerAlignment (%" PRIuLEAST64 ")", |
| allocate_info.allocationSize, |
| phys_dev_ext_props.external_memory_host_props.minImportedHostPointerAlignment); |
| } |
| |
| // only dispatch if known valid handle and host pointer |
| if (!skip) { |
| VkMemoryHostPointerPropertiesEXT host_pointer_props = vku::InitStructHelper(); |
| DispatchGetMemoryHostPointerPropertiesEXT(device, ext.import_info_host_pointer->handleType, |
| ext.import_info_host_pointer->pHostPointer, &host_pointer_props); |
| if (((1 << allocate_info.memoryTypeIndex) & host_pointer_props.memoryTypeBits) == 0) { |
| skip |= LogError( |
| "VUID-VkMemoryAllocateInfo-memoryTypeIndex-01744", device, allocate_info_loc.dot(Field::memoryTypeIndex), |
| "is %" PRIu32 " but VkMemoryHostPointerPropertiesEXT::memoryTypeBits is 0x%" PRIx32 " with handleType %s.", |
| allocate_info.memoryTypeIndex, host_pointer_props.memoryTypeBits, |
| string_VkExternalMemoryHandleTypeFlagBits(ext.import_info_host_pointer->handleType)); |
| } |
| } |
| |
| auto dedicated_allocate_info = vku::FindStructInPNextChain<VkMemoryDedicatedAllocateInfo>(allocate_info.pNext); |
| if (dedicated_allocate_info) { |
| if (dedicated_allocate_info->buffer != VK_NULL_HANDLE) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-02806", device, |
| allocate_info_loc.pNext(Struct::VkMemoryDedicatedAllocateInfo, Field::buffer), |
| "is %s but also using a host import with VkImportMemoryHostPointerInfoEXT.", |
| FormatHandle(dedicated_allocate_info->buffer).c_str()); |
| } else if (dedicated_allocate_info->image != VK_NULL_HANDLE) { |
| skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-02806", device, |
| allocate_info_loc.pNext(Struct::VkMemoryDedicatedAllocateInfo, Field::image), |
| "is %s but also using a host import with VkImportMemoryHostPointerInfoEXT.", |
| FormatHandle(dedicated_allocate_info->image).c_str()); |
| } |
| } |
| } |
| |
| #ifdef VK_USE_PLATFORM_METAL_EXT |
| skip |= ExportMetalObjectsPNextUtil(VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-06780", |
| allocate_info_loc, "VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT", allocate_info.pNext); |
| #endif // VK_USE_PLATFORM_METAL_EXT |
| |
| return skip; |
| } |
| } // namespace stateless |