Last active
October 21, 2024 12:12
-
-
Save mcourteaux/dfb43c14be90119dd20af4c91293ece9 to your computer and use it in GitHub Desktop.
Vulkan FPS test app X11/Wayland and different present modes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define VULKAN_ENABLE_LUNARG_VALIDATION | |
#include <stdarg.h> | |
#include <stdint.h> | |
#include <SDL2/SDL.h> | |
#include <SDL2/SDL_syswm.h> | |
#include <SDL2/SDL_timer.h> | |
#define VK_USE_PLATFORM_LINUX_KHR | |
#define VK_USE_PLATFORM_WAYLAND_KHR | |
#define VK_USE_PLATFORM_XLIB_KHR | |
#include <vulkan/vulkan.h> | |
enum { | |
MAX_DEVICE_COUNT = 8, | |
MAX_QUEUE_COUNT = 4, // ATM there should be at most transfer, graphics, | |
// compute, graphics+compute families | |
MAX_PRESENT_MODE_COUNT = 6, // At the moment in spec | |
MAX_SWAPCHAIN_IMAGES = 10, | |
FRAME_COUNT = 3, | |
PRESENT_MODE_MAILBOX_IMAGE_COUNT = 3, | |
PRESENT_MODE_DEFAULT_IMAGE_COUNT = 2, | |
}; | |
static uint32_t clamp_u32(uint32_t value, uint32_t min, uint32_t max) { | |
return value < min ? min : (value > max ? max : value); | |
} | |
//---------------------------------------------------------- | |
const VkApplicationInfo appInfo = { | |
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
.pApplicationName = "Vulkan SDL tutorial", | |
.applicationVersion = VK_MAKE_VERSION(1, 0, 0), | |
.pEngineName = "No Engine", | |
.engineVersion = VK_MAKE_VERSION(1, 0, 0), | |
.apiVersion = VK_API_VERSION_1_0, | |
}; | |
const VkInstanceCreateInfo createInfo = { | |
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
.pApplicationInfo = &appInfo, | |
.enabledExtensionCount = 3, | |
.ppEnabledExtensionNames = | |
(const char *const[]){VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, | |
VK_KHR_SURFACE_EXTENSION_NAME, | |
VK_KHR_XLIB_SURFACE_EXTENSION_NAME}, | |
}; | |
#ifdef VULKAN_ENABLE_LUNARG_VALIDATION | |
const VkInstanceCreateInfo createInfoLunarGValidation = { | |
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
.pApplicationInfo = &appInfo, | |
.enabledLayerCount = 1, | |
.ppEnabledLayerNames = | |
(const char *const[]){"VK_LAYER_LUNARG_standard_validation"}, | |
.enabledExtensionCount = 4, | |
.ppEnabledExtensionNames = | |
(const char *const[]){VK_KHR_SURFACE_EXTENSION_NAME, | |
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, | |
VK_KHR_XLIB_SURFACE_EXTENSION_NAME, | |
VK_EXT_DEBUG_REPORT_EXTENSION_NAME}, | |
}; | |
PFN_vkCreateDebugReportCallbackEXT vkpfn_CreateDebugReportCallbackEXT = 0; | |
PFN_vkDestroyDebugReportCallbackEXT vkpfn_DestroyDebugReportCallbackEXT = 0; | |
VkDebugReportCallbackEXT debugCallback = VK_NULL_HANDLE; | |
static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanReportFunc( | |
VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, | |
uint64_t obj, size_t location, int32_t code, const char *layerPrefix, | |
const char *msg, void *userData) { | |
printf("VULKAN VALIDATION: %s\n", msg); | |
return VK_FALSE; | |
} | |
VkDebugReportCallbackCreateInfoEXT debugCallbackCreateInfo = { | |
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, | |
.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, | |
.pfnCallback = VulkanReportFunc, | |
}; | |
#endif | |
VkInstance instance = VK_NULL_HANDLE; | |
int init_vulkan() { | |
VkResult result = VK_ERROR_INITIALIZATION_FAILED; | |
#ifdef VULKAN_ENABLE_LUNARG_VALIDATION | |
result = vkCreateInstance(&createInfoLunarGValidation, 0, &instance); | |
if (result == VK_SUCCESS) { | |
vkpfn_CreateDebugReportCallbackEXT = | |
(PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( | |
instance, "vkCreateDebugReportCallbackEXT"); | |
vkpfn_DestroyDebugReportCallbackEXT = | |
(PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( | |
instance, "vkDestroyDebugReportCallbackEXT"); | |
if (vkpfn_CreateDebugReportCallbackEXT && | |
vkpfn_DestroyDebugReportCallbackEXT) { | |
vkpfn_CreateDebugReportCallbackEXT(instance, &debugCallbackCreateInfo, 0, | |
&debugCallback); | |
} | |
} | |
#endif | |
if (result != VK_SUCCESS) { | |
result = vkCreateInstance(&createInfo, 0, &instance); | |
} | |
return result == VK_SUCCESS; | |
} | |
void fini_vulkan() { | |
#ifdef VULKAN_ENABLE_LUNARG_VALIDATION | |
if (vkpfn_DestroyDebugReportCallbackEXT && debugCallback) { | |
vkpfn_DestroyDebugReportCallbackEXT(instance, debugCallback, 0); | |
} | |
#endif | |
vkDestroyInstance(instance, 0); | |
} | |
//---------------------------------------------------------- | |
SDL_Window *window = 0; | |
VkSurfaceKHR surface = VK_NULL_HANDLE; | |
uint32_t width = 1920; | |
uint32_t height = 1080; | |
int init_window() { | |
SDL_Window *window = | |
SDL_CreateWindow("Vulkan Sample", SDL_WINDOWPOS_CENTERED, | |
SDL_WINDOWPOS_CENTERED, width, height, 0); | |
SDL_SysWMinfo info; | |
SDL_VERSION(&info.version); | |
SDL_GetWindowWMInfo(window, &info); | |
VkResult result; | |
if (info.subsystem == SDL_SYSWM_WAYLAND) { | |
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = { | |
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR}; | |
surfaceCreateInfo.display = info.info.wl.display; | |
surfaceCreateInfo.surface = info.info.wl.surface; | |
result = | |
vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface); | |
printf("Created Wayland Surface: %d\n", result); | |
} else if (info.subsystem == SDL_SYSWM_X11) { | |
VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = { | |
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR}; | |
surfaceCreateInfo.dpy = info.info.x11.display; | |
surfaceCreateInfo.window = info.info.x11.window; | |
result = vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface); | |
printf("Created X11 Surface: %d\n", result); | |
} else { | |
printf("Unknown window system.\n"); | |
return 0; | |
} | |
return window != 0 && result == VK_SUCCESS; | |
} | |
void fini_window() { | |
vkDestroySurfaceKHR(instance, surface, 0); | |
SDL_DestroyWindow(window); | |
} | |
//---------------------------------------------------------- | |
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; | |
uint32_t queueFamilyIndex; | |
VkQueue queue; | |
VkDevice device = VK_NULL_HANDLE; | |
VkDeviceCreateInfo deviceCreateInfo = { | |
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
.queueCreateInfoCount = 1, | |
.pQueueCreateInfos = 0, | |
.enabledLayerCount = 0, | |
.ppEnabledLayerNames = 0, | |
.enabledExtensionCount = 1, | |
.ppEnabledExtensionNames = | |
(const char *const[]){VK_KHR_SWAPCHAIN_EXTENSION_NAME}, | |
.pEnabledFeatures = 0, | |
}; | |
int init_device() { | |
uint32_t physicalDeviceCount; | |
VkPhysicalDevice deviceHandles[MAX_DEVICE_COUNT]; | |
VkQueueFamilyProperties queueFamilyProperties[MAX_QUEUE_COUNT]; | |
VkPhysicalDeviceProperties deviceProperties; | |
VkPhysicalDeviceFeatures deviceFeatures; | |
VkPhysicalDeviceMemoryProperties deviceMemoryProperties; | |
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, 0); | |
physicalDeviceCount = physicalDeviceCount > MAX_DEVICE_COUNT | |
? MAX_DEVICE_COUNT | |
: physicalDeviceCount; | |
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, deviceHandles); | |
for (uint32_t i = 0; i < physicalDeviceCount; ++i) { | |
uint32_t queueFamilyCount = 0; | |
vkGetPhysicalDeviceQueueFamilyProperties(deviceHandles[i], | |
&queueFamilyCount, NULL); | |
queueFamilyCount = | |
queueFamilyCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueFamilyCount; | |
vkGetPhysicalDeviceQueueFamilyProperties( | |
deviceHandles[i], &queueFamilyCount, queueFamilyProperties); | |
vkGetPhysicalDeviceProperties(deviceHandles[i], &deviceProperties); | |
vkGetPhysicalDeviceFeatures(deviceHandles[i], &deviceFeatures); | |
vkGetPhysicalDeviceMemoryProperties(deviceHandles[i], | |
&deviceMemoryProperties); | |
for (uint32_t j = 0; j < queueFamilyCount; ++j) { | |
VkBool32 supportsPresent = VK_FALSE; | |
vkGetPhysicalDeviceSurfaceSupportKHR(deviceHandles[i], j, surface, | |
&supportsPresent); | |
if (supportsPresent && | |
(queueFamilyProperties[j].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { | |
queueFamilyIndex = j; | |
physicalDevice = deviceHandles[i]; | |
break; | |
} | |
} | |
if (physicalDevice) { | |
break; | |
} | |
} | |
float priority = 1.0f; | |
VkDeviceQueueCreateInfo qci = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | |
.queueFamilyIndex = queueFamilyIndex, | |
.queueCount = 1, | |
.pQueuePriorities = &priority}; | |
deviceCreateInfo.pQueueCreateInfos = &qci; | |
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, NULL, &device); | |
vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); | |
return result == VK_SUCCESS; | |
} | |
void fini_device() { vkDestroyDevice(device, 0); } | |
//---------------------------------------------------------- | |
VkSwapchainKHR swapchain; | |
uint32_t swapchainImageCount; | |
VkImage swapchainImages[MAX_SWAPCHAIN_IMAGES]; | |
VkExtent2D swapchainExtent; | |
VkSurfaceFormatKHR surfaceFormat; | |
int init_swapchain(VkPresentModeKHR preferredPresentMode) { | |
// Use first available format | |
uint32_t formatCount = 1; | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, | |
0); // suppress validation layer | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, | |
&surfaceFormat); | |
surfaceFormat.format = surfaceFormat.format == VK_FORMAT_UNDEFINED | |
? VK_FORMAT_B8G8R8A8_UNORM | |
: surfaceFormat.format; | |
uint32_t presentModeCount = 0; | |
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, | |
&presentModeCount, NULL); | |
VkPresentModeKHR presentModes[MAX_PRESENT_MODE_COUNT]; | |
presentModeCount = presentModeCount > MAX_PRESENT_MODE_COUNT | |
? MAX_PRESENT_MODE_COUNT | |
: presentModeCount; | |
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, | |
&presentModeCount, presentModes); | |
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; // always supported. | |
for (uint32_t i = 0; i < presentModeCount; ++i) { | |
if (presentModes[i] == preferredPresentMode) { | |
presentMode = preferredPresentMode; | |
break; | |
} | |
} | |
if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) { | |
printf("Mailbox present mode selected.\n"); | |
} else if (presentMode == VK_PRESENT_MODE_FIFO_KHR) { | |
printf("FIFO present mode selected.\n"); | |
} else if (presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) { | |
printf("FIFO-Relaxed present mode selected.\n"); | |
} else if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { | |
printf("Immediate present mode selected.\n"); | |
} | |
swapchainImageCount = presentMode == VK_PRESENT_MODE_MAILBOX_KHR | |
? PRESENT_MODE_MAILBOX_IMAGE_COUNT | |
: PRESENT_MODE_DEFAULT_IMAGE_COUNT; | |
swapchainImageCount += 4; | |
VkSurfaceCapabilitiesKHR surfaceCapabilities; | |
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, | |
&surfaceCapabilities); | |
swapchainExtent = surfaceCapabilities.currentExtent; | |
if (swapchainExtent.width == UINT32_MAX) { | |
swapchainExtent.width = | |
clamp_u32(width, surfaceCapabilities.minImageExtent.width, | |
surfaceCapabilities.maxImageExtent.width); | |
swapchainExtent.height = | |
clamp_u32(height, surfaceCapabilities.minImageExtent.height, | |
surfaceCapabilities.maxImageExtent.height); | |
} | |
VkSwapchainCreateInfoKHR swapChainCreateInfo = { | |
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
.surface = surface, | |
.minImageCount = swapchainImageCount, | |
.imageFormat = surfaceFormat.format, | |
.imageColorSpace = surfaceFormat.colorSpace, | |
.imageExtent = swapchainExtent, | |
.imageArrayLayers = 1, // 2 for stereo | |
.imageUsage = | |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, | |
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, | |
.preTransform = surfaceCapabilities.currentTransform, | |
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, | |
.presentMode = presentMode, | |
.clipped = VK_TRUE, | |
}; | |
VkResult result = | |
vkCreateSwapchainKHR(device, &swapChainCreateInfo, 0, &swapchain); | |
if (result != VK_SUCCESS) { | |
return 0; | |
} | |
vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, NULL); | |
vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, | |
swapchainImages); | |
return 1; | |
} | |
void fini_swapchain() { vkDestroySwapchainKHR(device, swapchain, 0); } | |
//---------------------------------------------------------- | |
uint32_t frameIndex = 0; | |
VkCommandPool commandPool; | |
VkCommandBuffer commandBuffers[FRAME_COUNT]; | |
VkFence frameFences[FRAME_COUNT]; // Create with VK_FENCE_CREATE_SIGNALED_BIT. | |
VkSemaphore imageAvailableSemaphores[FRAME_COUNT]; | |
VkSemaphore renderFinishedSemaphores[FRAME_COUNT]; | |
int init_render() { | |
VkCommandPoolCreateInfo commandPoolCreateInfo = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, | |
.queueFamilyIndex = queueFamilyIndex, | |
}; | |
vkCreateCommandPool(device, &commandPoolCreateInfo, 0, &commandPool); | |
VkCommandBufferAllocateInfo commandBufferAllocInfo = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
.commandPool = commandPool, | |
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
.commandBufferCount = FRAME_COUNT, | |
}; | |
vkAllocateCommandBuffers(device, &commandBufferAllocInfo, commandBuffers); | |
VkSemaphoreCreateInfo semaphoreCreateInfo = { | |
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&imageAvailableSemaphores[0]); | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&imageAvailableSemaphores[1]); | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&imageAvailableSemaphores[2]); | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&renderFinishedSemaphores[0]); | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&renderFinishedSemaphores[1]); | |
vkCreateSemaphore(device, &semaphoreCreateInfo, 0, | |
&renderFinishedSemaphores[2]); | |
VkFenceCreateInfo fenceCreateInfo = {.sType = | |
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
.flags = VK_FENCE_CREATE_SIGNALED_BIT}; | |
vkCreateFence(device, &fenceCreateInfo, 0, &frameFences[0]); | |
vkCreateFence(device, &fenceCreateInfo, 0, &frameFences[1]); | |
vkCreateFence(device, &fenceCreateInfo, 0, &frameFences[2]); | |
return 1; | |
} | |
void fini_render() { | |
vkDeviceWaitIdle(device); | |
vkDestroyFence(device, frameFences[0], 0); | |
vkDestroyFence(device, frameFences[1], 0); | |
vkDestroyFence(device, frameFences[2], 0); | |
vkDestroySemaphore(device, renderFinishedSemaphores[0], 0); | |
vkDestroySemaphore(device, renderFinishedSemaphores[1], 0); | |
vkDestroySemaphore(device, renderFinishedSemaphores[2], 0); | |
vkDestroySemaphore(device, imageAvailableSemaphores[0], 0); | |
vkDestroySemaphore(device, imageAvailableSemaphores[1], 0); | |
vkDestroySemaphore(device, imageAvailableSemaphores[2], 0); | |
vkDestroyCommandPool(device, commandPool, 0); | |
} | |
void draw_frame() { | |
uint32_t index = (frameIndex++) % FRAME_COUNT; | |
vkWaitForFences(device, 1, &frameFences[index], VK_TRUE, UINT64_MAX); | |
vkResetFences(device, 1, &frameFences[index]); | |
uint32_t imageIndex; | |
vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, | |
imageAvailableSemaphores[index], VK_NULL_HANDLE, | |
&imageIndex); | |
VkCommandBufferBeginInfo beginInfo = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; | |
vkBeginCommandBuffer(commandBuffers[index], &beginInfo); | |
VkImageSubresourceRange subResourceRange = { | |
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | |
.baseMipLevel = 0, | |
.levelCount = VK_REMAINING_MIP_LEVELS, | |
.baseArrayLayer = 0, | |
.layerCount = VK_REMAINING_ARRAY_LAYERS, | |
}; | |
// Change layout of image to be optimal for clearing | |
VkImageMemoryBarrier barrier = { | |
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | |
.srcAccessMask = 0, | |
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | |
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, | |
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
.srcQueueFamilyIndex = queueFamilyIndex, | |
.dstQueueFamilyIndex = queueFamilyIndex, | |
.image = swapchainImages[imageIndex], | |
.subresourceRange = subResourceRange, | |
}; | |
vkCmdPipelineBarrier(commandBuffers[index], VK_PIPELINE_STAGE_TRANSFER_BIT, | |
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, | |
&barrier); | |
VkClearColorValue cc = {sinf(frameIndex * 0.3f) * 0.5f + 0.5f, 0, 0, 1.0f}; | |
vkCmdClearColorImage(commandBuffers[index], swapchainImages[imageIndex], | |
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cc, 1, | |
&subResourceRange); | |
// Change layout of image to be optimal for presenting | |
VkImageMemoryBarrier barrier2 = { | |
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | |
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | |
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, | |
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, | |
.srcQueueFamilyIndex = queueFamilyIndex, | |
.dstQueueFamilyIndex = queueFamilyIndex, | |
.image = swapchainImages[imageIndex], | |
.subresourceRange = subResourceRange, | |
}; | |
vkCmdPipelineBarrier(commandBuffers[index], VK_PIPELINE_STAGE_TRANSFER_BIT, | |
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, | |
NULL, 1, &barrier2); | |
vkEndCommandBuffer(commandBuffers[index]); | |
VkSubmitInfo submitInfo = { | |
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
.waitSemaphoreCount = 1, | |
.pWaitSemaphores = &imageAvailableSemaphores[index], | |
.pWaitDstStageMask = | |
(VkPipelineStageFlags[]){ | |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}, | |
.commandBufferCount = 1, | |
.pCommandBuffers = &commandBuffers[index], | |
.signalSemaphoreCount = 1, | |
.pSignalSemaphores = &renderFinishedSemaphores[index], | |
}; | |
vkQueueSubmit(queue, 1, &submitInfo, frameFences[index]); | |
VkPresentInfoKHR presentInfo = { | |
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, | |
.waitSemaphoreCount = 1, | |
.pWaitSemaphores = &renderFinishedSemaphores[index], | |
.swapchainCount = 1, | |
.pSwapchains = &swapchain, | |
.pImageIndices = &imageIndex, | |
}; | |
vkQueuePresentKHR(queue, &presentInfo); | |
} | |
//---------------------------------------------------------- | |
int main(int argc, char *argv[]) { | |
printf("Supported command line argsuments:\n" | |
" wl = force to attempt Wayland in window creation in SDL.\n" | |
" x11 = force to attempt X11 in window creation in SDL.\n" | |
" mailbox = attempt to use MAILBOX mode for the swapchain.\n" | |
" fifo = attempt to use FIFO mode for the swapchain.\n" | |
" fiforelaxed = attempt to use FIFO_RELAXED mode for the swapchain.\n" | |
" immediate = attempt to use IMMEDIATE mode for the swapchain.\n" | |
"\n" | |
); | |
VkPresentModeKHR preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; | |
for (int i = 1; i < argc; ++i) { | |
if (strcmp(argv[i], "wl") == 0) { | |
SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland"); | |
} | |
if (strcmp(argv[i], "x11") == 0) { | |
SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11"); | |
} | |
if (strcmp(argv[i], "mailbox") == 0) { | |
preferredPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; | |
} | |
if (strcmp(argv[i], "fifo") == 0) { | |
preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; | |
} | |
if (strcmp(argv[i], "immediate") == 0) { | |
preferredPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; | |
} | |
if (strcmp(argv[i], "fiforelaxed") == 0) { | |
preferredPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; | |
} | |
} | |
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); | |
int run = init_vulkan() && init_window() && init_device() && | |
init_swapchain(preferredPresentMode) && init_render(); | |
Uint64 last_time = SDL_GetPerformanceCounter(); | |
int frame_counter = 0; | |
while (run) { | |
SDL_Event evt; | |
while (SDL_PollEvent(&evt)) { | |
if (evt.type == SDL_QUIT) { | |
run = 0; | |
} | |
} | |
draw_frame(); | |
frame_counter++; | |
if (frame_counter % 10 == 0) { | |
Uint64 now = SDL_GetPerformanceCounter(); | |
double time = (double)(now - last_time) / SDL_GetPerformanceFrequency(); | |
printf("Frames %05d -> %05d mean frame time: %.4f ms FPS=%6.1f\n", | |
frame_counter - 9, frame_counter, | |
100.0 * time, 10.0 / time); | |
last_time = now; | |
} | |
} | |
fini_render(); | |
fini_swapchain(); | |
fini_device(); | |
fini_window(); | |
fini_vulkan(); | |
SDL_Quit(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment