feat: create vulkan swapchain
This commit is contained in:
		
							parent
							
								
									904a26374b
								
							
						
					
					
						commit
						6937e55888
					
				@ -78,8 +78,10 @@ if vk_dep.found()
 | 
			
		||||
  vk_renderer_lib = library('vyvk',
 | 
			
		||||
    # Project Sources
 | 
			
		||||
    'src/renderer/vk/gpu.h',
 | 
			
		||||
    'src/renderer/vk/swapchain.h',
 | 
			
		||||
 | 
			
		||||
    'src/renderer/vk/init.c',
 | 
			
		||||
    'src/renderer/vk/swapchain.c',
 | 
			
		||||
    'src/renderer/vk/gfx_pipelines.c',
 | 
			
		||||
 | 
			
		||||
    # Contrib Sources
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								pch/vk_pch.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								pch/vk_pch.h
									
									
									
									
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(VY_USE_XLIB)
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
@ -3,6 +3,25 @@
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
struct HINSTANCE__;
 | 
			
		||||
struct HWND__;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
struct _XDisplay;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    struct HINSTANCE__ *hInstance;
 | 
			
		||||
    struct HWND__ *hWnd;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
    struct _XDisplay *display;
 | 
			
		||||
    unsigned long window;
 | 
			
		||||
#endif
 | 
			
		||||
} vy_native_window;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkInstance instance;
 | 
			
		||||
    VkDebugUtilsMessengerEXT messenger;
 | 
			
		||||
@ -13,6 +32,11 @@ typedef struct {
 | 
			
		||||
    VkQueue graphics_queue;
 | 
			
		||||
    VkQueue compute_queue;
 | 
			
		||||
    VkQueue present_queue;
 | 
			
		||||
    uint32_t graphics_family;
 | 
			
		||||
    uint32_t compute_family;
 | 
			
		||||
    uint32_t present_family;
 | 
			
		||||
 | 
			
		||||
    vy_native_window native_window;
 | 
			
		||||
 | 
			
		||||
    VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props;
 | 
			
		||||
    VkPhysicalDeviceProperties phys_device_props;
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
#define VY_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
@ -81,9 +82,14 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
 | 
			
		||||
    return VK_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern vy_cvar r_VkPreferredSwapchainImages;
 | 
			
		||||
extern vy_cvar r_VkPreferMailboxMode;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterCVars(void) {
 | 
			
		||||
    vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPhysDeviceName);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPreferredSwapchainImages);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPreferMailboxMode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CreateInstance(void) {
 | 
			
		||||
@ -178,6 +184,8 @@ static int CreateInstance(void) {
 | 
			
		||||
 | 
			
		||||
static int CreateSurface(const vy_renderer_init_info *info) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    g_gpu.native_window.hInstance            = info->hInstance;
 | 
			
		||||
    g_gpu.native_window.hWnd                 = info->hWnd;
 | 
			
		||||
    VkWin32SurfaceCreateInfoKHR surface_info = {
 | 
			
		||||
        .sType     = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
 | 
			
		||||
        .hinstance = info->hInstance,
 | 
			
		||||
@ -191,6 +199,8 @@ static int CreateSurface(const vy_renderer_init_info *info) {
 | 
			
		||||
    else
 | 
			
		||||
        return -100;
 | 
			
		||||
#elif defined(VY_USE_XLIB_KHR)
 | 
			
		||||
    g_gpu.native_window.display             = info->display;
 | 
			
		||||
    g_gpu.native_window.window              = info->window;
 | 
			
		||||
    VkXlibSurfaceCreateInfoKHR surface_info = {
 | 
			
		||||
        .sType     = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
			
		||||
        .dpy       = info->display,
 | 
			
		||||
@ -395,6 +405,10 @@ static int CreateDevice(void) {
 | 
			
		||||
    vy_queue_indices queue_indices =
 | 
			
		||||
        RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
 | 
			
		||||
 | 
			
		||||
    g_gpu.compute_family  = queue_indices.compute;
 | 
			
		||||
    g_gpu.graphics_family = queue_indices.graphics;
 | 
			
		||||
    g_gpu.present_family  = queue_indices.present;
 | 
			
		||||
 | 
			
		||||
    float priority = 1.f;
 | 
			
		||||
 | 
			
		||||
    uint32_t distinct_queue_count = 1;
 | 
			
		||||
@ -482,6 +496,9 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
 | 
			
		||||
    if (res != 0)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = CreateDevice();
 | 
			
		||||
    if (res != 0)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = vyCreateSwapchain();
 | 
			
		||||
    if (res != 0)
 | 
			
		||||
        return res;
 | 
			
		||||
 | 
			
		||||
@ -490,7 +507,8 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdown(void) {
 | 
			
		||||
    vyLog("vk", "Shutdown");
 | 
			
		||||
    
 | 
			
		||||
    vkDeviceWaitIdle(g_gpu.device);
 | 
			
		||||
    vyDestroySwapchain();
 | 
			
		||||
    vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb);
 | 
			
		||||
    vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb);
 | 
			
		||||
    vkDestroyInstance(g_gpu.instance, g_gpu.alloc_cb);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										198
									
								
								src/renderer/vk/swapchain.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/renderer/vk/swapchain.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,198 @@
 | 
			
		||||
#define VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
			
		||||
          "Preferred number of swapchain iamges. [2/3] Default: 2",
 | 
			
		||||
          2);
 | 
			
		||||
VY_CVAR_I(r_VkPreferMailboxMode,
 | 
			
		||||
          "Prefer mailbox present mode over fifo mode. [0/1] Default: 0",
 | 
			
		||||
          1);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkPresentModeKHR present_mode;
 | 
			
		||||
    VkSurfaceFormatKHR surface_format;
 | 
			
		||||
    VkExtent2D extent;
 | 
			
		||||
    VkSurfaceTransformFlagsKHR pre_transform;
 | 
			
		||||
} vy_device_swapchain_parameters;
 | 
			
		||||
 | 
			
		||||
static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
			
		||||
    vy_device_swapchain_parameters params;
 | 
			
		||||
 | 
			
		||||
    /* determine presentation mode. FIFO should always be available */
 | 
			
		||||
    params.present_mode = VK_PRESENT_MODE_FIFO_KHR;
 | 
			
		||||
    if (r_VkPreferMailboxMode.i) {
 | 
			
		||||
        VkPresentModeKHR modes[6];
 | 
			
		||||
        uint32_t count = 6;
 | 
			
		||||
        vkGetPhysicalDeviceSurfacePresentModesKHR(g_gpu.phys_device,
 | 
			
		||||
                                                  g_gpu.surface,
 | 
			
		||||
                                                  &count,
 | 
			
		||||
                                                  modes);
 | 
			
		||||
        for (uint32_t i = 0; i < count; ++i) {
 | 
			
		||||
            if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
 | 
			
		||||
                params.present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Determine surface format */
 | 
			
		||||
    VkSurfaceFormatKHR formats[64];
 | 
			
		||||
    uint32_t format_count = 64;
 | 
			
		||||
    vkGetPhysicalDeviceSurfaceFormatsKHR(g_gpu.phys_device,
 | 
			
		||||
                                         g_gpu.surface,
 | 
			
		||||
                                         &format_count,
 | 
			
		||||
                                         formats);
 | 
			
		||||
    params.surface_format = formats[0];
 | 
			
		||||
    for (uint32_t i = 0; i < format_count; ++i) {
 | 
			
		||||
        if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
 | 
			
		||||
                formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
 | 
			
		||||
            params.surface_format = formats[i];
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* get extent */
 | 
			
		||||
    VkSurfaceCapabilitiesKHR capabilities;
 | 
			
		||||
    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_gpu.phys_device,
 | 
			
		||||
                                              g_gpu.surface,
 | 
			
		||||
                                              &capabilities);
 | 
			
		||||
    if (capabilities.currentExtent.width != UINT32_MAX) {
 | 
			
		||||
        params.extent = capabilities.currentExtent;
 | 
			
		||||
    } else {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        RECT client_area;
 | 
			
		||||
        GetClientRect(g_gpu.native_window.hWnd, &client_area);
 | 
			
		||||
        params.extent.width = (uint32_t)client_area.right;
 | 
			
		||||
        params.extent.height = (uint32_t)client_area.bottom;
 | 
			
		||||
#else
 | 
			
		||||
        XWindowAttributes attribs;
 | 
			
		||||
        XGetWindowAttributes(g_gpu.native_window.display,
 | 
			
		||||
                             g_gpu.native_window.window,
 | 
			
		||||
                             &attribs);
 | 
			
		||||
        params.extent.width = (uint32_t)attribs.width;
 | 
			
		||||
        params.extent.height = (uint32_t)attribs.height;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    params.pre_transform = capabilities.currentTransform;
 | 
			
		||||
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_swapchain g_swapchain;
 | 
			
		||||
 | 
			
		||||
int vyCreateSwapchain(void) {
 | 
			
		||||
    vy_device_swapchain_parameters device_params =
 | 
			
		||||
        DetermineSwapchainParameters();
 | 
			
		||||
 | 
			
		||||
    uint32_t image_count = r_VkPreferredSwapchainImages.i;
 | 
			
		||||
    if (image_count < 2)
 | 
			
		||||
        image_count = 2;
 | 
			
		||||
    else if (image_count > 3)
 | 
			
		||||
        image_count = 3;
 | 
			
		||||
 | 
			
		||||
    VkSwapchainCreateInfoKHR swapchain_info = {
 | 
			
		||||
        .sType            = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
 | 
			
		||||
        .surface          = g_gpu.surface,
 | 
			
		||||
        .presentMode      = device_params.present_mode,
 | 
			
		||||
        .imageFormat      = device_params.surface_format.format,
 | 
			
		||||
        .imageColorSpace  = device_params.surface_format.colorSpace,
 | 
			
		||||
        .imageExtent      = device_params.extent,
 | 
			
		||||
        .preTransform     = device_params.pre_transform,
 | 
			
		||||
        .compositeAlpha   = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
 | 
			
		||||
        .clipped          = VK_TRUE,
 | 
			
		||||
        .minImageCount    = image_count,
 | 
			
		||||
        .imageUsage       = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
 | 
			
		||||
        .imageArrayLayers = 1,
 | 
			
		||||
        .oldSwapchain     = VK_NULL_HANDLE,
 | 
			
		||||
    };
 | 
			
		||||
    uint32_t queue_families[] = {g_gpu.graphics_family, g_gpu.present_family};
 | 
			
		||||
    if (g_gpu.present_family != g_gpu.graphics_family) {
 | 
			
		||||
        swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
 | 
			
		||||
        swapchain_info.pQueueFamilyIndices = queue_families;
 | 
			
		||||
        swapchain_info.queueFamilyIndexCount = 2;
 | 
			
		||||
    } else {
 | 
			
		||||
        swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 | 
			
		||||
        swapchain_info.pQueueFamilyIndices   = NULL;
 | 
			
		||||
        swapchain_info.queueFamilyIndexCount = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (vkCreateSwapchainKHR(g_gpu.device,
 | 
			
		||||
                             &swapchain_info,
 | 
			
		||||
                             g_gpu.alloc_cb,
 | 
			
		||||
                             &g_swapchain.swapchain) != VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Failed to create the swapchain");
 | 
			
		||||
        return -50;
 | 
			
		||||
    }
 | 
			
		||||
    g_swapchain.format = device_params.surface_format.format;
 | 
			
		||||
 | 
			
		||||
    /* Retrieve images */
 | 
			
		||||
    g_swapchain.image_count = 0;
 | 
			
		||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
			
		||||
                            g_swapchain.swapchain,
 | 
			
		||||
                            &g_swapchain.image_count,
 | 
			
		||||
                            NULL);
 | 
			
		||||
    if (g_swapchain.image_count > VY_VK_MAX_SWAPCHAIN_IMAGES) {
 | 
			
		||||
        vyReportError("vk",
 | 
			
		||||
                      "Unsupported number of swapchain images: %u",
 | 
			
		||||
                      g_swapchain.image_count);
 | 
			
		||||
        return -51;
 | 
			
		||||
    }
 | 
			
		||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
			
		||||
                            g_swapchain.swapchain,
 | 
			
		||||
                            &g_swapchain.image_count,
 | 
			
		||||
                            g_swapchain.images);
 | 
			
		||||
 | 
			
		||||
    /* Create image views */
 | 
			
		||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
			
		||||
        VkImageViewCreateInfo view_info = {
 | 
			
		||||
            .sType  = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
			
		||||
            .image  = g_swapchain.images[i],
 | 
			
		||||
            .format = g_swapchain.format,
 | 
			
		||||
            .viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
			
		||||
            .components = {
 | 
			
		||||
                .r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
                .g = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
                .b = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
                .a = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
            },
 | 
			
		||||
            .subresourceRange = {
 | 
			
		||||
                .aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT,
 | 
			
		||||
                .baseArrayLayer = 0,
 | 
			
		||||
                .layerCount     = 1,
 | 
			
		||||
                .baseMipLevel   = 0,
 | 
			
		||||
                .levelCount     = 1,
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
        if (vkCreateImageView(g_gpu.device,
 | 
			
		||||
                          &view_info,
 | 
			
		||||
                          g_gpu.alloc_cb,
 | 
			
		||||
                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
			
		||||
            vyReportError("vk",
 | 
			
		||||
                          "Failed to create an image view for the swapchain.");
 | 
			
		||||
            return -52;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void vyDestroySwapchain(void) {
 | 
			
		||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
			
		||||
        vkDestroyImageView(g_gpu.device,
 | 
			
		||||
                           g_swapchain.image_views[i],
 | 
			
		||||
                           g_gpu.alloc_cb);
 | 
			
		||||
    }
 | 
			
		||||
    vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/renderer/vk/swapchain.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/renderer/vk/swapchain.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#ifndef VY_VK_SWAPCHAIN_H
 | 
			
		||||
#define VY_VK_SWAPCHAIN_H
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkSwapchainKHR swapchain;
 | 
			
		||||
    VkImage images[VY_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    VkImageView image_views[VY_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    uint32_t image_count;
 | 
			
		||||
    VkFormat format;
 | 
			
		||||
} vy_swapchain;
 | 
			
		||||
 | 
			
		||||
#ifndef VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
extern vy_swapchain g_swapchain;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int vyCreateSwapchain(void);
 | 
			
		||||
 | 
			
		||||
void vyDestroySwapchain(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user