mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 07:24:34 +00:00
Add VulkanMock for isolating tests from system
Allows the tests to set the exact values vk-bootstrap will receieve rather than require a real vulkan driver to be present on the system. This is done by creating a `vulkan-1.dll` on windows that implements all of the API functions, and on linux/macOS intercepts `dlsym` to make it return the mock's functions.
This commit is contained in:
parent
5e351fcdf8
commit
d759d3d575
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION 1.3.265)
|
||||
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION_GIT_TAG v1.3.265)
|
||||
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION 1.3.266)
|
||||
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION_GIT_TAG v1.3.266)
|
||||
|
@ -133,26 +133,22 @@ class VulkanFunctions {
|
||||
PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = nullptr;
|
||||
PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = nullptr;
|
||||
PFN_vkCreateInstance fp_vkCreateInstance = nullptr;
|
||||
PFN_vkDestroyInstance fp_vkDestroyInstance = nullptr;
|
||||
|
||||
PFN_vkDestroyInstance fp_vkDestroyInstance = nullptr;
|
||||
PFN_vkCreateDebugUtilsMessengerEXT fp_vkCreateDebugUtilsMessengerEXT = nullptr;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT fp_vkDestroyDebugUtilsMessengerEXT = nullptr;
|
||||
PFN_vkEnumeratePhysicalDevices fp_vkEnumeratePhysicalDevices = nullptr;
|
||||
PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = nullptr;
|
||||
PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = nullptr;
|
||||
PFN_vkGetPhysicalDeviceFeatures2KHR fp_vkGetPhysicalDeviceFeatures2KHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceFormatProperties fp_vkGetPhysicalDeviceFormatProperties = nullptr;
|
||||
PFN_vkGetPhysicalDeviceImageFormatProperties fp_vkGetPhysicalDeviceImageFormatProperties = nullptr;
|
||||
PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = nullptr;
|
||||
PFN_vkGetPhysicalDeviceProperties2 fp_vkGetPhysicalDeviceProperties2 = nullptr;
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fp_vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties fp_vkGetPhysicalDeviceMemoryProperties = nullptr;
|
||||
PFN_vkGetPhysicalDeviceFormatProperties2 fp_vkGetPhysicalDeviceFormatProperties2 = nullptr;
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties2 fp_vkGetPhysicalDeviceMemoryProperties2 = nullptr;
|
||||
|
||||
PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
|
||||
PFN_vkCreateDevice fp_vkCreateDevice = nullptr;
|
||||
PFN_vkEnumerateDeviceExtensionProperties fp_vkEnumerateDeviceExtensionProperties = nullptr;
|
||||
|
||||
PFN_vkCreateDevice fp_vkCreateDevice = nullptr;
|
||||
PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
|
||||
|
||||
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fp_vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fp_vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
|
||||
@ -169,24 +165,21 @@ class VulkanFunctions {
|
||||
void init_instance_funcs(VkInstance inst) {
|
||||
instance = inst;
|
||||
get_inst_proc_addr(fp_vkDestroyInstance, "vkDestroyInstance");
|
||||
get_inst_proc_addr(fp_vkCreateDebugUtilsMessengerEXT, "vkCreateDebugUtilsMessengerEXT");
|
||||
get_inst_proc_addr(fp_vkDestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT");
|
||||
get_inst_proc_addr(fp_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices");
|
||||
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures2KHR, "vkGetPhysicalDeviceFeatures2KHR");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
|
||||
|
||||
get_inst_proc_addr(fp_vkGetDeviceProcAddr, "vkGetDeviceProcAddr");
|
||||
get_inst_proc_addr(fp_vkCreateDevice, "vkCreateDevice");
|
||||
get_inst_proc_addr(fp_vkEnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties");
|
||||
|
||||
get_inst_proc_addr(fp_vkCreateDevice, "vkCreateDevice");
|
||||
get_inst_proc_addr(fp_vkGetDeviceProcAddr, "vkGetDeviceProcAddr");
|
||||
|
||||
get_inst_proc_addr(fp_vkDestroySurfaceKHR, "vkDestroySurfaceKHR");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||
get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||
@ -269,11 +262,9 @@ VkResult create_debug_utils_messenger(VkInstance instance,
|
||||
messengerCreateInfo.pfnUserCallback = debug_callback;
|
||||
messengerCreateInfo.pUserData = user_data_pointer;
|
||||
|
||||
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc;
|
||||
detail::vulkan_functions().get_inst_proc_addr(createMessengerFunc, "vkCreateDebugUtilsMessengerEXT");
|
||||
|
||||
if (createMessengerFunc != nullptr) {
|
||||
return createMessengerFunc(instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
||||
if (detail::vulkan_functions().fp_vkCreateDebugUtilsMessengerEXT != nullptr) {
|
||||
return detail::vulkan_functions().fp_vkCreateDebugUtilsMessengerEXT(
|
||||
instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
||||
} else {
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
@ -282,11 +273,8 @@ VkResult create_debug_utils_messenger(VkInstance instance,
|
||||
void destroy_debug_utils_messenger(
|
||||
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
|
||||
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc;
|
||||
detail::vulkan_functions().get_inst_proc_addr(deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT");
|
||||
|
||||
if (deleteMessengerFunc != nullptr) {
|
||||
deleteMessengerFunc(instance, debugMessenger, allocation_callbacks);
|
||||
if (detail::vulkan_functions().fp_vkDestroyDebugUtilsMessengerEXT != nullptr) {
|
||||
detail::vulkan_functions().fp_vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, allocation_callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,7 +918,13 @@ bool supports_features(VkPhysicalDeviceFeatures supported,
|
||||
if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false;
|
||||
if (requested.inheritedQueries && !supported.inheritedQueries) return false;
|
||||
|
||||
for(size_t i = 0; i < extension_requested.size(); ++i) {
|
||||
// Should only be false if extension_supported was unable to be filled out, due to the
|
||||
// physical device not supporting vkGetPhysicalDeviceFeatures2 in any capacity.
|
||||
if (extension_requested.size() != extension_supported.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < extension_requested.size() && i < extension_supported.size(); ++i) {
|
||||
auto res = GenericFeaturesPNextNode::match(extension_requested[i], extension_supported[i]);
|
||||
if(!res) return false;
|
||||
}
|
||||
|
@ -2236,6 +2236,21 @@ struct DispatchTable {
|
||||
#endif
|
||||
#if (defined(VK_AMDX_shader_enqueue))
|
||||
fp_vkCmdDispatchGraphIndirectCountAMDX = reinterpret_cast<PFN_vkCmdDispatchGraphIndirectCountAMDX>(procAddr(device, "vkCmdDispatchGraphIndirectCountAMDX"));
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
fp_vkSetLatencySleepModeNV = reinterpret_cast<PFN_vkSetLatencySleepModeNV>(procAddr(device, "vkSetLatencySleepModeNV"));
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
fp_vkLatencySleepNV = reinterpret_cast<PFN_vkLatencySleepNV>(procAddr(device, "vkLatencySleepNV"));
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
fp_vkSetLatencyMarkerNV = reinterpret_cast<PFN_vkSetLatencyMarkerNV>(procAddr(device, "vkSetLatencyMarkerNV"));
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
fp_vkGetLatencyTimingsNV = reinterpret_cast<PFN_vkGetLatencyTimingsNV>(procAddr(device, "vkGetLatencyTimingsNV"));
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
fp_vkQueueNotifyOutOfBandNV = reinterpret_cast<PFN_vkQueueNotifyOutOfBandNV>(procAddr(device, "vkQueueNotifyOutOfBandNV"));
|
||||
#endif
|
||||
}
|
||||
void getDeviceQueue(uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) const noexcept {
|
||||
@ -4439,6 +4454,31 @@ struct DispatchTable {
|
||||
void cmdDispatchGraphIndirectCountAMDX(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceAddress countInfo) const noexcept {
|
||||
fp_vkCmdDispatchGraphIndirectCountAMDX(commandBuffer, scratch, countInfo);
|
||||
}
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
VkResult setLatencySleepModeNV(VkSwapchainKHR swapchain, VkLatencySleepModeInfoNV* pSleepModeInfo) const noexcept {
|
||||
return fp_vkSetLatencySleepModeNV(device, swapchain, pSleepModeInfo);
|
||||
}
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
VkResult latencySleepNV(VkSwapchainKHR swapchain, VkLatencySleepInfoNV* pSleepInfo) const noexcept {
|
||||
return fp_vkLatencySleepNV(device, swapchain, pSleepInfo);
|
||||
}
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
void setLatencyMarkerNV(VkSwapchainKHR swapchain, VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo) const noexcept {
|
||||
fp_vkSetLatencyMarkerNV(device, swapchain, pLatencyMarkerInfo);
|
||||
}
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
void getLatencyTimingsNV(VkSwapchainKHR swapchain, uint32_t* pTimingCount, VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo) const noexcept {
|
||||
fp_vkGetLatencyTimingsNV(device, swapchain, pTimingCount, pLatencyMarkerInfo);
|
||||
}
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
void queueNotifyOutOfBandNV(VkQueue queue, VkOutOfBandQueueTypeInfoNV pQueueTypeInfo) const noexcept {
|
||||
fp_vkQueueNotifyOutOfBandNV(queue, pQueueTypeInfo);
|
||||
}
|
||||
#endif
|
||||
PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr;
|
||||
PFN_vkQueueSubmit fp_vkQueueSubmit = nullptr;
|
||||
@ -5665,6 +5705,21 @@ struct DispatchTable {
|
||||
#endif
|
||||
#if (defined(VK_AMDX_shader_enqueue))
|
||||
PFN_vkCmdDispatchGraphIndirectCountAMDX fp_vkCmdDispatchGraphIndirectCountAMDX = nullptr;
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
PFN_vkSetLatencySleepModeNV fp_vkSetLatencySleepModeNV = nullptr;
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
PFN_vkLatencySleepNV fp_vkLatencySleepNV = nullptr;
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
PFN_vkSetLatencyMarkerNV fp_vkSetLatencyMarkerNV = nullptr;
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
PFN_vkGetLatencyTimingsNV fp_vkGetLatencyTimingsNV = nullptr;
|
||||
#endif
|
||||
#if (defined(VK_NV_low_latency2))
|
||||
PFN_vkQueueNotifyOutOfBandNV fp_vkQueueNotifyOutOfBandNV = nullptr;
|
||||
#endif
|
||||
bool is_populated() const { return populated; }
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
|
@ -1,14 +1,31 @@
|
||||
if (WIN32)
|
||||
add_library(VulkanMock SHARED vulkan_mock.hpp vulkan_mock.cpp)
|
||||
# Need to name the target "vulkan-1" so that it'll be loaded instead of the *actual* vulkan-1.dll on the system
|
||||
set_target_properties(VulkanMock PROPERTIES OUTPUT_NAME "vulkan-1")
|
||||
else()
|
||||
add_library(VulkanMock STATIC vulkan_mock.hpp vulkan_mock.cpp)
|
||||
endif()
|
||||
target_link_libraries(VulkanMock
|
||||
PUBLIC
|
||||
vk-bootstrap-vulkan-headers
|
||||
PRIVATE
|
||||
vk-bootstrap-compiler-warnings
|
||||
)
|
||||
target_compile_features(VulkanMock PUBLIC cxx_std_17)
|
||||
|
||||
add_executable(vk-bootstrap-test
|
||||
vulkan_library_loader.hpp
|
||||
bootstrap_tests.cpp
|
||||
error_code_tests.cpp
|
||||
unit_tests.cpp)
|
||||
unit_tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(vk-bootstrap-test
|
||||
PRIVATE
|
||||
vk-bootstrap
|
||||
vk-bootstrap-vulkan-headers
|
||||
vk-bootstrap-compiler-warnings
|
||||
glfw
|
||||
VulkanMock
|
||||
Catch2::Catch2WithMain
|
||||
)
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
#include "common.h"
|
||||
#include "vulkan_library_loader.hpp"
|
||||
|
||||
#include "vulkan_mock.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
@ -14,14 +18,64 @@ vkb::Instance get_headless_instance(uint32_t minor_version = 0) {
|
||||
return instance_ret.value();
|
||||
}
|
||||
|
||||
VkExtensionProperties get_extension_properties(const char* extName) {
|
||||
VkExtensionProperties ext_props{};
|
||||
std::copy_n(extName, VK_MAX_EXTENSION_NAME_SIZE, ext_props.extensionName);
|
||||
return ext_props;
|
||||
}
|
||||
|
||||
VulkanMock& get_and_setup_default() {
|
||||
VulkanMock& mock = get_vulkan_mock();
|
||||
mock.instance_extensions.push_back(get_extension_properties(VK_KHR_SURFACE_EXTENSION_NAME));
|
||||
#if defined(_WIN32)
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_win32_surface"));
|
||||
#elif defined(__ANDROID__)
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_android_surface"));
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_android_surface"));
|
||||
#elif defined(__linux__)
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_xcb_surface"));
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_xlib_surface"));
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_wayland_surface"));
|
||||
#elif defined(__APPLE__)
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_EXT_metal_surface"));
|
||||
#endif
|
||||
mock.instance_extensions.push_back(get_extension_properties(VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
|
||||
VulkanMock::PhysicalDeviceDetails physical_device_details{};
|
||||
physical_device_details.extensions.push_back(get_extension_properties(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
|
||||
physical_device_details.properties.apiVersion = VK_API_VERSION_1_0;
|
||||
VkQueueFamilyProperties queue_family_properties{};
|
||||
queue_family_properties.queueCount = 1;
|
||||
queue_family_properties.queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
|
||||
queue_family_properties.minImageTransferGranularity = { 1, 1, 1 };
|
||||
physical_device_details.queue_family_properties.push_back(queue_family_properties);
|
||||
mock.add_physical_device(std::move(physical_device_details));
|
||||
return mock;
|
||||
}
|
||||
|
||||
VulkanMock::SurfaceDetails get_basic_surface_details() {
|
||||
VulkanMock::SurfaceDetails details;
|
||||
details.present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
|
||||
details.surface_formats.push_back(VkSurfaceFormatKHR{ VK_FORMAT_R8G8B8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR });
|
||||
details.capabilities.minImageCount = 2;
|
||||
details.capabilities.minImageExtent = { 600, 800 };
|
||||
details.capabilities.currentExtent = { 600, 800 };
|
||||
details.capabilities.supportedUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
return details;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// changing present modes and/or image formats
|
||||
|
||||
TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_KHR_multiview"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_KHR_driver_properties"));
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
GIVEN("A window and a vulkan instance") {
|
||||
|
||||
auto window = create_window_glfw("Instance with surface");
|
||||
|
||||
auto sys_info_ret = vkb::SystemInfo::get_system_info();
|
||||
REQUIRE(sys_info_ret);
|
||||
|
||||
@ -32,7 +86,6 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||
.build();
|
||||
REQUIRE(instance_ret);
|
||||
vkb::Instance instance = instance_ret.value();
|
||||
auto surface = create_surface_glfw(instance.instance, window);
|
||||
|
||||
GIVEN("A default selected physical device") {
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance);
|
||||
@ -64,7 +117,6 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||
|
||||
vkb::destroy_surface(instance, surface);
|
||||
vkb::destroy_instance(instance);
|
||||
destroy_window_glfw(window);
|
||||
}
|
||||
GIVEN("Two Instances") {
|
||||
vkb::InstanceBuilder instance_builder1;
|
||||
@ -80,6 +132,7 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
SECTION("custom debug callback") {
|
||||
vkb::InstanceBuilder builder;
|
||||
|
||||
@ -121,6 +174,7 @@ TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
auto instance = get_headless_instance();
|
||||
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance);
|
||||
@ -137,10 +191,11 @@ TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") {
|
||||
|
||||
auto window = create_window_glfw("Device Configuration");
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_1;
|
||||
auto instance = get_instance(1);
|
||||
auto surface = create_surface_glfw(instance.instance, window);
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance);
|
||||
|
||||
@ -198,15 +253,18 @@ TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") {
|
||||
|
||||
|
||||
TEST_CASE("Select all Physical Devices", "[VkBootstrap.bootstrap]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_1;
|
||||
std::copy_n("mocking_gpus_for_fun_and_profit", VK_MAX_DRIVER_NAME_SIZE, mock.physical_devices_details[0].properties.deviceName);
|
||||
|
||||
auto window = create_window_glfw("Select all Physical Devices");
|
||||
auto instance = get_instance(1);
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
|
||||
auto instance_dispatch_table = instance.make_table();
|
||||
// needs to successfully create an instance dispatch table
|
||||
REQUIRE(instance_dispatch_table.fp_vkEnumeratePhysicalDevices);
|
||||
|
||||
auto surface = create_surface_glfw(instance.instance, window);
|
||||
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance, surface);
|
||||
|
||||
@ -229,6 +287,7 @@ TEST_CASE("Select all Physical Devices", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Loading Dispatch Table", "[VkBootstrap.bootstrap]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
auto instance = get_headless_instance(0);
|
||||
{
|
||||
vkb::PhysicalDeviceSelector selector(instance);
|
||||
@ -255,10 +314,12 @@ TEST_CASE("Loading Dispatch Table", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Swapchain", "[VkBootstrap.bootstrap]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_1;
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
GIVEN("A working instance, window, surface, and device") {
|
||||
auto window = create_window_glfw("Swapchain");
|
||||
auto instance = get_instance(1);
|
||||
auto surface = create_surface_glfw(instance.instance, window);
|
||||
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance);
|
||||
auto phys_device_ret = phys_device_selector.set_surface(surface).select();
|
||||
@ -389,12 +450,14 @@ void VKAPI_PTR shim_vkFreeFunction(void* /*pUserData*/, void* pMemory) { return
|
||||
|
||||
|
||||
TEST_CASE("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
|
||||
VkAllocationCallbacks allocation_callbacks{};
|
||||
allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction;
|
||||
allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction;
|
||||
allocation_callbacks.pfnFree = &shim_vkFreeFunction;
|
||||
|
||||
auto window = create_window_glfw("Allocation Callbacks");
|
||||
vkb::InstanceBuilder builder;
|
||||
|
||||
auto instance_ret = builder.request_validation_layers()
|
||||
@ -402,7 +465,6 @@ TEST_CASE("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
|
||||
.use_default_debug_messenger()
|
||||
.build();
|
||||
REQUIRE(instance_ret.has_value());
|
||||
auto surface = create_surface_glfw(instance_ret.value().instance, window, &allocation_callbacks);
|
||||
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(instance_ret.value());
|
||||
|
||||
@ -428,6 +490,7 @@ TEST_CASE("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
auto info_ret = vkb::SystemInfo::get_system_info();
|
||||
REQUIRE(info_ret);
|
||||
vkb::InstanceBuilder builder;
|
||||
@ -436,6 +499,7 @@ TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||
}
|
||||
|
||||
TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
VulkanLibrary vk_lib;
|
||||
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
|
||||
auto info_ret = vkb::SystemInfo::get_system_info(vk_lib.vkGetInstanceProcAddr);
|
||||
@ -447,12 +511,14 @@ TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceBuilder Loading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
vkb::InstanceBuilder builder;
|
||||
auto ret = builder.build();
|
||||
REQUIRE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
VulkanLibrary vk_lib;
|
||||
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
|
||||
vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr };
|
||||
@ -460,6 +526,7 @@ TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
vk_lib.close();
|
||||
}
|
||||
TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
{
|
||||
vkb::InstanceBuilder builder;
|
||||
auto ret = builder.build();
|
||||
@ -473,6 +540,7 @@ TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||
}
|
||||
|
||||
TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
{
|
||||
VulkanLibrary vk_lib;
|
||||
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
|
||||
@ -492,6 +560,13 @@ TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||
}
|
||||
|
||||
TEST_CASE("Querying Required Extension Features but with 1.0", "[VkBootstrap.select_features]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_get_physical_device_properties2"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_EXT_descriptor_indexing"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_KHR_maintenance3"));
|
||||
auto mock_descriptor_indexing_features = VkPhysicalDeviceDescriptorIndexingFeaturesEXT{};
|
||||
mock_descriptor_indexing_features.runtimeDescriptorArray = true;
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_descriptor_indexing_features);
|
||||
GIVEN("A working instance") {
|
||||
auto instance = get_headless_instance();
|
||||
// Requires a device that supports runtime descriptor arrays via descriptor indexing extension.
|
||||
@ -517,6 +592,13 @@ TEST_CASE("Querying Required Extension Features but with 1.0", "[VkBootstrap.sel
|
||||
}
|
||||
}
|
||||
TEST_CASE("Querying Required Extension Features", "[VkBootstrap.select_features]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_get_physical_device_properties2"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_EXT_descriptor_indexing"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_KHR_maintenance3"));
|
||||
auto mock_descriptor_indexing_features = VkPhysicalDeviceDescriptorIndexingFeaturesEXT{};
|
||||
mock_descriptor_indexing_features.runtimeDescriptorArray = true;
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_descriptor_indexing_features);
|
||||
GIVEN("A working instance") {
|
||||
auto instance = get_headless_instance();
|
||||
// Requires a device that supports runtime descriptor arrays via descriptor indexing extension.
|
||||
@ -543,6 +625,8 @@ TEST_CASE("Querying Required Extension Features", "[VkBootstrap.select_features]
|
||||
}
|
||||
|
||||
TEST_CASE("Passing vkb classes to Vulkan handles", "[VkBootstrap.pass_class_to_handle]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
auto surface = mock.get_new_surface(get_basic_surface_details());
|
||||
GIVEN("A working instance") {
|
||||
auto instance = get_instance();
|
||||
|
||||
@ -550,9 +634,6 @@ TEST_CASE("Passing vkb classes to Vulkan handles", "[VkBootstrap.pass_class_to_h
|
||||
PFN_vkVoidFunction instanceFunction = instance.fp_vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"); // validation layers should be provided.
|
||||
REQUIRE(instanceFunction != NULL);
|
||||
|
||||
auto window = create_window_glfw("Conversion operators");
|
||||
auto surface = create_surface_glfw(instance, window);
|
||||
|
||||
vkb::PhysicalDeviceSelector physicalDeviceSelector(instance);
|
||||
auto physicalDevice =
|
||||
physicalDeviceSelector.add_required_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME).set_surface(surface).select();
|
||||
@ -567,8 +648,14 @@ TEST_CASE("Passing vkb classes to Vulkan handles", "[VkBootstrap.pass_class_to_h
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(VKB_VK_API_VERSION_1_1)
|
||||
TEST_CASE("Querying Required Extension Features in 1.1", "[VkBootstrap.version]") {
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_get_physical_device_properties2"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_EXT_descriptor_indexing"));
|
||||
mock.physical_devices_details[0].extensions.push_back(get_extension_properties("VK_KHR_maintenance3"));
|
||||
auto mock_descriptor_indexing_features = VkPhysicalDeviceDescriptorIndexingFeaturesEXT{};
|
||||
mock_descriptor_indexing_features.runtimeDescriptorArray = true;
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_descriptor_indexing_features);
|
||||
GIVEN("A working instance") {
|
||||
auto instance = get_headless_instance();
|
||||
SECTION("Requires a device that supports runtime descriptor arrays via descriptor indexing extension.") {
|
||||
@ -638,10 +725,20 @@ TEST_CASE("Querying Required Extension Features in 1.1", "[VkBootstrap.version]"
|
||||
vkb::destroy_instance(instance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VKB_VK_API_VERSION_1_2)
|
||||
TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_2;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_2;
|
||||
|
||||
auto mock_vulkan_11_features = VkPhysicalDeviceVulkan11Features{};
|
||||
mock_vulkan_11_features.multiview = true;
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_vulkan_11_features);
|
||||
|
||||
auto mock_vulkan_12_features = VkPhysicalDeviceVulkan12Features{};
|
||||
mock_vulkan_12_features.bufferDeviceAddress = true;
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_vulkan_12_features);
|
||||
|
||||
GIVEN("A working instance") {
|
||||
vkb::InstanceBuilder builder;
|
||||
auto instance = get_headless_instance(2); // make sure we use 1.2
|
||||
@ -663,6 +760,8 @@ TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
|
||||
REQUIRE(device_ret.has_value());
|
||||
vkb::destroy_device(device_ret.value());
|
||||
}
|
||||
mock.api_version = VK_API_VERSION_1_1;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_1;
|
||||
SECTION("protectedMemory should NOT be supported") {
|
||||
VkPhysicalDeviceVulkan11Features features_11{};
|
||||
features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
|
||||
@ -676,5 +775,3 @@ TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
|
||||
vkb::destroy_instance(instance);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
168
tests/common.h
168
tests/common.h
@ -1,168 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
#include "../src/VkBootstrap.h"
|
||||
|
||||
GLFWwindow* create_window_glfw(const char* window_name = "", bool resize = true) {
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
if (!resize) glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
|
||||
return glfwCreateWindow(1024, 1024, window_name, NULL, NULL);
|
||||
}
|
||||
void destroy_window_glfw(GLFWwindow* window) {
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
}
|
||||
VkSurfaceKHR create_surface_glfw(
|
||||
VkInstance instance, GLFWwindow* window, VkAllocationCallbacks* allocator = nullptr) {
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
VkResult err = glfwCreateWindowSurface(instance, window, allocator, &surface);
|
||||
if (err) {
|
||||
const char* error_msg;
|
||||
int ret = glfwGetError(&error_msg);
|
||||
if (ret != 0) {
|
||||
std::cout << ret << " ";
|
||||
if (error_msg != nullptr) std::cout << error_msg;
|
||||
std::cout << "\n";
|
||||
}
|
||||
surface = VK_NULL_HANDLE;
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
struct VulkanLibrary {
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
void* library;
|
||||
#elif defined(_WIN32)
|
||||
|
||||
HMODULE library;
|
||||
#endif
|
||||
|
||||
VulkanLibrary() {
|
||||
#if defined(__linux__)
|
||||
library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
|
||||
if (!library) library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||
#elif defined(__APPLE__)
|
||||
library = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||
if (!library) library = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||
#elif defined(_WIN32)
|
||||
library = LoadLibrary(TEXT("vulkan-1.dll"));
|
||||
#else
|
||||
assert(false && "Unsupported platform");
|
||||
#endif
|
||||
if (!library) return;
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
vkGetInstanceProcAddr =
|
||||
reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(library, "vkGetInstanceProcAddr"));
|
||||
#elif defined(_WIN32)
|
||||
vkGetInstanceProcAddr =
|
||||
reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetProcAddress(library, "vkGetInstanceProcAddr"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void close() {
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
dlclose(library);
|
||||
#elif defined(_WIN32)
|
||||
FreeLibrary(library);
|
||||
#endif
|
||||
library = 0;
|
||||
}
|
||||
|
||||
void init(VkInstance instance) {
|
||||
vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");
|
||||
vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR");
|
||||
}
|
||||
|
||||
void init(VkDevice device) {
|
||||
vkCreateRenderPass = (PFN_vkCreateRenderPass)vkGetDeviceProcAddr(device, "vkCreateRenderPass");
|
||||
vkCreateShaderModule = (PFN_vkCreateShaderModule)vkGetDeviceProcAddr(device, "vkCreateShaderModule");
|
||||
vkCreatePipelineLayout =
|
||||
(PFN_vkCreatePipelineLayout)vkGetDeviceProcAddr(device, "vkCreatePipelineLayout");
|
||||
vkCreateGraphicsPipelines =
|
||||
(PFN_vkCreateGraphicsPipelines)vkGetDeviceProcAddr(device, "vkCreateGraphicsPipelines");
|
||||
vkDestroyShaderModule = (PFN_vkDestroyShaderModule)vkGetDeviceProcAddr(device, "vkDestroyShaderModule");
|
||||
vkCreateFramebuffer = (PFN_vkCreateFramebuffer)vkGetDeviceProcAddr(device, "vkCreateFramebuffer");
|
||||
vkCreateCommandPool = (PFN_vkCreateCommandPool)vkGetDeviceProcAddr(device, "vkCreateCommandPool");
|
||||
vkAllocateCommandBuffers =
|
||||
(PFN_vkAllocateCommandBuffers)vkGetDeviceProcAddr(device, "vkAllocateCommandBuffers");
|
||||
vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)vkGetDeviceProcAddr(device, "vkBeginCommandBuffer");
|
||||
vkEndCommandBuffer = (PFN_vkEndCommandBuffer)vkGetDeviceProcAddr(device, "vkEndCommandBuffer");
|
||||
vkCmdSetViewport = (PFN_vkCmdSetViewport)vkGetDeviceProcAddr(device, "vkCmdSetViewport");
|
||||
vkCmdSetScissor = (PFN_vkCmdSetScissor)vkGetDeviceProcAddr(device, "vkCmdSetScissor");
|
||||
vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)vkGetDeviceProcAddr(device, "vkCmdBeginRenderPass");
|
||||
vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)vkGetDeviceProcAddr(device, "vkCmdEndRenderPass");
|
||||
vkCmdBindPipeline = (PFN_vkCmdBindPipeline)vkGetDeviceProcAddr(device, "vkCmdBindPipeline");
|
||||
vkCmdDraw = (PFN_vkCmdDraw)vkGetDeviceProcAddr(device, "vkCmdDraw");
|
||||
vkCreateSemaphore = (PFN_vkCreateSemaphore)vkGetDeviceProcAddr(device, "vkCreateSemaphore");
|
||||
vkCreateFence = (PFN_vkCreateFence)vkGetDeviceProcAddr(device, "vkCreateFence");
|
||||
vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)vkGetDeviceProcAddr(device, "vkDeviceWaitIdle");
|
||||
vkDestroyCommandPool = (PFN_vkDestroyCommandPool)vkGetDeviceProcAddr(device, "vkDestroyCommandPool");
|
||||
vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)vkGetDeviceProcAddr(device, "vkDestroyFramebuffer");
|
||||
vkWaitForFences = (PFN_vkWaitForFences)vkGetDeviceProcAddr(device, "vkWaitForFences");
|
||||
vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)vkGetDeviceProcAddr(device, "vkAcquireNextImageKHR");
|
||||
vkResetFences = (PFN_vkResetFences)vkGetDeviceProcAddr(device, "vkResetFences");
|
||||
vkQueueSubmit = (PFN_vkQueueSubmit)vkGetDeviceProcAddr(device, "vkQueueSubmit");
|
||||
vkQueuePresentKHR = (PFN_vkQueuePresentKHR)vkGetDeviceProcAddr(device, "vkQueuePresentKHR");
|
||||
vkDestroySemaphore = (PFN_vkDestroySemaphore)vkGetDeviceProcAddr(device, "vkDestroySemaphore");
|
||||
vkDestroyFence = (PFN_vkDestroyFence)vkGetDeviceProcAddr(device, "vkDestroyFence");
|
||||
vkDestroyPipeline = (PFN_vkDestroyPipeline)vkGetDeviceProcAddr(device, "vkDestroyPipeline");
|
||||
vkDestroyPipelineLayout =
|
||||
(PFN_vkDestroyPipelineLayout)vkGetDeviceProcAddr(device, "vkDestroyPipelineLayout");
|
||||
vkDestroyRenderPass = (PFN_vkDestroyRenderPass)vkGetDeviceProcAddr(device, "vkDestroyRenderPass");
|
||||
}
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = VK_NULL_HANDLE;
|
||||
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = VK_NULL_HANDLE;
|
||||
|
||||
PFN_vkCreateRenderPass vkCreateRenderPass = VK_NULL_HANDLE;
|
||||
PFN_vkCreateShaderModule vkCreateShaderModule = VK_NULL_HANDLE;
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout = VK_NULL_HANDLE;
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyShaderModule vkDestroyShaderModule = VK_NULL_HANDLE;
|
||||
PFN_vkCreateFramebuffer vkCreateFramebuffer = VK_NULL_HANDLE;
|
||||
PFN_vkCreateCommandPool vkCreateCommandPool = VK_NULL_HANDLE;
|
||||
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = VK_NULL_HANDLE;
|
||||
PFN_vkBeginCommandBuffer vkBeginCommandBuffer = VK_NULL_HANDLE;
|
||||
PFN_vkEndCommandBuffer vkEndCommandBuffer = VK_NULL_HANDLE;
|
||||
PFN_vkCmdSetViewport vkCmdSetViewport = VK_NULL_HANDLE;
|
||||
PFN_vkCmdSetScissor vkCmdSetScissor = VK_NULL_HANDLE;
|
||||
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass = VK_NULL_HANDLE;
|
||||
PFN_vkCmdEndRenderPass vkCmdEndRenderPass = VK_NULL_HANDLE;
|
||||
PFN_vkCmdBindPipeline vkCmdBindPipeline = VK_NULL_HANDLE;
|
||||
PFN_vkCmdDraw vkCmdDraw = VK_NULL_HANDLE;
|
||||
PFN_vkCreateSemaphore vkCreateSemaphore = VK_NULL_HANDLE;
|
||||
PFN_vkCreateFence vkCreateFence = VK_NULL_HANDLE;
|
||||
PFN_vkDeviceWaitIdle vkDeviceWaitIdle = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyCommandPool vkDestroyCommandPool = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyFramebuffer vkDestroyFramebuffer = VK_NULL_HANDLE;
|
||||
PFN_vkWaitForFences vkWaitForFences = VK_NULL_HANDLE;
|
||||
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR = VK_NULL_HANDLE;
|
||||
PFN_vkResetFences vkResetFences = VK_NULL_HANDLE;
|
||||
PFN_vkQueueSubmit vkQueueSubmit = VK_NULL_HANDLE;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR = VK_NULL_HANDLE;
|
||||
PFN_vkDestroySemaphore vkDestroySemaphore = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyFence vkDestroyFence = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyPipeline vkDestroyPipeline = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout = VK_NULL_HANDLE;
|
||||
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = VK_NULL_HANDLE;
|
||||
PFN_vkDestroyRenderPass vkDestroyRenderPass = VK_NULL_HANDLE;
|
||||
};
|
63
tests/vulkan_library_loader.hpp
Normal file
63
tests/vulkan_library_loader.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include "../src/VkBootstrap.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
struct VulkanLibrary {
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
void* library;
|
||||
#elif defined(_WIN32)
|
||||
|
||||
HMODULE library;
|
||||
#endif
|
||||
|
||||
VulkanLibrary() {
|
||||
#if defined(__linux__)
|
||||
library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
|
||||
if (!library) library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||
#elif defined(__APPLE__)
|
||||
library = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||
if (!library) library = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||
#elif defined(_WIN32)
|
||||
library = LoadLibrary(TEXT("vulkan-1.dll"));
|
||||
#else
|
||||
assert(false && "Unsupported platform");
|
||||
#endif
|
||||
if (!library) return;
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(library, "vkGetInstanceProcAddr"));
|
||||
#elif defined(_WIN32)
|
||||
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetProcAddress(library, "vkGetInstanceProcAddr"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void close() {
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
dlclose(library);
|
||||
#elif defined(_WIN32)
|
||||
FreeLibrary(library);
|
||||
#endif
|
||||
library = 0;
|
||||
}
|
||||
|
||||
void init(VkInstance instance) {
|
||||
vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");
|
||||
}
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = VK_NULL_HANDLE;
|
||||
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = VK_NULL_HANDLE;
|
||||
};
|
414
tests/vulkan_mock.cpp
Normal file
414
tests/vulkan_mock.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
|
||||
|
||||
#include "vulkan_mock.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#define GPA_IMPL(x) \
|
||||
if (strcmp(pName, #x) == 0) { \
|
||||
return reinterpret_cast<PFN_vkVoidFunction>(shim_##x); \
|
||||
}
|
||||
|
||||
|
||||
VulkanMock mock;
|
||||
|
||||
EXPORT_MACRO VulkanMock& get_vulkan_mock() {
|
||||
mock = VulkanMock{};
|
||||
return mock;
|
||||
}
|
||||
|
||||
template <typename T> VkResult fill_out_count_pointer_pair(std::vector<T> const& data_vec, uint32_t* pCount, T* pData) {
|
||||
if (pCount == nullptr) {
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
if (pData == nullptr) {
|
||||
if (pCount) *pCount = static_cast<uint32_t>(data_vec.size());
|
||||
return VK_SUCCESS;
|
||||
} else {
|
||||
uint32_t amount_written = 0;
|
||||
uint32_t amount_to_write = static_cast<uint32_t>(data_vec.size());
|
||||
if (*pCount < data_vec.size()) {
|
||||
amount_to_write = *pCount;
|
||||
}
|
||||
for (size_t i = 0; i < amount_to_write; i++) {
|
||||
pData[i] = data_vec[i];
|
||||
amount_written++;
|
||||
}
|
||||
if (*pCount < data_vec.size()) {
|
||||
*pCount = amount_written;
|
||||
return VK_INCOMPLETE;
|
||||
}
|
||||
*pCount = amount_written;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
|
||||
if (pApiVersion == nullptr) {
|
||||
return VK_ERROR_DEVICE_LOST;
|
||||
}
|
||||
*pApiVersion = mock.api_version;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkEnumerateInstanceExtensionProperties(
|
||||
const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) {
|
||||
if (pLayerName) {
|
||||
for (size_t i = 0; i < mock.instance_layers.size(); i++) {
|
||||
if (strcmp(mock.instance_layers[i].layerName, pLayerName) == 0) {
|
||||
return fill_out_count_pointer_pair(mock.per_layer_instance_extension_properties[i], pPropertyCount, pProperties);
|
||||
}
|
||||
}
|
||||
// Layer not found, fill out with empty list
|
||||
return fill_out_count_pointer_pair({}, pPropertyCount, pProperties);
|
||||
}
|
||||
return fill_out_count_pointer_pair(mock.instance_extensions, pPropertyCount, pProperties);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkEnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties) {
|
||||
return fill_out_count_pointer_pair(mock.instance_layers, pPropertyCount, pProperties);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateInstance([[maybe_unused]] const VkInstanceCreateInfo* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkInstance* pInstance) {
|
||||
if (pInstance == nullptr) {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
*pInstance = reinterpret_cast<VkInstance>(0x0000ABCD);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroyInstance(
|
||||
[[maybe_unused]] VkInstance instance, [[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateDebugUtilsMessengerEXT([[maybe_unused]] VkInstance instance,
|
||||
[[maybe_unused]] const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkDebugUtilsMessengerEXT* pMessenger) {
|
||||
if (instance == nullptr) {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
*pMessenger = reinterpret_cast<VkDebugUtilsMessengerEXT>(0xDEBE0000DEBE0000);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroyDebugUtilsMessengerEXT([[maybe_unused]] VkInstance instance,
|
||||
[[maybe_unused]] VkDebugUtilsMessengerEXT messenger,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkEnumeratePhysicalDevices(
|
||||
VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
|
||||
if (instance == nullptr) {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
return fill_out_count_pointer_pair(mock.physical_device_handles, pPhysicalDeviceCount, pPhysicalDevices);
|
||||
}
|
||||
|
||||
VulkanMock::PhysicalDeviceDetails& get_physical_device_details(VkPhysicalDevice physicalDevice) {
|
||||
for (size_t i = 0; i < mock.physical_device_handles.size(); i++) {
|
||||
if (mock.physical_device_handles[i] == physicalDevice) return mock.physical_devices_details[i];
|
||||
}
|
||||
assert(false && "should never reach here!");
|
||||
return mock.physical_devices_details.front();
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) {
|
||||
*pFeatures = get_physical_device_details(physicalDevice).features;
|
||||
}
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) {
|
||||
*pProperties = get_physical_device_details(physicalDevice).properties;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties) {
|
||||
fill_out_count_pointer_pair(
|
||||
get_physical_device_details(physicalDevice).queue_family_properties, pQueueFamilyPropertyCount, pQueueFamilyProperties);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceMemoryProperties(
|
||||
VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) {
|
||||
*pMemoryProperties = get_physical_device_details(physicalDevice).memory_properties;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
|
||||
const auto& phys_dev = get_physical_device_details(physicalDevice);
|
||||
VkBaseOutStructure* current = static_cast<VkBaseOutStructure*>(pFeatures->pNext);
|
||||
while (current) {
|
||||
for (const auto& features_pNext : phys_dev.features_pNextChain) {
|
||||
if (features_pNext->sType == current->sType) {
|
||||
VkBaseOutStructure* next = static_cast<VkBaseOutStructure*>(current->pNext);
|
||||
std::memcpy(current, features_pNext.get(), get_pnext_chain_struct_size(features_pNext->sType));
|
||||
current->pNext = next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = static_cast<VkBaseOutStructure*>(current->pNext);
|
||||
}
|
||||
}
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
|
||||
shim_vkGetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkEnumerateDeviceExtensionProperties(
|
||||
VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) {
|
||||
if (pLayerName) {
|
||||
for (size_t i = 0; i < mock.instance_layers.size(); i++) {
|
||||
if (strcmp(mock.instance_layers[i].layerName, pLayerName) == 0) {
|
||||
return fill_out_count_pointer_pair(mock.per_layer_device_extension_properties[i], pPropertyCount, pProperties);
|
||||
}
|
||||
}
|
||||
// Layer not found, fill out with empty list
|
||||
return fill_out_count_pointer_pair({}, pPropertyCount, pProperties);
|
||||
}
|
||||
return fill_out_count_pointer_pair(get_physical_device_details(physicalDevice).extensions, pPropertyCount, pProperties);
|
||||
}
|
||||
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
[[maybe_unused]] const VkDeviceCreateInfo* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkDevice* pDevice) {
|
||||
if (physicalDevice == nullptr) {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
*pDevice = reinterpret_cast<VkDevice>(0x00FEDC00);
|
||||
get_physical_device_details(physicalDevice).created_devices.push_back(*pDevice);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroyDevice(
|
||||
[[maybe_unused]] VkDevice device, [[maybe_unused]] const VkAllocationCallbacks* pAllocator) {
|
||||
for (auto& physical_devices : mock.physical_devices_details) {
|
||||
auto it = std::find(std::begin(physical_devices.created_devices), std::end(physical_devices.created_devices), device);
|
||||
if (it != std::end(physical_devices.created_devices)) {
|
||||
physical_devices.created_devices.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) {
|
||||
for (auto& physical_devices : mock.physical_devices_details) {
|
||||
auto it = std::find(std::begin(physical_devices.created_devices), std::end(physical_devices.created_devices), device);
|
||||
if (it != std::end(physical_devices.created_devices)) {
|
||||
if (queueFamilyIndex < physical_devices.queue_family_properties.size() &&
|
||||
queueIndex < physical_devices.queue_family_properties[queueFamilyIndex].queueCount) {
|
||||
*pQueue = reinterpret_cast<VkQueue>(0x0000CCEE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateCommandPool([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] const VkCommandPoolCreateInfo* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkCommandPool* pCommandPool) {
|
||||
*pCommandPool = reinterpret_cast<VkCommandPool>(0x0000ABBB);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateFence([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] const VkFenceCreateInfo* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkFence* pFence) {
|
||||
*pFence = reinterpret_cast<VkFence>(0x0000AAAC);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroyFence(
|
||||
[[maybe_unused]] VkDevice device, [[maybe_unused]] VkFence fence, [[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateSwapchainKHR([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkSwapchainKHR* pSwapchain) {
|
||||
*pSwapchain = reinterpret_cast<VkSwapchainKHR>(0x0000FFFE);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetSwapchainImagesKHR(
|
||||
[[maybe_unused]] VkDevice device, [[maybe_unused]] VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) {
|
||||
|
||||
std::vector<VkImage> images = { reinterpret_cast<VkImage>(0x0000EDD0),
|
||||
reinterpret_cast<VkImage>(0x0000EDD1),
|
||||
reinterpret_cast<VkImage>(0x0000EDD1) };
|
||||
return fill_out_count_pointer_pair(images, pSwapchainImageCount, pSwapchainImages);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkCreateImageView([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] const VkImageViewCreateInfo* pCreateInfo,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator,
|
||||
VkImageView* pView) {
|
||||
if (pView) *pView = reinterpret_cast<VkImageView>(0x0000CCCE);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroyImageView([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] VkImageView imageView,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroySwapchainKHR([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] VkSwapchainKHR swapchain,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkAcquireNextImageKHR([[maybe_unused]] VkDevice device,
|
||||
[[maybe_unused]] VkSwapchainKHR swapchain,
|
||||
[[maybe_unused]] uint64_t timeout,
|
||||
[[maybe_unused]] VkSemaphore semaphore,
|
||||
[[maybe_unused]] VkFence fence,
|
||||
[[maybe_unused]] uint32_t* pImageIndex) {
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL shim_vkGetDeviceProcAddr(VkDevice device, const char* pName) {
|
||||
if (device == VK_NULL_HANDLE) {
|
||||
return nullptr;
|
||||
}
|
||||
GPA_IMPL(vkDestroyDevice)
|
||||
GPA_IMPL(vkGetDeviceQueue)
|
||||
GPA_IMPL(vkCreateCommandPool)
|
||||
GPA_IMPL(vkCreateFence)
|
||||
GPA_IMPL(vkDestroyFence)
|
||||
GPA_IMPL(vkCreateSwapchainKHR)
|
||||
GPA_IMPL(vkGetSwapchainImagesKHR)
|
||||
GPA_IMPL(vkCreateImageView)
|
||||
GPA_IMPL(vkDestroyImageView)
|
||||
GPA_IMPL(vkDestroySwapchainKHR)
|
||||
GPA_IMPL(vkAcquireNextImageKHR)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL shim_vkDestroySurfaceKHR([[maybe_unused]] VkInstance instance,
|
||||
[[maybe_unused]] VkSurfaceKHR surface,
|
||||
[[maybe_unused]] const VkAllocationCallbacks* pAllocator) {}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) {
|
||||
|
||||
for (size_t i = 0; i < mock.physical_device_handles.size(); i++) {
|
||||
if (physicalDevice == mock.physical_device_handles[i]) {
|
||||
if (queueFamilyIndex >= mock.physical_devices_details[i].queue_family_properties.size()) {
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (surface && pSupported) *pSupported = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
[[maybe_unused]] VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) {
|
||||
for (size_t i = 0; i < mock.surface_handles.size(); i++) {
|
||||
if (mock.surface_handles[i] == surface) {
|
||||
return fill_out_count_pointer_pair(mock.surface_details[i].surface_formats, pSurfaceFormatCount, pSurfaceFormats);
|
||||
}
|
||||
}
|
||||
return VK_ERROR_SURFACE_LOST_KHR;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
[[maybe_unused]] VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) {
|
||||
for (size_t i = 0; i < mock.surface_handles.size(); i++) {
|
||||
if (mock.surface_handles[i] == surface) {
|
||||
return fill_out_count_pointer_pair(mock.surface_details[i].present_modes, pPresentModeCount, pPresentModes);
|
||||
}
|
||||
}
|
||||
return VK_ERROR_SURFACE_LOST_KHR;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
[[maybe_unused]] VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) {
|
||||
for (size_t i = 0; i < mock.surface_handles.size(); i++) {
|
||||
if (mock.surface_handles[i] == surface) {
|
||||
*pSurfaceCapabilities = mock.surface_details[i].capabilities;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
return VK_ERROR_SURFACE_LOST_KHR;
|
||||
}
|
||||
|
||||
PFN_vkVoidFunction shim_vkGetInstanceProcAddr([[maybe_unused]] VkInstance instance, [[maybe_unused]] const char* pName) {
|
||||
GPA_IMPL(vkEnumerateInstanceVersion)
|
||||
GPA_IMPL(vkEnumerateInstanceExtensionProperties)
|
||||
GPA_IMPL(vkEnumerateInstanceLayerProperties)
|
||||
GPA_IMPL(vkCreateInstance)
|
||||
|
||||
GPA_IMPL(vkDestroyInstance)
|
||||
GPA_IMPL(vkCreateDebugUtilsMessengerEXT)
|
||||
GPA_IMPL(vkDestroyDebugUtilsMessengerEXT)
|
||||
GPA_IMPL(vkEnumeratePhysicalDevices)
|
||||
GPA_IMPL(vkGetPhysicalDeviceFeatures)
|
||||
GPA_IMPL(vkGetPhysicalDeviceFeatures2)
|
||||
GPA_IMPL(vkGetPhysicalDeviceFeatures2KHR)
|
||||
GPA_IMPL(vkGetPhysicalDeviceProperties)
|
||||
GPA_IMPL(vkGetPhysicalDeviceQueueFamilyProperties)
|
||||
GPA_IMPL(vkGetPhysicalDeviceMemoryProperties)
|
||||
GPA_IMPL(vkEnumerateDeviceExtensionProperties)
|
||||
|
||||
GPA_IMPL(vkCreateDevice)
|
||||
GPA_IMPL(vkGetDeviceProcAddr)
|
||||
GPA_IMPL(vkGetDeviceQueue)
|
||||
GPA_IMPL(vkDestroyDevice)
|
||||
|
||||
GPA_IMPL(vkDestroySurfaceKHR)
|
||||
GPA_IMPL(vkGetPhysicalDeviceSurfaceSupportKHR)
|
||||
GPA_IMPL(vkGetPhysicalDeviceSurfaceFormatsKHR)
|
||||
GPA_IMPL(vkGetPhysicalDeviceSurfacePresentModesKHR)
|
||||
GPA_IMPL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
|
||||
|
||||
// Only used by the tests, not by vk-bootstrap
|
||||
GPA_IMPL(vkCreateCommandPool)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
EXPORT_MACRO VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName) {
|
||||
return shim_vkGetInstanceProcAddr(instance, pName);
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__GNU__)
|
||||
#define DLSYM_FUNC_NAME dlsym
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#define DLSYM_FUNC_NAME my_dlsym
|
||||
#endif
|
||||
|
||||
using PFN_DLSYM = void* (*)(void* handle, const char* symbol);
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define real_dlsym dlsym
|
||||
#else
|
||||
PFN_DLSYM real_dlsym = nullptr;
|
||||
#endif
|
||||
|
||||
void* DLSYM_FUNC_NAME([[maybe_unused]] void* handle, const char* symbol) {
|
||||
if (strcmp(symbol, "vkGetInstanceProcAddr") == 0) {
|
||||
return reinterpret_cast<void*>(shim_vkGetInstanceProcAddr);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Shiming functions on apple is limited by the linker prefering to not use functions in the
|
||||
* executable in loaded dylibs. By adding an interposer, we redirect the linker to use our
|
||||
* version of the function over the real one, thus shimming the system function.
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
#define MACOS_ATTRIB __attribute__((section("__DATA,__interpose")))
|
||||
#define VOIDCP_CAST(_func) reinterpret_cast<const void*>(&_func)
|
||||
|
||||
struct Interposer {
|
||||
const void* shim_function;
|
||||
const void* underlying_function;
|
||||
};
|
||||
|
||||
__attribute__((used)) static Interposer _interpose_dlsym MACOS_ATTRIB = { VOIDCP_CAST(my_dlsym), VOIDCP_CAST(dlsym) };
|
||||
|
||||
#endif
|
||||
}
|
95
tests/vulkan_mock.hpp
Normal file
95
tests/vulkan_mock.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
// Helper function to get the size of a struct given a VkStructureType
|
||||
// Hand written, must be updated to include any used struct.
|
||||
inline size_t get_pnext_chain_struct_size(VkStructureType type) {
|
||||
switch (type) {
|
||||
case (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES):
|
||||
return sizeof(VkPhysicalDeviceDescriptorIndexingFeatures);
|
||||
case (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES):
|
||||
return sizeof(VkPhysicalDeviceVulkan11Features);
|
||||
case (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES):
|
||||
return sizeof(VkPhysicalDeviceVulkan12Features);
|
||||
default:
|
||||
assert(false && "Must update get_pnext_chain_struct_size(VkStructureType type) to add type!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VulkanMock {
|
||||
uint32_t api_version = VK_API_VERSION_1_3;
|
||||
std::vector<VkExtensionProperties> instance_extensions;
|
||||
std::vector<VkLayerProperties> instance_layers;
|
||||
std::vector<std::vector<VkExtensionProperties>> per_layer_instance_extension_properties;
|
||||
std::vector<std::vector<VkExtensionProperties>> per_layer_device_extension_properties;
|
||||
|
||||
void add_layer(VkLayerProperties layer_properties,
|
||||
std::vector<VkExtensionProperties> layer_instance_extensions,
|
||||
std::vector<VkExtensionProperties> layer_device_extensions) {
|
||||
instance_layers.push_back(layer_properties);
|
||||
per_layer_instance_extension_properties.push_back(layer_instance_extensions);
|
||||
per_layer_instance_extension_properties.push_back(layer_device_extensions);
|
||||
}
|
||||
|
||||
struct SurfaceDetails {
|
||||
VkSurfaceCapabilitiesKHR capabilities{};
|
||||
std::vector<VkSurfaceFormatKHR> surface_formats;
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
};
|
||||
|
||||
std::vector<VkSurfaceKHR> surface_handles;
|
||||
std::vector<SurfaceDetails> surface_details;
|
||||
|
||||
VkSurfaceKHR get_new_surface(SurfaceDetails details) {
|
||||
size_t new_index = 0x123456789AB + surface_handles.size();
|
||||
surface_handles.push_back(reinterpret_cast<VkSurfaceKHR>(new_index));
|
||||
surface_details.push_back(details);
|
||||
return surface_handles.back();
|
||||
}
|
||||
|
||||
struct PhysicalDeviceDetails {
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
VkPhysicalDeviceFeatures features{};
|
||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||
std::vector<VkExtensionProperties> extensions;
|
||||
std::vector<VkQueueFamilyProperties> queue_family_properties;
|
||||
std::vector<std::unique_ptr<VkBaseOutStructure>> features_pNextChain;
|
||||
|
||||
std::vector<VkDevice> created_devices;
|
||||
|
||||
template <typename T> void add_features_pNext_struct(T t) {
|
||||
T* new_type = new T();
|
||||
*new_type = t;
|
||||
features_pNextChain.emplace_back(reinterpret_cast<VkBaseOutStructure*>(new_type));
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<VkPhysicalDevice> physical_device_handles;
|
||||
std::vector<PhysicalDeviceDetails> physical_devices_details;
|
||||
|
||||
void add_physical_device(PhysicalDeviceDetails details) {
|
||||
size_t new_index = 0x001122334455 + physical_device_handles.size();
|
||||
physical_device_handles.push_back(reinterpret_cast<VkPhysicalDevice>(new_index));
|
||||
physical_devices_details.emplace_back(std::move(details));
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(EXPORT_MACRO)
|
||||
#if defined(WIN32)
|
||||
#define EXPORT_MACRO __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT_MACRO
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXPORT_MACRO VulkanMock& get_vulkan_mock();
|
Loading…
Reference in New Issue
Block a user