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:
Charles Giessen 2023-09-29 17:47:44 -06:00 committed by Charles Giessen
parent 5e351fcdf8
commit d759d3d575
10 changed files with 1262 additions and 669 deletions

View File

@ -5,7 +5,10 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
#include "../tests/common.h" #include <vulkan/vulkan.h>
#include <GLFW/glfw3.h>
#include <VkBootstrap.h>
#include "example_config.h" #include "example_config.h"
@ -13,13 +16,12 @@ const int MAX_FRAMES_IN_FLIGHT = 2;
struct Init { struct Init {
GLFWwindow* window; GLFWwindow* window;
VulkanLibrary vk_lib;
vkb::Instance instance; vkb::Instance instance;
vkb::InstanceDispatchTable inst_disp;
VkSurfaceKHR surface; VkSurfaceKHR surface;
vkb::Device device; vkb::Device device;
vkb::DispatchTable disp;
vkb::Swapchain swapchain; vkb::Swapchain swapchain;
//convenience
VulkanLibrary* operator->(){ return &vk_lib; }
}; };
struct RenderData { struct RenderData {
@ -44,6 +46,35 @@ struct RenderData {
size_t current_frame = 0; size_t current_frame = 0;
}; };
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;
}
int device_initialization(Init& init) { int device_initialization(Init& init) {
init.window = create_window_glfw("Vulkan Triangle", true); init.window = create_window_glfw("Vulkan Triangle", true);
@ -55,7 +86,7 @@ int device_initialization (Init& init) {
} }
init.instance = instance_ret.value(); init.instance = instance_ret.value();
init.vk_lib.init(init.instance); init.inst_disp = init.instance.make_table();
init.surface = create_surface_glfw(init.instance, init.window); init.surface = create_surface_glfw(init.instance, init.window);
@ -74,7 +105,8 @@ int device_initialization (Init& init) {
return -1; return -1;
} }
init.device = device_ret.value(); init.device = device_ret.value();
init.vk_lib.init(init.device);
init.disp = init.device.make_table();
return 0; return 0;
} }
@ -146,7 +178,7 @@ int create_render_pass (Init& init, RenderData& data) {
render_pass_info.dependencyCount = 1; render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = &dependency; render_pass_info.pDependencies = &dependency;
if (init->vkCreateRenderPass (init.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) { if (init.disp.createRenderPass(&render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) {
std::cout << "failed to create render pass\n"; std::cout << "failed to create render pass\n";
return -1; // failed to create render pass! return -1; // failed to create render pass!
} }
@ -178,7 +210,7 @@ VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) {
create_info.pCode = reinterpret_cast<const uint32_t*>(code.data()); create_info.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule; VkShaderModule shaderModule;
if (init->vkCreateShaderModule (init.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) { if (init.disp.createShaderModule(&create_info, nullptr, &shaderModule) != VK_SUCCESS) {
return VK_NULL_HANDLE; // failed to create shader module return VK_NULL_HANDLE; // failed to create shader module
} }
@ -255,8 +287,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | colorBlendAttachment.colorWriteMask =
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE; colorBlendAttachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo color_blending = {}; VkPipelineColorBlendStateCreateInfo color_blending = {};
@ -275,8 +307,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
pipeline_layout_info.setLayoutCount = 0; pipeline_layout_info.setLayoutCount = 0;
pipeline_layout_info.pushConstantRangeCount = 0; pipeline_layout_info.pushConstantRangeCount = 0;
if (init->vkCreatePipelineLayout ( if (init.disp.createPipelineLayout(&pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
init.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
std::cout << "failed to create pipeline layout\n"; std::cout << "failed to create pipeline layout\n";
return -1; // failed to create pipeline layout return -1; // failed to create pipeline layout
} }
@ -304,14 +335,13 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
pipeline_info.subpass = 0; pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE; pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
if (init->vkCreateGraphicsPipelines ( if (init.disp.createGraphicsPipelines(VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
init.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
std::cout << "failed to create pipline\n"; std::cout << "failed to create pipline\n";
return -1; // failed to create graphics pipeline return -1; // failed to create graphics pipeline
} }
init->vkDestroyShaderModule (init.device, frag_module, nullptr); init.disp.destroyShaderModule(frag_module, nullptr);
init->vkDestroyShaderModule (init.device, vert_module, nullptr); init.disp.destroyShaderModule(vert_module, nullptr);
return 0; return 0;
} }
@ -333,7 +363,7 @@ int create_framebuffers (Init& init, RenderData& data) {
framebuffer_info.height = init.swapchain.extent.height; framebuffer_info.height = init.swapchain.extent.height;
framebuffer_info.layers = 1; framebuffer_info.layers = 1;
if (init->vkCreateFramebuffer (init.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) { if (init.disp.createFramebuffer(&framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) {
return -1; // failed to create framebuffer return -1; // failed to create framebuffer
} }
} }
@ -345,7 +375,7 @@ int create_command_pool (Init& init, RenderData& data) {
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.queueFamilyIndex = init.device.get_queue_index(vkb::QueueType::graphics).value(); pool_info.queueFamilyIndex = init.device.get_queue_index(vkb::QueueType::graphics).value();
if (init->vkCreateCommandPool (init.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) { if (init.disp.createCommandPool(&pool_info, nullptr, &data.command_pool) != VK_SUCCESS) {
std::cout << "failed to create command pool\n"; std::cout << "failed to create command pool\n";
return -1; // failed to create command pool return -1; // failed to create command pool
} }
@ -361,7 +391,7 @@ int create_command_buffers (Init& init, RenderData& data) {
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size(); allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size();
if (init->vkAllocateCommandBuffers (init.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS) { if (init.disp.allocateCommandBuffers(&allocInfo, data.command_buffers.data()) != VK_SUCCESS) {
return -1; // failed to allocate command buffers; return -1; // failed to allocate command buffers;
} }
@ -369,7 +399,7 @@ int create_command_buffers (Init& init, RenderData& data) {
VkCommandBufferBeginInfo begin_info = {}; VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (init->vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) { if (init.disp.beginCommandBuffer(data.command_buffers[i], &begin_info) != VK_SUCCESS) {
return -1; // failed to begin recording command buffer return -1; // failed to begin recording command buffer
} }
@ -395,18 +425,18 @@ int create_command_buffers (Init& init, RenderData& data) {
scissor.offset = { 0, 0 }; scissor.offset = { 0, 0 };
scissor.extent = init.swapchain.extent; scissor.extent = init.swapchain.extent;
init->vkCmdSetViewport (data.command_buffers[i], 0, 1, &viewport); init.disp.cmdSetViewport(data.command_buffers[i], 0, 1, &viewport);
init->vkCmdSetScissor (data.command_buffers[i], 0, 1, &scissor); init.disp.cmdSetScissor(data.command_buffers[i], 0, 1, &scissor);
init->vkCmdBeginRenderPass (data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); init.disp.cmdBeginRenderPass(data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
init->vkCmdBindPipeline (data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline); init.disp.cmdBindPipeline(data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline);
init->vkCmdDraw (data.command_buffers[i], 3, 1, 0, 0); init.disp.cmdDraw(data.command_buffers[i], 3, 1, 0, 0);
init->vkCmdEndRenderPass (data.command_buffers[i]); init.disp.cmdEndRenderPass(data.command_buffers[i]);
if (init->vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) { if (init.disp.endCommandBuffer(data.command_buffers[i]) != VK_SUCCESS) {
std::cout << "failed to record command buffer\n"; std::cout << "failed to record command buffer\n";
return -1; // failed to record command buffer! return -1; // failed to record command buffer!
} }
@ -428,9 +458,9 @@ int create_sync_objects (Init& init, RenderData& data) {
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (init->vkCreateSemaphore (init.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS || if (init.disp.createSemaphore(&semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS ||
init->vkCreateSemaphore (init.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS || init.disp.createSemaphore(&semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS ||
init->vkCreateFence (init.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) { init.disp.createFence(&fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) {
std::cout << "failed to create sync objects\n"; std::cout << "failed to create sync objects\n";
return -1; // failed to create synchronization objects for a frame return -1; // failed to create synchronization objects for a frame
} }
@ -439,12 +469,12 @@ int create_sync_objects (Init& init, RenderData& data) {
} }
int recreate_swapchain(Init& init, RenderData& data) { int recreate_swapchain(Init& init, RenderData& data) {
init->vkDeviceWaitIdle (init.device); init.disp.deviceWaitIdle();
init->vkDestroyCommandPool (init.device, data.command_pool, nullptr); init.disp.destroyCommandPool(data.command_pool, nullptr);
for (auto framebuffer : data.framebuffers) { for (auto framebuffer : data.framebuffers) {
init->vkDestroyFramebuffer (init.device, framebuffer, nullptr); init.disp.destroyFramebuffer(framebuffer, nullptr);
} }
init.swapchain.destroy_image_views(data.swapchain_image_views); init.swapchain.destroy_image_views(data.swapchain_image_views);
@ -457,15 +487,11 @@ int recreate_swapchain (Init& init, RenderData& data) {
} }
int draw_frame(Init& init, RenderData& data) { int draw_frame(Init& init, RenderData& data) {
init->vkWaitForFences (init.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX); init.disp.waitForFences(1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
uint32_t image_index = 0; uint32_t image_index = 0;
VkResult result = init->vkAcquireNextImageKHR (init.device, VkResult result = init.disp.acquireNextImageKHR(
init.swapchain, init.swapchain, UINT64_MAX, data.available_semaphores[data.current_frame], VK_NULL_HANDLE, &image_index);
UINT64_MAX,
data.available_semaphores[data.current_frame],
VK_NULL_HANDLE,
&image_index);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
return recreate_swapchain(init, data); return recreate_swapchain(init, data);
@ -475,7 +501,7 @@ int draw_frame (Init& init, RenderData& data) {
} }
if (data.image_in_flight[image_index] != VK_NULL_HANDLE) { if (data.image_in_flight[image_index] != VK_NULL_HANDLE) {
init->vkWaitForFences (init.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX); init.disp.waitForFences(1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX);
} }
data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame]; data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame];
@ -495,9 +521,9 @@ int draw_frame (Init& init, RenderData& data) {
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signal_semaphores; submitInfo.pSignalSemaphores = signal_semaphores;
init->vkResetFences (init.device, 1, &data.in_flight_fences[data.current_frame]); init.disp.resetFences(1, &data.in_flight_fences[data.current_frame]);
if (init->vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) { if (init.disp.queueSubmit(data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) {
std::cout << "failed to submit draw command buffer\n"; std::cout << "failed to submit draw command buffer\n";
return -1; //"failed to submit draw command buffer return -1; //"failed to submit draw command buffer
} }
@ -514,7 +540,7 @@ int draw_frame (Init& init, RenderData& data) {
present_info.pImageIndices = &image_index; present_info.pImageIndices = &image_index;
result = init->vkQueuePresentKHR (data.present_queue, &present_info); result = init.disp.queuePresentKHR(data.present_queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
return recreate_swapchain(init, data); return recreate_swapchain(init, data);
} else if (result != VK_SUCCESS) { } else if (result != VK_SUCCESS) {
@ -528,20 +554,20 @@ int draw_frame (Init& init, RenderData& data) {
void cleanup(Init& init, RenderData& data) { void cleanup(Init& init, RenderData& data) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
init->vkDestroySemaphore (init.device, data.finished_semaphore[i], nullptr); init.disp.destroySemaphore(data.finished_semaphore[i], nullptr);
init->vkDestroySemaphore (init.device, data.available_semaphores[i], nullptr); init.disp.destroySemaphore(data.available_semaphores[i], nullptr);
init->vkDestroyFence (init.device, data.in_flight_fences[i], nullptr); init.disp.destroyFence(data.in_flight_fences[i], nullptr);
} }
init->vkDestroyCommandPool (init.device, data.command_pool, nullptr); init.disp.destroyCommandPool(data.command_pool, nullptr);
for (auto framebuffer : data.framebuffers) { for (auto framebuffer : data.framebuffers) {
init->vkDestroyFramebuffer (init.device, framebuffer, nullptr); init.disp.destroyFramebuffer(framebuffer, nullptr);
} }
init->vkDestroyPipeline (init.device, data.graphics_pipeline, nullptr); init.disp.destroyPipeline(data.graphics_pipeline, nullptr);
init->vkDestroyPipelineLayout (init.device, data.pipeline_layout, nullptr); init.disp.destroyPipelineLayout(data.pipeline_layout, nullptr);
init->vkDestroyRenderPass (init.device, data.render_pass, nullptr); init.disp.destroyRenderPass(data.render_pass, nullptr);
init.swapchain.destroy_image_views(data.swapchain_image_views); init.swapchain.destroy_image_views(data.swapchain_image_views);
@ -574,7 +600,7 @@ int main () {
return -1; return -1;
} }
} }
init->vkDeviceWaitIdle (init.device); init.disp.deviceWaitIdle();
cleanup(init, render_data); cleanup(init, render_data);
return 0; return 0;

View File

@ -1,2 +1,2 @@
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION 1.3.265) set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION 1.3.266)
set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION_GIT_TAG v1.3.265) set(VK_BOOTSTRAP_SOURCE_HEADER_VERSION_GIT_TAG v1.3.266)

View File

@ -133,26 +133,22 @@ class VulkanFunctions {
PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = nullptr; PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = nullptr;
PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = nullptr; PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = nullptr;
PFN_vkCreateInstance fp_vkCreateInstance = 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_vkEnumeratePhysicalDevices fp_vkEnumeratePhysicalDevices = nullptr;
PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = nullptr; PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = nullptr;
PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = nullptr; PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = nullptr;
PFN_vkGetPhysicalDeviceFeatures2KHR fp_vkGetPhysicalDeviceFeatures2KHR = nullptr; PFN_vkGetPhysicalDeviceFeatures2KHR fp_vkGetPhysicalDeviceFeatures2KHR = nullptr;
PFN_vkGetPhysicalDeviceFormatProperties fp_vkGetPhysicalDeviceFormatProperties = nullptr;
PFN_vkGetPhysicalDeviceImageFormatProperties fp_vkGetPhysicalDeviceImageFormatProperties = nullptr;
PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = nullptr; PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = nullptr;
PFN_vkGetPhysicalDeviceProperties2 fp_vkGetPhysicalDeviceProperties2 = nullptr;
PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties = nullptr; PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fp_vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
PFN_vkGetPhysicalDeviceMemoryProperties fp_vkGetPhysicalDeviceMemoryProperties = 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_vkEnumerateDeviceExtensionProperties fp_vkEnumerateDeviceExtensionProperties = nullptr;
PFN_vkCreateDevice fp_vkCreateDevice = nullptr;
PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = nullptr; PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fp_vkGetPhysicalDeviceSurfaceSupportKHR = nullptr; PFN_vkGetPhysicalDeviceSurfaceSupportKHR fp_vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fp_vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fp_vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
@ -169,24 +165,21 @@ class VulkanFunctions {
void init_instance_funcs(VkInstance inst) { void init_instance_funcs(VkInstance inst) {
instance = inst; instance = inst;
get_inst_proc_addr(fp_vkDestroyInstance, "vkDestroyInstance"); 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_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices");
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures"); get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures");
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2"); get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2");
get_inst_proc_addr(fp_vkGetPhysicalDeviceFeatures2KHR, "vkGetPhysicalDeviceFeatures2KHR"); 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_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
get_inst_proc_addr(fp_vkGetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2");
get_inst_proc_addr(fp_vkGetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties"); 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_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_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_vkDestroySurfaceKHR, "vkDestroySurfaceKHR");
get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR"); get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR");
get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR"); get_inst_proc_addr(fp_vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR");
@ -269,11 +262,9 @@ VkResult create_debug_utils_messenger(VkInstance instance,
messengerCreateInfo.pfnUserCallback = debug_callback; messengerCreateInfo.pfnUserCallback = debug_callback;
messengerCreateInfo.pUserData = user_data_pointer; messengerCreateInfo.pUserData = user_data_pointer;
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc; if (detail::vulkan_functions().fp_vkCreateDebugUtilsMessengerEXT != nullptr) {
detail::vulkan_functions().get_inst_proc_addr(createMessengerFunc, "vkCreateDebugUtilsMessengerEXT"); return detail::vulkan_functions().fp_vkCreateDebugUtilsMessengerEXT(
instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
if (createMessengerFunc != nullptr) {
return createMessengerFunc(instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
} else { } else {
return VK_ERROR_EXTENSION_NOT_PRESENT; return VK_ERROR_EXTENSION_NOT_PRESENT;
} }
@ -282,11 +273,8 @@ VkResult create_debug_utils_messenger(VkInstance instance,
void destroy_debug_utils_messenger( void destroy_debug_utils_messenger(
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) { VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc; if (detail::vulkan_functions().fp_vkDestroyDebugUtilsMessengerEXT != nullptr) {
detail::vulkan_functions().get_inst_proc_addr(deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT"); detail::vulkan_functions().fp_vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, allocation_callbacks);
if (deleteMessengerFunc != nullptr) {
deleteMessengerFunc(instance, debugMessenger, allocation_callbacks);
} }
} }
@ -930,7 +918,13 @@ bool supports_features(VkPhysicalDeviceFeatures supported,
if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false; if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false;
if (requested.inheritedQueries && !supported.inheritedQueries) 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]); auto res = GenericFeaturesPNextNode::match(extension_requested[i], extension_supported[i]);
if(!res) return false; if(!res) return false;
} }

View File

@ -2236,6 +2236,21 @@ struct DispatchTable {
#endif #endif
#if (defined(VK_AMDX_shader_enqueue)) #if (defined(VK_AMDX_shader_enqueue))
fp_vkCmdDispatchGraphIndirectCountAMDX = reinterpret_cast<PFN_vkCmdDispatchGraphIndirectCountAMDX>(procAddr(device, "vkCmdDispatchGraphIndirectCountAMDX")); 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 #endif
} }
void getDeviceQueue(uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) const noexcept { 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 { void cmdDispatchGraphIndirectCountAMDX(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceAddress countInfo) const noexcept {
fp_vkCmdDispatchGraphIndirectCountAMDX(commandBuffer, scratch, countInfo); 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 #endif
PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr; PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr;
PFN_vkQueueSubmit fp_vkQueueSubmit = nullptr; PFN_vkQueueSubmit fp_vkQueueSubmit = nullptr;
@ -5665,6 +5705,21 @@ struct DispatchTable {
#endif #endif
#if (defined(VK_AMDX_shader_enqueue)) #if (defined(VK_AMDX_shader_enqueue))
PFN_vkCmdDispatchGraphIndirectCountAMDX fp_vkCmdDispatchGraphIndirectCountAMDX = nullptr; 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 #endif
bool is_populated() const { return populated; } bool is_populated() const { return populated; }
VkDevice device = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE;

View File

@ -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 add_executable(vk-bootstrap-test
vulkan_library_loader.hpp
bootstrap_tests.cpp bootstrap_tests.cpp
error_code_tests.cpp error_code_tests.cpp
unit_tests.cpp) unit_tests.cpp
)
target_link_libraries(vk-bootstrap-test target_link_libraries(vk-bootstrap-test
PRIVATE PRIVATE
vk-bootstrap vk-bootstrap
vk-bootstrap-vulkan-headers vk-bootstrap-vulkan-headers
vk-bootstrap-compiler-warnings vk-bootstrap-compiler-warnings
glfw VulkanMock
Catch2::Catch2WithMain Catch2::Catch2WithMain
) )

View File

@ -1,4 +1,8 @@
#include "common.h" #include "vulkan_library_loader.hpp"
#include "vulkan_mock.hpp"
#include <algorithm>
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
@ -14,14 +18,64 @@ vkb::Instance get_headless_instance(uint32_t minor_version = 0) {
return instance_ret.value(); 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 // TODO
// changing present modes and/or image formats // changing present modes and/or image formats
TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") { 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") { GIVEN("A window and a vulkan instance") {
auto window = create_window_glfw("Instance with surface");
auto sys_info_ret = vkb::SystemInfo::get_system_info(); auto sys_info_ret = vkb::SystemInfo::get_system_info();
REQUIRE(sys_info_ret); REQUIRE(sys_info_ret);
@ -32,7 +86,6 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
.build(); .build();
REQUIRE(instance_ret); REQUIRE(instance_ret);
vkb::Instance instance = instance_ret.value(); vkb::Instance instance = instance_ret.value();
auto surface = create_surface_glfw(instance.instance, window);
GIVEN("A default selected physical device") { GIVEN("A default selected physical device") {
vkb::PhysicalDeviceSelector phys_device_selector(instance); vkb::PhysicalDeviceSelector phys_device_selector(instance);
@ -64,7 +117,6 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
vkb::destroy_surface(instance, surface); vkb::destroy_surface(instance, surface);
vkb::destroy_instance(instance); vkb::destroy_instance(instance);
destroy_window_glfw(window);
} }
GIVEN("Two Instances") { GIVEN("Two Instances") {
vkb::InstanceBuilder instance_builder1; vkb::InstanceBuilder instance_builder1;
@ -80,6 +132,7 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
} }
TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") { TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
SECTION("custom debug callback") { SECTION("custom debug callback") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
@ -121,6 +174,7 @@ TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") {
} }
TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") { TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
auto instance = get_headless_instance(); auto instance = get_headless_instance();
vkb::PhysicalDeviceSelector phys_device_selector(instance); vkb::PhysicalDeviceSelector phys_device_selector(instance);
@ -137,10 +191,11 @@ TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") {
} }
TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") { TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") {
VulkanMock& mock = get_and_setup_default();
auto window = create_window_glfw("Device Configuration"); 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 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); vkb::PhysicalDeviceSelector phys_device_selector(instance);
@ -198,15 +253,18 @@ TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") {
TEST_CASE("Select all Physical Devices", "[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 instance = get_instance(1);
auto surface = mock.get_new_surface(get_basic_surface_details());
auto instance_dispatch_table = instance.make_table(); auto instance_dispatch_table = instance.make_table();
// needs to successfully create an instance dispatch table // needs to successfully create an instance dispatch table
REQUIRE(instance_dispatch_table.fp_vkEnumeratePhysicalDevices); REQUIRE(instance_dispatch_table.fp_vkEnumeratePhysicalDevices);
auto surface = create_surface_glfw(instance.instance, window);
vkb::PhysicalDeviceSelector phys_device_selector(instance, surface); 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]") { TEST_CASE("Loading Dispatch Table", "[VkBootstrap.bootstrap]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
auto instance = get_headless_instance(0); auto instance = get_headless_instance(0);
{ {
vkb::PhysicalDeviceSelector selector(instance); vkb::PhysicalDeviceSelector selector(instance);
@ -255,10 +314,12 @@ TEST_CASE("Loading Dispatch Table", "[VkBootstrap.bootstrap]") {
} }
TEST_CASE("Swapchain", "[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") { GIVEN("A working instance, window, surface, and device") {
auto window = create_window_glfw("Swapchain");
auto instance = get_instance(1); auto instance = get_instance(1);
auto surface = create_surface_glfw(instance.instance, window);
vkb::PhysicalDeviceSelector phys_device_selector(instance); vkb::PhysicalDeviceSelector phys_device_selector(instance);
auto phys_device_ret = phys_device_selector.set_surface(surface).select(); 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]") { 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{}; VkAllocationCallbacks allocation_callbacks{};
allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction; allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction;
allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction; allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction;
allocation_callbacks.pfnFree = &shim_vkFreeFunction; allocation_callbacks.pfnFree = &shim_vkFreeFunction;
auto window = create_window_glfw("Allocation Callbacks");
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = builder.request_validation_layers() auto instance_ret = builder.request_validation_layers()
@ -402,7 +465,6 @@ TEST_CASE("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
.use_default_debug_messenger() .use_default_debug_messenger()
.build(); .build();
REQUIRE(instance_ret.has_value()); 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()); 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]") { TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
auto info_ret = vkb::SystemInfo::get_system_info(); auto info_ret = vkb::SystemInfo::get_system_info();
REQUIRE(info_ret); REQUIRE(info_ret);
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
@ -436,6 +499,7 @@ TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
} }
TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
auto info_ret = vkb::SystemInfo::get_system_info(vk_lib.vkGetInstanceProcAddr); 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]") { TEST_CASE("InstanceBuilder Loading Vulkan Automatically", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build(); auto ret = builder.build();
REQUIRE(ret); REQUIRE(ret);
} }
TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr }; vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr };
@ -460,6 +526,7 @@ TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
vk_lib.close(); vk_lib.close();
} }
TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") { TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
{ {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build(); auto ret = builder.build();
@ -473,6 +540,7 @@ TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
} }
TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
{ {
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL); 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]") { 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") { GIVEN("A working instance") {
auto instance = get_headless_instance(); auto instance = get_headless_instance();
// Requires a device that supports runtime descriptor arrays via descriptor indexing extension. // 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]") { 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") { GIVEN("A working instance") {
auto instance = get_headless_instance(); auto instance = get_headless_instance();
// Requires a device that supports runtime descriptor arrays via descriptor indexing extension. // 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]") { 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") { GIVEN("A working instance") {
auto instance = get_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. PFN_vkVoidFunction instanceFunction = instance.fp_vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"); // validation layers should be provided.
REQUIRE(instanceFunction != NULL); REQUIRE(instanceFunction != NULL);
auto window = create_window_glfw("Conversion operators");
auto surface = create_surface_glfw(instance, window);
vkb::PhysicalDeviceSelector physicalDeviceSelector(instance); vkb::PhysicalDeviceSelector physicalDeviceSelector(instance);
auto physicalDevice = auto physicalDevice =
physicalDeviceSelector.add_required_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME).set_surface(surface).select(); 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]") { 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") { GIVEN("A working instance") {
auto instance = get_headless_instance(); auto instance = get_headless_instance();
SECTION("Requires a device that supports runtime descriptor arrays via descriptor indexing extension.") { 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); 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]") { 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") { GIVEN("A working instance") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance = get_headless_instance(2); // make sure we use 1.2 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()); REQUIRE(device_ret.has_value());
vkb::destroy_device(device_ret.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") { SECTION("protectedMemory should NOT be supported") {
VkPhysicalDeviceVulkan11Features features_11{}; VkPhysicalDeviceVulkan11Features features_11{};
features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 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); vkb::destroy_instance(instance);
} }
} }
#endif

View File

@ -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;
};

View 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
View 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
View 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();