Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VK_EXT_external_memory_metal validation and tests #9221

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion layers/core_checks/cc_device_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,15 @@ bool CoreChecks::IgnoreAllocationSize(const VkMemoryAllocateInfo &allocate_info)
if (import_memory_win32 && (import_memory_win32->handleType & ignored_allocation) != 0) {
return true;
}
#endif
#elif VK_USE_PLATFORM_METAL_EXT
const VkExternalMemoryHandleTypeFlags ignored_allocation = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
const auto import_memory_metal = vku::FindStructInPNextChain<VkImportMemoryMetalHandleInfoEXT>(allocate_info.pNext);
if (import_memory_metal && (import_memory_metal->handleType & ignored_allocation) != 0) {
return true;
}
#endif // VK_USE_PLATFORM_METAL_EXT
// Handles 01874 cases
const auto export_info = vku::FindStructInPNextChain<VkExportMemoryAllocateInfo>(allocate_info.pNext);
if (export_info && (export_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
Expand Down Expand Up @@ -770,6 +778,13 @@ bool CoreChecks::PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAl
}
}
#endif

#ifdef VK_USE_PLATFORM_METAL_EXT
if (IsExtEnabled(extensions.vk_ext_external_memory_metal)) {
skip |= ValidateAllocateMemoryMetal(*pAllocateInfo, dedicated_allocate_info, allocate_info_loc);
}
#endif // VK_USE_PLATFORM_METAL_EXT

return skip;
}

Expand Down
147 changes: 147 additions & 0 deletions layers/core_checks/cc_external_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,150 @@ bool CoreChecks::PreCallValidateExportMetalObjectsEXT(VkDevice device, VkExportM
return skip;
}
#endif // VK_USE_PLATFORM_METAL_EXT

bool CoreChecks::ValidateAllocateMemoryMetal(const VkMemoryAllocateInfo &allocate_info,
const VkMemoryDedicatedAllocateInfo *dedicated_allocation_info,
const Location &allocate_info_loc) const {
bool skip = false;

#if VK_USE_PLATFORM_METAL_EXT
// When dealing with Metal external memory, we can have the following 3 scenarios:
// 1. Allocation will be exported. Contains VkExportMemoryAllocateInfo
// 2. Allocation is being imported. Contains VkImportMemoryMetalHandleInfoEXT
// 3. Previous 2 combined
// Whenever the memory will be used for an image, VK_EXT_external_memory_metal requires that the allocation
// is dedicated to that single resource.

// Case 1 and partially 3
// Since we know Metal textures required to be imported as a dedicated allocation, we can do the check directly here instead
// of deferring to the binding call.
const auto export_memory_info = vku::FindStructInPNextChain<VkExportMemoryAllocateInfo>(allocate_info.pNext);
const auto export_memory_info_nv = vku::FindStructInPNextChain<VkExportMemoryAllocateInfoNV>(allocate_info.pNext);
if (export_memory_info || export_memory_info_nv) {
VkExternalMemoryHandleTypeFlags handles =
export_memory_info ? export_memory_info->handleTypes : export_memory_info_nv->handleTypes;
if ((handles == VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) && dedicated_allocation_info == nullptr) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-00639", device, allocate_info_loc.dot(Field::pNext),
"VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT requires textures to be imported as a dedicated "
"allocation.");
}
}

// Case 2 and remaining 3
const auto import_memory_metal_info = vku::FindStructInPNextChain<VkImportMemoryMetalHandleInfoEXT>(allocate_info.pNext);
if (import_memory_metal_info == nullptr) {
return skip;
}

// Ensure user is importing correct type before checking any other VUID since we will assume correct type
if ((import_memory_metal_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT) &&
(import_memory_metal_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) &&
(import_memory_metal_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
skip |= LogError("VUID-VkImportMemoryMetalHandleInfoEXT-handleType-10410", device,
allocate_info_loc.pNext(Struct::VkImportMemoryMetalHandleInfoEXT, Field::handleType), "current value is %s",
string_VkExternalMemoryHandleTypeFlagBits(import_memory_metal_info->handleType));
return skip;
}

// Only images require to be created as a dedicated allocation. This allows us to check if the format
// used by the image allows for importing such images from external memory. We cannot do that with
// buffers since we lack the usage, so it's not possible to know if the device allows import
// operations on buffers.
if (import_memory_metal_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) {
if (allocate_info.allocationSize != 0) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-10397", device,
allocate_info_loc.dot(Field::allocationSize), "is %" PRId64,
allocate_info.allocationSize);
}

if (dedicated_allocation_info == nullptr) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-10395", device,
allocate_info_loc.dot(Field::pNext),
"VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT requires textures to be imported as a dedicated"
"allocation.");
// Early out since the image comes from VkMemoryDedicatedAllocateInfoKHR and there's none.
return skip;
}

// Unsure if there should be a VUID that enforces image to not be NULL when importing a MTLTEXTURE type
if (dedicated_allocation_info->image == VK_NULL_HANDLE) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-10395", device,
allocate_info_loc.dot(Struct::VkMemoryDedicatedAllocateInfo, Field::image),
"must be a valid image handle.");
// Early out since there's no image in VkMemoryDedicatedAllocateInfoKHR.
return skip;
}

// We can only validate images since we lack information to do the buffer call for the properties
auto image_state_ptr = Get<vvl::Image>(dedicated_allocation_info->image);
VkFormat image_format = image_state_ptr->create_info.format;
VkPhysicalDeviceExternalImageFormatInfo external_info = vku::InitStructHelper();
external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;
VkPhysicalDeviceImageFormatInfo2 format_info = vku::InitStructHelper(&external_info);
format_info.format = image_state_ptr->safe_create_info.format;
format_info.tiling = image_state_ptr->safe_create_info.tiling;
format_info.type = image_state_ptr->safe_create_info.imageType;
format_info.usage = image_state_ptr->safe_create_info.usage;
VkExternalImageFormatProperties external_image_format_properties = vku::InitStructHelper();
VkImageFormatProperties2 format_properties = vku::InitStructHelper(&external_image_format_properties);
DispatchGetPhysicalDeviceImageFormatProperties2Helper(physical_device, &format_info, &format_properties);

if ((external_image_format_properties.externalMemoryProperties.externalMemoryFeatures &
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0u) {
skip |= LogError("VUID-VkImportMemoryMetalHandleInfoEXT-handleType-10408", device,
allocate_info_loc.dot(Struct::VkImportMemoryMetalHandleInfoEXT, Field::handleType),
"does not support importing image with format %s", string_VkFormat(image_format));
}
}
#endif // VK_USE_PLATFORM_METAL_EXT

return skip;
}

#ifdef VK_USE_PLATFORM_METAL_EXT
bool CoreChecks::PreCallValidateGetMemoryMetalHandleEXT(VkDevice device, const VkMemoryGetMetalHandleInfoEXT *pGetMetalHandleInfo,
void **pHandle, const ErrorObject &error_obj) const {
bool skip = false;
const Location get_metal_handle_info = error_obj.location.dot(Field::pGetMetalHandleInfo);
auto memory = Get<vvl::DeviceMemory>(pGetMetalHandleInfo->memory);
ASSERT_AND_RETURN_SKIP(memory);
auto export_memory_allocate_info = vku::FindStructInPNextChain<VkExportMemoryAllocateInfo>(memory->safe_allocate_info.pNext);
if (export_memory_allocate_info == nullptr) {
skip |= LogError("VUID-VkMemoryGetMetalHandleInfoEXT-memory-10413", device,
get_metal_handle_info.dot(Field::memory).dot(Field::pNext),
"device memory missing VkExportMemoryAllocateInfo at creation");
} else if ((export_memory_allocate_info->handleTypes & pGetMetalHandleInfo->handleType) == 0u) {
skip |= LogError("VUID-VkMemoryGetMetalHandleInfoEXT-handleType-10414", device,
get_metal_handle_info.dot(Field::handleType),
"device memory was created with (%s) handle types. Missing %s type",
string_VkExternalMemoryHandleTypeFlags(export_memory_allocate_info->handleTypes).c_str(),
string_VkExternalMemoryHandleTypeFlagBits(pGetMetalHandleInfo->handleType));
}

if ((pGetMetalHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT) &&
(pGetMetalHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) &&
(pGetMetalHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
skip |= LogError("VUID-VkMemoryGetMetalHandleInfoEXT-handleType-10415", device,
get_metal_handle_info.dot(Field::handleType), "current value is %s",
string_VkExternalMemoryHandleTypeFlagBits(pGetMetalHandleInfo->handleType));
}
return skip;
}

bool CoreChecks::PreCallValidateGetMemoryMetalHandlePropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType,
const void *handle,
VkMemoryMetalHandlePropertiesEXT *pMemoryMetalHandleProperties,
const ErrorObject &error_obj) const {
bool skip = false;

if ((handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT) &&
(handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) &&
(handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
skip |= LogError("VUID-vkGetMemoryMetalHandlePropertiesEXT-handleType-10417", device,
error_obj.location.dot(Field::handleType), "current value is %s",
string_VkExternalMemoryHandleTypeFlagBits(handleType));
}

return skip;
}
#endif // VK_USE_PLATFORM_METAL_EXT
11 changes: 11 additions & 0 deletions layers/core_checks/core_validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,9 @@ class CoreChecks : public ValidationStateTracker {
bool ValidatePhysicalDeviceQueueFamilies(uint32_t queue_family_count, const uint32_t* queue_families, const Location& loc,
const char* vuid) const;
bool ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo& allocate_info, const Location& allocate_info_loc) const;
bool ValidateAllocateMemoryMetal(const VkMemoryAllocateInfo& allocate_info,
const VkMemoryDedicatedAllocateInfo* dedicated_allocation_info,
const Location& allocate_info_loc) const;
bool ValidateGetImageMemoryRequirementsANDROID(const VkImage image, const Location& loc) const;
bool ValidateBufferImportedHandleANDROID(VkExternalMemoryHandleTypeFlags handle_types, VkDeviceMemory memory, VkBuffer buffer,
const Location& loc) const;
Expand Down Expand Up @@ -2061,6 +2064,14 @@ class CoreChecks : public ValidationStateTracker {
const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo,
zx_handle_t* pZirconHandle, const RecordObject& record_obj) override;
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
bool PreCallValidateGetMemoryMetalHandleEXT(VkDevice device, const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo,
void** pHandle, const ErrorObject& error_obj) const override;
bool PreCallValidateGetMemoryMetalHandlePropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType,
const void* handle,
VkMemoryMetalHandlePropertiesEXT* pMemoryMetalHandleProperties,
const ErrorObject& error_obj) const override;
#endif // VK_USE_PLATFORM_METAL_EXT
#ifdef VK_USE_PLATFORM_WIN32_KHR
bool PreCallValidateGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
HANDLE* pHandle, const ErrorObject& error_obj) const override;
Expand Down
6 changes: 6 additions & 0 deletions layers/stateless/sl_external_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,12 @@ ExternalOperationsInfo GetExternalOperationsInfo(const void *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
Expand Down
2 changes: 1 addition & 1 deletion layers/vulkan/generated/feature_requirements_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4388,7 +4388,7 @@ FeatureAndName AddFeature(APIVersion api_version, vkt::Feature feature, void **i
}
#ifdef VK_ENABLE_BETA_EXTENSIONS

case Feature::constantAlphaColorBlendFactors: {
case Feature::constantAlphaColorBlendFactors: {
auto vk_struct = const_cast<VkPhysicalDevicePortabilitySubsetFeaturesKHR *>(
vku::FindStructInPNextChain<VkPhysicalDevicePortabilitySubsetFeaturesKHR>(*inout_pnext_chain));
if (!vk_struct) {
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ target_sources(vk_layer_validation_tests PRIVATE
unit/dynamic_rendering_local_read_positive.cpp
unit/dynamic_state.cpp
unit/dynamic_state_positive.cpp
unit/external_memory_metal.cpp
unit/external_memory_sync.cpp
unit/external_memory_sync_positive.cpp
unit/fragment_shading_rate.cpp
Expand Down
Loading