Skip to content

Commit

Permalink
tests: Add VK_EXT_external_memory_metal tests
Browse files Browse the repository at this point in the history
  • Loading branch information
aitor-lunarg committed Sep 5, 2024
1 parent d331cdb commit 52e8328
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,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
223 changes: 223 additions & 0 deletions tests/unit/external_memory_metal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Copyright (c) 2015-2024 The Khronos Group Inc.
* Copyright (c) 2015-2024 Valve Corporation
* Copyright (c) 2015-2024 LunarG, Inc.
* Copyright (c) 2015-2024 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* 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
*/

#include "utils/vk_layer_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/external_memory_sync.h"

class NegativeExternalMemoryMetal : public VkLayerTest {};

TEST_F(NegativeExternalMemoryMetal, AllocateExportableImageWithoutDedicatedAllocationInPNext) {
TEST_DESCRIPTION("Allocate exportable metal texture without dedicated allocation in pNext chain");

AddRequiredExtensions(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
RETURN_IF_SKIP(Init());

// Create export image
VkExternalMemoryImageCreateInfo external_image_info = vku::InitStructHelper();
VkImageCreateInfo image_info = vku::InitStructHelper(&external_image_info);
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.arrayLayers = 1;
image_info.extent = {64, 64, 1};
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_info.mipLevels = 1;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;

auto exportable_types = FindSupportedExternalMemoryHandleTypes(gpu(), image_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT);

VkExternalMemoryHandleTypeFlagBits metal_texture_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;
if ((exportable_types & metal_texture_type) == 0u) {
GTEST_SKIP() << "Unable to find exportable metal texture handle type";
}
external_image_info.handleTypes = metal_texture_type;
vkt::Image image(*m_device, image_info, vkt::no_mem);

VkExportMemoryAllocateInfo export_memory_info = vku::InitStructHelper(nullptr);
export_memory_info.handleTypes = metal_texture_type;

auto alloc_info = vkt::DeviceMemory::get_resource_alloc_info(*m_device, image.memory_requirements(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &export_memory_info);
m_errorMonitor->SetDesiredError("VUID-UNASSIGNED-VK_EXT_external_memory-no-VkMemoryDedicatedAllocateInfo-export");
image.memory().try_init(*m_device, alloc_info);
m_errorMonitor->VerifyFound();
}

TEST_F(NegativeExternalMemoryMetal, InvalidImportType) {
TEST_DESCRIPTION("Import metal resource with invalid handle type");

AddRequiredExtensions(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
RETURN_IF_SKIP(Init());

VkExternalMemoryBufferCreateInfo external_buffer_info = vku::InitStructHelper();
const auto buffer_info = vkt::Buffer::create_info(4096, VK_BUFFER_USAGE_TRANSFER_DST_BIT, nullptr, &external_buffer_info);
const auto exportable_types =
FindSupportedExternalMemoryHandleTypes(gpu(), buffer_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT);

auto metal_types = static_cast<VkExternalMemoryHandleTypeFlagBits>(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT);
auto valid_types = static_cast<VkExternalMemoryHandleTypeFlagBits>(exportable_types & metal_types);
if (valid_types == 0u) {
GTEST_SKIP() << "Unable to find exportable metal handle type";
}
const auto handle_type = LeastSignificantFlag<VkExternalMemoryHandleTypeFlagBits>(valid_types);
external_buffer_info.handleTypes = handle_type;
vkt::Buffer buffer(*m_device, buffer_info, vkt::no_mem);

// Check if dedicated allocation is required
bool dedicated_allocation = false;
IterateFlags<VkExternalMemoryHandleTypeFlagBits>(exportable_types, [&](VkExternalMemoryHandleTypeFlagBits handle_type) {
if (HandleTypeNeedsDedicatedAllocation(gpu(), buffer_info, handle_type)) {
dedicated_allocation = true;
}
});
VkMemoryDedicatedAllocateInfo dedicated_info = vku::InitStructHelper();
dedicated_info.buffer = buffer;

VkExportMemoryAllocateInfo export_memory_info = vku::InitStructHelper(dedicated_allocation ? &dedicated_info : nullptr);
export_memory_info.handleTypes = handle_type;

auto alloc_info = vkt::DeviceMemory::get_resource_alloc_info(*m_device, buffer.memory_requirements(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &export_memory_info);
VkResult result = buffer.memory().try_init(*m_device, alloc_info);
if (result != VK_SUCCESS) {
GTEST_SKIP() << "vkAllocateMemory failed. Unable to continue test to check for incorrect import handle type.";
}

VkMemoryGetMetalHandleInfoEXT get_handle_info = vku::InitStructHelper();
get_handle_info.handleType = handle_type;
get_handle_info.memory = buffer.memory().handle();
MTLResource_id import_handle = nullptr;
vk::GetMemoryMetalHandleEXT(*m_device, &get_handle_info, &import_handle);

VkImportMemoryMetalHandleInfoEXT metal_import_info = vku::InitStructHelper();
metal_import_info.handleType = metal_types;
metal_import_info.handle = import_handle;
VkMemoryAllocateInfo import_allocate_info = vku::InitStructHelper(&metal_import_info);
VkDeviceMemory device_memory = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VK_EXT_external_memory-incorrect-handle-type");
// Since we are using two bits to import the memory which is not allowed, we will trigger this undefined VUID
m_errorMonitor->SetAllowedFailureMsg("VUID_Undefined");
vk::AllocateMemory(*m_device, &import_allocate_info, nullptr, &device_memory);
m_errorMonitor->VerifyFound();
}

TEST_F(NegativeExternalMemoryMetal, AllocateImportableImageWithoutDedicatedAllocationInPNext) {
TEST_DESCRIPTION("Import metal texture at allocation without dedicated allocation in pNext chain");

AddRequiredExtensions(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
RETURN_IF_SKIP(Init());

// Create export image
VkExternalMemoryImageCreateInfo external_image_info = vku::InitStructHelper();
VkImageCreateInfo image_info = vku::InitStructHelper(&external_image_info);
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.arrayLayers = 1;
image_info.extent = {64, 64, 1};
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_info.mipLevels = 1;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;

auto exportable_types = FindSupportedExternalMemoryHandleTypes(
gpu(), image_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);

VkExternalMemoryHandleTypeFlagBits metal_texture_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;
if ((exportable_types & metal_texture_type) == 0u) {
GTEST_SKIP() << "Unable to find exportable metal texture handle type";
}
external_image_info.handleTypes = metal_texture_type;
vkt::Image image(*m_device, image_info, vkt::no_mem);

VkMemoryDedicatedAllocateInfo dedicated_info = vku::InitStructHelper();
dedicated_info.image = image.handle();
VkExportMemoryAllocateInfo export_memory_info = vku::InitStructHelper(&dedicated_info);
export_memory_info.handleTypes = metal_texture_type;
image.allocate_and_bind_memory(*m_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &export_memory_info);

VkMemoryGetMetalHandleInfoEXT get_handle_info = vku::InitStructHelper();
get_handle_info.handleType = metal_texture_type;
get_handle_info.memory = image.memory().handle();
MTLResource_id import_handle = nullptr;
vk::GetMemoryMetalHandleEXT(*m_device, &get_handle_info, &import_handle);

VkImportMemoryMetalHandleInfoEXT metal_import_info = vku::InitStructHelper();
metal_import_info.handleType = metal_texture_type;
metal_import_info.handle = import_handle;
VkMemoryAllocateInfo import_allocate_info = vku::InitStructHelper(&metal_import_info);
VkDeviceMemory device_memory = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-UNASSIGNED-VK_EXT_external_memory-no-VkMemoryDedicatedAllocateInfo-import");
vk::AllocateMemory(*m_device, &import_allocate_info, nullptr, &device_memory);
m_errorMonitor->VerifyFound();
}

TEST_F(NegativeExternalMemoryMetal, AllocateImportableImageWithoutDedicatedImageAllocation) {
TEST_DESCRIPTION("Import invalid metal texture without dedicated image specified");

AddRequiredExtensions(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
RETURN_IF_SKIP(Init());

// Create export image
VkExternalMemoryImageCreateInfo external_image_info = vku::InitStructHelper();
VkImageCreateInfo image_info = vku::InitStructHelper(&external_image_info);
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.arrayLayers = 1;
image_info.extent = {64, 64, 1};
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_info.mipLevels = 1;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;

auto exportable_types = FindSupportedExternalMemoryHandleTypes(
gpu(), image_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);

VkExternalMemoryHandleTypeFlagBits metal_texture_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;
if ((exportable_types & metal_texture_type) == 0u) {
GTEST_SKIP() << "Unable to find exportable metal texture handle type";
}
external_image_info.handleTypes = metal_texture_type;
vkt::Image image(*m_device, image_info, vkt::no_mem);

VkMemoryDedicatedAllocateInfo dedicated_info = vku::InitStructHelper();
dedicated_info.image = image.handle();
VkExportMemoryAllocateInfo export_memory_info = vku::InitStructHelper(&dedicated_info);
export_memory_info.handleTypes = metal_texture_type;
image.allocate_and_bind_memory(*m_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &export_memory_info);

VkMemoryGetMetalHandleInfoEXT get_handle_info = vku::InitStructHelper();
get_handle_info.handleType = metal_texture_type;
get_handle_info.memory = image.memory().handle();
MTLResource_id import_handle = nullptr;
vk::GetMemoryMetalHandleEXT(*m_device, &get_handle_info, &import_handle);

dedicated_info.image = VK_NULL_HANDLE; // This is what makes it ilegal
VkImportMemoryMetalHandleInfoEXT metal_import_info = vku::InitStructHelper(&dedicated_info);
metal_import_info.handleType = metal_texture_type;
metal_import_info.handle = import_handle;
VkMemoryAllocateInfo import_allocate_info = vku::InitStructHelper(&metal_import_info);
VkDeviceMemory device_memory = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-UNASSIGNED-VK_EXT_external_memory-dedicated-null-image-import");
vk::AllocateMemory(*m_device, &import_allocate_info, nullptr, &device_memory);
m_errorMonitor->VerifyFound();
}

0 comments on commit 52e8328

Please sign in to comment.