Compare commits
2 commits
main
...
vk_refacto
Author | SHA1 | Date | |
---|---|---|---|
9a28978380 | |||
578fde4a09 |
15 changed files with 834 additions and 652 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include <ptk_option.h>
|
#include <ptk_option.h>
|
||||||
|
|
||||||
#include <ptk_vk/components.h>
|
#include <ptk_vk/components.h>
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
#include <ptk_vk/draw.h>
|
#include <ptk_vk/draw.h>
|
||||||
#include <ptk_vk/init.h>
|
#include <ptk_vk/init.h>
|
||||||
#include <ptk_vk/utils.h>
|
#include <ptk_vk/utils.h>
|
||||||
|
@ -196,7 +197,7 @@ int ptk_run(PtkHandle root) {
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(m_window)) {
|
while (!glfwWindowShouldClose(m_window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
if (!vk_draw_frame()) {
|
if (!vk_draw_frame(m_window, g_surface)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
137
src/ptk_vk/device.c
Normal file
137
src/ptk_vk/device.c
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
|
|
||||||
|
#include <ptk_vk/init.h>
|
||||||
|
#include <ptk_vk/swapchain.h>
|
||||||
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ptk_array.h>
|
||||||
|
#include <ptk_list.h>
|
||||||
|
#include <ptk_log.h>
|
||||||
|
#include <ptk_option.h>
|
||||||
|
|
||||||
|
VkDevice g_dev = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
QueueFamilyIndices g_queue_family_indices = {0};
|
||||||
|
const size_t g_queue_family_count = sizeof(QueueFamilyIndices) / sizeof(PTK_OPTION(uint32_t));
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkQueueFamilyProperties);
|
||||||
|
|
||||||
|
static const PTK_ARRAY(constcharptr) m_device_extensions = PTK_ARRAY_NEW(constcharptr, {
|
||||||
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
|
});
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkExtensionProperties);
|
||||||
|
|
||||||
|
bool are_extensions_supported(const VkPhysicalDevice physical_dev) {
|
||||||
|
PTK_LIST(VkExtensionProperties) available_extensions;
|
||||||
|
vkEnumerateDeviceExtensionProperties(physical_dev, NULL, &available_extensions.allocated, NULL);
|
||||||
|
|
||||||
|
available_extensions = PTK_LIST_NEW(VkExtensionProperties, available_extensions.allocated);
|
||||||
|
vkEnumerateDeviceExtensionProperties(physical_dev, NULL, &available_extensions.allocated, available_extensions.data);
|
||||||
|
PTK_LIST_FILLED(available_extensions);
|
||||||
|
|
||||||
|
size_t supported_extensions = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_device_extensions.size; ++i) {
|
||||||
|
PTK_LIST_FOR_EACH(const VkExtensionProperties, available_extensions, current_extension, {
|
||||||
|
if (strcmp(m_device_extensions.data[i], current_extension.extensionName) == 0) {
|
||||||
|
supported_extensions += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported_extensions == m_device_extensions.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_device_suitable(const VkPhysicalDevice physical_dev, const VkSurfaceKHR surface) {
|
||||||
|
PTK_LIST(VkQueueFamilyProperties) queue_families;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_dev, &queue_families.allocated, NULL);
|
||||||
|
|
||||||
|
queue_families = PTK_LIST_NEW(VkQueueFamilyProperties, queue_families.allocated);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_dev, &queue_families.allocated, queue_families.data);
|
||||||
|
PTK_LIST_FILLED(queue_families);
|
||||||
|
|
||||||
|
g_queue_family_indices.graphics = PTK_OPTION_NONE(uint32_t);
|
||||||
|
g_queue_family_indices.present = PTK_OPTION_NONE(uint32_t);
|
||||||
|
PTK_LIST_FOR_EACH_E(const VkQueueFamilyProperties, queue_families, i, queue_family, {
|
||||||
|
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
|
g_queue_family_indices.graphics = PTK_OPTION_SOME(uint32_t, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 present_support = VK_FALSE;
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_dev, i, surface, &present_support);
|
||||||
|
if (present_support) {
|
||||||
|
g_queue_family_indices.present = PTK_OPTION_SOME(uint32_t, i);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const bool indices_found = g_queue_family_indices.graphics.exists
|
||||||
|
&& g_queue_family_indices.present.exists;
|
||||||
|
const bool extensions_supported = are_extensions_supported(physical_dev);
|
||||||
|
bool swapchain_adequate = false;
|
||||||
|
|
||||||
|
if (extensions_supported) {
|
||||||
|
const SwapchainSupportInfo swapchain_support = query_swapchain_support(physical_dev, surface);
|
||||||
|
swapchain_adequate = swapchain_support.formats.size != 0
|
||||||
|
&& swapchain_support.present_modes.size != 0;
|
||||||
|
PTK_LIST_FREE(swapchain_support.formats);
|
||||||
|
PTK_LIST_FREE(swapchain_support.present_modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
PTK_LIST_FREE(queue_families);
|
||||||
|
|
||||||
|
return indices_found && extensions_supported && swapchain_adequate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vk_create_logical_dev(VkPhysicalDevice physical_dev, VkSurfaceKHR surface, const PTK_ARRAY(constcharptr) validation_layers) {
|
||||||
|
if (!is_device_suitable(physical_dev, surface)) {
|
||||||
|
PTK_ERR("physical device isn't suitable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceQueueCreateInfo queue_create_infos[g_queue_family_count];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < g_queue_family_count; ++i) {
|
||||||
|
const PTK_OPTION(uint32_t) index = *(((PTK_OPTION(uint32_t) *)&g_queue_family_indices) + i);
|
||||||
|
|
||||||
|
queue_create_infos[i] = (VkDeviceQueueCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.queueFamilyIndex = index.value,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &(float){1.0f},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateDevice(
|
||||||
|
physical_dev,
|
||||||
|
&(VkDeviceCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.queueCreateInfoCount = g_queue_family_count,
|
||||||
|
.pQueueCreateInfos = queue_create_infos,
|
||||||
|
.enabledLayerCount = validation_layers.size,
|
||||||
|
.ppEnabledLayerNames = validation_layers.data,
|
||||||
|
.enabledExtensionCount = m_device_extensions.size,
|
||||||
|
.ppEnabledExtensionNames = m_device_extensions.data,
|
||||||
|
.pEnabledFeatures = &(VkPhysicalDeviceFeatures){0},
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&g_dev
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vkGetDeviceQueue(g_dev, g_queue_family_indices.graphics.value, 0, &g_graphics_queue);
|
||||||
|
vkGetDeviceQueue(g_dev, g_queue_family_indices.present.value, 0, &g_present_queue);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
30
src/ptk_vk/device.h
Normal file
30
src/ptk_vk/device.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#ifndef PTK_PTK_VK_DEVICE_H_
|
||||||
|
#define PTK_PTK_VK_DEVICE_H_
|
||||||
|
|
||||||
|
#include <ptk_array.h>
|
||||||
|
#include <ptk_option.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
extern VkDevice g_dev;
|
||||||
|
|
||||||
|
PTK_OPTION_DEFINE(VkDevice);
|
||||||
|
|
||||||
|
// for PTK_ARRAY(constcharptr)
|
||||||
|
#include <ptk_vk/instance.h>
|
||||||
|
|
||||||
|
PTK_OPTION_DEFINE(uint32_t);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PTK_OPTION(uint32_t) graphics;
|
||||||
|
PTK_OPTION(uint32_t) present;
|
||||||
|
} QueueFamilyIndices;
|
||||||
|
|
||||||
|
extern QueueFamilyIndices g_queue_family_indices;
|
||||||
|
extern const size_t g_queue_family_count;
|
||||||
|
|
||||||
|
bool vk_create_logical_dev(VkPhysicalDevice physical_dev, VkSurfaceKHR surface, const PTK_ARRAY(constcharptr) validation_layers);
|
||||||
|
|
||||||
|
#endif // PTK_PTK_VK_DEVICE_H_
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
#include <ptk_vk/draw.h>
|
#include <ptk_vk/draw.h>
|
||||||
|
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
#include <ptk_vk/init.h>
|
#include <ptk_vk/init.h>
|
||||||
|
#include <ptk_vk/swapchain.h>
|
||||||
#include <ptk_vk/utils.h>
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
#include <ptk_log.h>
|
#include <ptk_log.h>
|
||||||
|
@ -12,7 +14,7 @@
|
||||||
bool g_framebuffer_resized = false;
|
bool g_framebuffer_resized = false;
|
||||||
uint32_t g_current_frame = 0;
|
uint32_t g_current_frame = 0;
|
||||||
|
|
||||||
bool vk_draw_frame(void) {
|
bool vk_draw_frame(GLFWwindow *window, VkSurfaceKHR surface) {
|
||||||
vkWaitForFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame], VK_TRUE, UINT64_MAX);
|
vkWaitForFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame], VK_TRUE, UINT64_MAX);
|
||||||
|
|
||||||
uint32_t image_index;
|
uint32_t image_index;
|
||||||
|
@ -26,7 +28,7 @@ bool vk_draw_frame(void) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (acquire_next_image_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (acquire_next_image_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
if (!vk_recreate_swapchain()) {
|
if (!vk_recreate_swapchain(window, surface)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -83,7 +85,7 @@ bool vk_draw_frame(void) {
|
||||||
g_framebuffer_resized
|
g_framebuffer_resized
|
||||||
) {
|
) {
|
||||||
g_framebuffer_resized = false;
|
g_framebuffer_resized = false;
|
||||||
if (!vk_recreate_swapchain()) {
|
if (!vk_recreate_swapchain(window, surface)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PTK_TRACE("recreated swapchain");
|
PTK_TRACE("recreated swapchain");
|
||||||
|
|
|
@ -6,9 +6,14 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifndef GLFW_INCLUDE_VULKAN
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#endif
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
extern bool g_framebuffer_resized;
|
extern bool g_framebuffer_resized;
|
||||||
extern uint32_t g_current_frame;
|
extern uint32_t g_current_frame;
|
||||||
|
|
||||||
bool vk_draw_frame(void);
|
bool vk_draw_frame(GLFWwindow *window, VkSurfaceKHR surface);
|
||||||
|
|
||||||
#endif // PTK_PTK_VK_DRAW_H_
|
#endif // PTK_PTK_VK_DRAW_H_
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
#include <ptk_vk/init.h>
|
#include <ptk_vk/init.h>
|
||||||
|
|
||||||
#include <ptk_vk/components.h>
|
#include <ptk_vk/components.h>
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
#include <ptk_vk/draw.h>
|
#include <ptk_vk/draw.h>
|
||||||
|
#include <ptk_vk/instance.h>
|
||||||
|
#include <ptk_vk/physical_device.h>
|
||||||
|
#include <ptk_vk/render_pass.h>
|
||||||
|
#include <ptk_vk/swapchain.h>
|
||||||
#include <ptk_vk/utils.h>
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
#include <ptk_log.h>
|
#include <ptk_log.h>
|
||||||
|
@ -15,71 +20,25 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
PTK_LIST_DEFINE(VkImage);
|
|
||||||
PTK_LIST_DEFINE(VkImageView);
|
|
||||||
PTK_OPTION_DEFINE(uint32_t);
|
|
||||||
PTK_LIST_DEFINE(VkSurfaceFormatKHR);
|
|
||||||
PTK_LIST_DEFINE(VkPresentModeKHR);
|
|
||||||
PTK_LIST_DEFINE(VkFramebuffer);
|
|
||||||
PTK_ARRAY_DEFINE(VkVertexInputAttributeDescription);
|
PTK_ARRAY_DEFINE(VkVertexInputAttributeDescription);
|
||||||
PTK_LIST_DEFINE(VkExtensionProperties);
|
|
||||||
PTK_LIST_DEFINE(VkQueueFamilyProperties);
|
|
||||||
PTK_OPTION_DEFINE(VkShaderModule);
|
PTK_OPTION_DEFINE(VkShaderModule);
|
||||||
PTK_LIST_DEFINE(VkBuffer);
|
PTK_LIST_DEFINE(VkBuffer);
|
||||||
PTK_LIST_DEFINE(VkDeviceMemory);
|
PTK_LIST_DEFINE(VkDeviceMemory);
|
||||||
typedef void *voidptr;
|
typedef void *voidptr;
|
||||||
PTK_LIST_DEFINE(voidptr);
|
PTK_LIST_DEFINE(voidptr);
|
||||||
PTK_LIST_DEFINE(VkDescriptorSet);
|
PTK_LIST_DEFINE(VkDescriptorSet);
|
||||||
typedef const char *constcharptr;
|
|
||||||
PTK_ARRAY_DEFINE(constcharptr);
|
|
||||||
PTK_LIST_DEFINE(constcharptr);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
PTK_LIST_DEFINE(VkLayerProperties);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
|
||||||
PTK_LIST(VkSurfaceFormatKHR) formats;
|
|
||||||
PTK_LIST(VkPresentModeKHR) present_modes;
|
|
||||||
} SwapchainSupportInfo;
|
|
||||||
|
|
||||||
static GLFWwindow *m_window = NULL;
|
static GLFWwindow *m_window = NULL;
|
||||||
|
|
||||||
static VkInstance m_instance = VK_NULL_HANDLE;
|
VkSurfaceKHR g_surface = VK_NULL_HANDLE;
|
||||||
static VkPhysicalDevice m_physical_dev = VK_NULL_HANDLE;
|
|
||||||
VkDevice g_dev = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
static VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkSwapchainKHR g_swapchain = VK_NULL_HANDLE;
|
|
||||||
static VkFormat m_swapchain_image_format;
|
|
||||||
static VkExtent2D m_swapchain_extent;
|
|
||||||
|
|
||||||
static PTK_LIST(VkImage) m_swapchain_images;
|
|
||||||
|
|
||||||
static PTK_LIST(VkImageView) m_swapchain_image_views;
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
PTK_OPTION(uint32_t) graphics;
|
|
||||||
PTK_OPTION(uint32_t) present;
|
|
||||||
} m_queue_family_indices = {0};
|
|
||||||
static const size_t m_queue_family_count = sizeof(m_queue_family_indices) / sizeof(PTK_OPTION(uint32_t));
|
|
||||||
|
|
||||||
VkQueue g_graphics_queue = VK_NULL_HANDLE;
|
VkQueue g_graphics_queue = VK_NULL_HANDLE;
|
||||||
VkQueue g_present_queue = VK_NULL_HANDLE;
|
VkQueue g_present_queue = VK_NULL_HANDLE;
|
||||||
|
|
||||||
static const PTK_ARRAY(constcharptr) m_device_extensions = PTK_ARRAY_NEW(constcharptr, {
|
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
|
||||||
});
|
|
||||||
|
|
||||||
static VkRenderPass m_render_pass;
|
|
||||||
static VkDescriptorSetLayout m_descriptor_set_layout;
|
static VkDescriptorSetLayout m_descriptor_set_layout;
|
||||||
static VkPipelineLayout m_pipeline_layout;
|
static VkPipelineLayout m_pipeline_layout;
|
||||||
static VkPipeline m_pipeline;
|
static VkPipeline m_pipeline;
|
||||||
|
|
||||||
static PTK_LIST(VkFramebuffer) m_swapchain_framebuffers;
|
|
||||||
|
|
||||||
const size_t g_max_frames_in_flight = 2;
|
const size_t g_max_frames_in_flight = 2;
|
||||||
|
|
||||||
static VkCommandPool m_command_pool;
|
static VkCommandPool m_command_pool;
|
||||||
|
@ -145,450 +104,10 @@ static PTK_LIST(VkDescriptorSet) m_descriptor_sets;
|
||||||
static const PTK_ARRAY(constcharptr) m_validation_layers = PTK_ARRAY_NEW(constcharptr, {
|
static const PTK_ARRAY(constcharptr) m_validation_layers = PTK_ARRAY_NEW(constcharptr, {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
});
|
});
|
||||||
|
|
||||||
bool check_validation_layers(const PTK_ARRAY(constcharptr) validation_layers) {
|
|
||||||
PTK_LIST(VkLayerProperties) available_layers;
|
|
||||||
|
|
||||||
vkEnumerateInstanceLayerProperties(&available_layers.allocated, NULL);
|
|
||||||
|
|
||||||
available_layers = PTK_LIST_NEW(VkLayerProperties, available_layers.allocated);
|
|
||||||
vkEnumerateInstanceLayerProperties(&available_layers.allocated, available_layers.data);
|
|
||||||
PTK_LIST_FILLED(available_layers);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < validation_layers.size; ++i) {
|
|
||||||
const char *layer_name = validation_layers.data[i];
|
|
||||||
|
|
||||||
bool layer_found = false;
|
|
||||||
|
|
||||||
PTK_LIST_FOR_EACH(const VkLayerProperties, available_layers, layer_properties, {
|
|
||||||
if (strcmp(layer_name, layer_properties.layerName) == 0) {
|
|
||||||
layer_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!layer_found) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static const PTK_ARRAY(constcharptr) m_validation_layers = PTK_ARRAY_EMPTY(constcharptr);
|
static const PTK_ARRAY(constcharptr) m_validation_layers = PTK_ARRAY_EMPTY(constcharptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool create_vk_instance(const char *title, const PtkVersion version) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (!check_validation_layers(m_validation_layers)) {
|
|
||||||
PTK_ERR("couldn't find requested validation layer");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PTK_ARRAY(constcharptr) extension_names = PTK_ARRAY_EMPTY(constcharptr);
|
|
||||||
extension_names.data = glfwGetRequiredInstanceExtensions(&extension_names.size);
|
|
||||||
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateInstance(
|
|
||||||
&(VkInstanceCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.pApplicationInfo = &(VkApplicationInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.pApplicationName = title,
|
|
||||||
.applicationVersion = VK_MAKE_API_VERSION(0, version.major, version.minor, version.patch),
|
|
||||||
.pEngineName = PTK_ENGINE_NAME,
|
|
||||||
.engineVersion = VK_MAKE_API_VERSION(0, PTK_VERSION_MAJOR, PTK_VERSION_MINOR, PTK_VERSION_PATCH),
|
|
||||||
.apiVersion = VK_API_VERSION_1_3,
|
|
||||||
},
|
|
||||||
.enabledLayerCount = m_validation_layers.size,
|
|
||||||
.ppEnabledLayerNames = m_validation_layers.data,
|
|
||||||
.enabledExtensionCount = extension_names.size,
|
|
||||||
.ppEnabledExtensionNames = extension_names.data,
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&m_instance
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool select_physical_dev(void) {
|
|
||||||
uint32_t dev_count = 0;
|
|
||||||
vkEnumeratePhysicalDevices(m_instance, &dev_count, NULL);
|
|
||||||
if (dev_count == 0) {
|
|
||||||
PTK_ERR("failed to find GPU with vulkan support");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
VkPhysicalDevice devs[dev_count];
|
|
||||||
vkEnumeratePhysicalDevices(m_instance, &dev_count, devs);
|
|
||||||
|
|
||||||
VkPhysicalDeviceProperties dev_props[dev_count];
|
|
||||||
uint32_t dgpus[dev_count];
|
|
||||||
uint32_t dgpu_count = 0;
|
|
||||||
uint32_t igpus[dev_count];
|
|
||||||
uint32_t igpu_count = 0;
|
|
||||||
|
|
||||||
VkPhysicalDeviceMemoryProperties dev_mem_props[dev_count];
|
|
||||||
uint32_t dev_mem_counts[dev_count];
|
|
||||||
VkDeviceSize dev_mem_totals[dev_count];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < dev_count; ++i) {
|
|
||||||
vkGetPhysicalDeviceProperties(devs[i], &dev_props[i]);
|
|
||||||
|
|
||||||
if (dev_props[i].deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
|
||||||
dgpus[dgpu_count] = i;
|
|
||||||
dgpu_count += 1;
|
|
||||||
} else if (dev_props[i].deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
|
||||||
igpus[igpu_count] = i;
|
|
||||||
igpu_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(devs[i], &dev_mem_props[i]);
|
|
||||||
|
|
||||||
dev_mem_counts[i] = dev_mem_props[i].memoryHeapCount;
|
|
||||||
dev_mem_totals[i] = 0;
|
|
||||||
|
|
||||||
for (size_t j = 0; j < dev_mem_counts[i]; ++j) {
|
|
||||||
dev_mem_totals[i] += dev_mem_props[i].memoryHeaps[j].size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize max_mem_size = 0;
|
|
||||||
size_t dev_best_index = 0;
|
|
||||||
|
|
||||||
if (dgpu_count != 0) {
|
|
||||||
for (size_t i = 0; i < dgpu_count; ++i) {
|
|
||||||
if (dev_mem_totals[i] > max_mem_size) {
|
|
||||||
dev_best_index = dgpus[i];
|
|
||||||
max_mem_size = dev_mem_totals[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (igpu_count != 0) {
|
|
||||||
for (size_t i = 0; i < igpu_count; ++i) {
|
|
||||||
if (dev_mem_totals[i] > max_mem_size) {
|
|
||||||
dev_best_index = igpus[i];
|
|
||||||
max_mem_size = dev_mem_totals[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PTK_DEBUG("best device index: %ld", dev_best_index);
|
|
||||||
PTK_DEBUG("device name: %s", dev_props[dev_best_index].deviceName);
|
|
||||||
|
|
||||||
PTK_DEBUG("device type: %s", (dgpu_count != 0 ? "dgpu" : (igpu_count != 0 ? "igpu" : "probably cpu")));
|
|
||||||
|
|
||||||
PTK_DEBUG("total memory: %lu", dev_mem_totals[dev_best_index]);
|
|
||||||
|
|
||||||
m_physical_dev = devs[dev_best_index];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSurfaceFormatKHR select_swap_surface_format(const PTK_LIST(VkSurfaceFormatKHR) available_formats) {
|
|
||||||
PTK_LIST_FOR_EACH(const VkSurfaceFormatKHR, available_formats, current_format, {
|
|
||||||
if (current_format.format == VK_FORMAT_B8G8R8A8_SRGB && current_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
||||||
return current_format;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return available_formats.data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR select_swap_present_mode(const PTK_LIST(VkPresentModeKHR) available_present_modes) {
|
|
||||||
PTK_LIST_FOR_EACH(const VkPresentModeKHR, available_present_modes, current_present_mode, {
|
|
||||||
if (current_present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
||||||
return current_present_mode;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D select_swap_extent(const VkSurfaceCapabilitiesKHR capabilities) {
|
|
||||||
if (capabilities.currentExtent.width != UINT32_MAX) {
|
|
||||||
return capabilities.currentExtent;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
glfwGetFramebufferSize(m_window, &width, &height);
|
|
||||||
|
|
||||||
VkExtent2D actual_extent = {
|
|
||||||
.width = (uint32_t)width,
|
|
||||||
.height = (uint32_t)height,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (actual_extent.width < capabilities.minImageExtent.width) {
|
|
||||||
actual_extent.width = capabilities.minImageExtent.width;
|
|
||||||
} else if (actual_extent.width > capabilities.maxImageExtent.width) {
|
|
||||||
actual_extent.width = capabilities.maxImageExtent.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actual_extent.height < capabilities.minImageExtent.height) {
|
|
||||||
actual_extent.height = capabilities.minImageExtent.height;
|
|
||||||
} else if (actual_extent.height > capabilities.maxImageExtent.height) {
|
|
||||||
actual_extent.height = capabilities.maxImageExtent.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return actual_extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
SwapchainSupportInfo query_swapchain_support(const VkPhysicalDevice dev) {
|
|
||||||
SwapchainSupportInfo info;
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, m_surface, &info.capabilities);
|
|
||||||
|
|
||||||
const uint32_t width = info.capabilities.currentExtent.width;
|
|
||||||
const uint32_t height = info.capabilities.currentExtent.height;
|
|
||||||
|
|
||||||
if (
|
|
||||||
info.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR
|
|
||||||
|| info.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR
|
|
||||||
) {
|
|
||||||
info.capabilities.currentExtent.height = width;
|
|
||||||
info.capabilities.currentExtent.width = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(dev, m_surface, &info.formats.allocated, NULL);
|
|
||||||
|
|
||||||
if (info.formats.allocated != 0) {
|
|
||||||
info.formats = PTK_LIST_NEW(VkSurfaceFormatKHR, info.formats.allocated);
|
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(dev, m_surface, &info.formats.allocated, info.formats.data);
|
|
||||||
info.formats.size = info.formats.allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(dev, m_surface, &info.present_modes.allocated, NULL);
|
|
||||||
|
|
||||||
if (info.present_modes.allocated != 0) {
|
|
||||||
info.present_modes = PTK_LIST_NEW(VkPresentModeKHR, info.present_modes.allocated);
|
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(dev, m_surface, &info.present_modes.allocated, info.present_modes.data);
|
|
||||||
info.present_modes.size = info.present_modes.allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool are_extensions_supported(const VkPhysicalDevice dev) {
|
|
||||||
PTK_LIST(VkExtensionProperties) available_extensions;
|
|
||||||
vkEnumerateDeviceExtensionProperties(dev, NULL, &available_extensions.allocated, NULL);
|
|
||||||
|
|
||||||
available_extensions = PTK_LIST_NEW(VkExtensionProperties, available_extensions.allocated);
|
|
||||||
vkEnumerateDeviceExtensionProperties(dev, NULL, &available_extensions.allocated, available_extensions.data);
|
|
||||||
PTK_LIST_FILLED(available_extensions);
|
|
||||||
|
|
||||||
size_t supported_extensions = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_device_extensions.size; ++i) {
|
|
||||||
PTK_LIST_FOR_EACH(const VkExtensionProperties, available_extensions, current_extension, {
|
|
||||||
if (strcmp(m_device_extensions.data[i], current_extension.extensionName) == 0) {
|
|
||||||
supported_extensions += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return supported_extensions == m_device_extensions.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_device_suitable(const VkPhysicalDevice dev) {
|
|
||||||
PTK_LIST(VkQueueFamilyProperties) queue_families;
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(dev, &queue_families.allocated, NULL);
|
|
||||||
|
|
||||||
queue_families = PTK_LIST_NEW(VkQueueFamilyProperties, queue_families.allocated);
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(dev, &queue_families.allocated, queue_families.data);
|
|
||||||
PTK_LIST_FILLED(queue_families);
|
|
||||||
|
|
||||||
m_queue_family_indices.graphics = PTK_OPTION_NONE(uint32_t);
|
|
||||||
m_queue_family_indices.present = PTK_OPTION_NONE(uint32_t);
|
|
||||||
PTK_LIST_FOR_EACH_E(const VkQueueFamilyProperties, queue_families, i, queue_family, {
|
|
||||||
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
||||||
m_queue_family_indices.graphics = PTK_OPTION_SOME(uint32_t, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBool32 present_support = VK_FALSE;
|
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, m_surface, &present_support);
|
|
||||||
if (present_support) {
|
|
||||||
m_queue_family_indices.present = PTK_OPTION_SOME(uint32_t, i);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const bool indices_found = m_queue_family_indices.graphics.exists
|
|
||||||
&& m_queue_family_indices.present.exists;
|
|
||||||
const bool extensions_supported = are_extensions_supported(dev);
|
|
||||||
bool swapchain_adequate = false;
|
|
||||||
|
|
||||||
if (extensions_supported) {
|
|
||||||
const SwapchainSupportInfo swapchain_support = query_swapchain_support(dev);
|
|
||||||
swapchain_adequate = swapchain_support.formats.size != 0
|
|
||||||
&& swapchain_support.present_modes.size != 0;
|
|
||||||
PTK_LIST_FREE(swapchain_support.formats);
|
|
||||||
PTK_LIST_FREE(swapchain_support.present_modes);
|
|
||||||
}
|
|
||||||
|
|
||||||
PTK_LIST_FREE(queue_families);
|
|
||||||
|
|
||||||
return indices_found && extensions_supported && swapchain_adequate;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create_logical_dev(void) {
|
|
||||||
if (!is_device_suitable(m_physical_dev)) {
|
|
||||||
PTK_ERR("physical device isn't suitable");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceQueueCreateInfo queue_create_infos[m_queue_family_count];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_queue_family_count; ++i) {
|
|
||||||
const PTK_OPTION(uint32_t) index = *(((PTK_OPTION(uint32_t) *)&m_queue_family_indices) + i);
|
|
||||||
|
|
||||||
queue_create_infos[i] = (VkDeviceQueueCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.queueFamilyIndex = index.value,
|
|
||||||
.queueCount = 1,
|
|
||||||
.pQueuePriorities = &(float){1.0f},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateDevice(
|
|
||||||
m_physical_dev,
|
|
||||||
&(VkDeviceCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.queueCreateInfoCount = m_queue_family_count,
|
|
||||||
.pQueueCreateInfos = queue_create_infos,
|
|
||||||
.enabledLayerCount = m_validation_layers.size,
|
|
||||||
.ppEnabledLayerNames = m_validation_layers.data,
|
|
||||||
.enabledExtensionCount = m_device_extensions.size,
|
|
||||||
.ppEnabledExtensionNames = m_device_extensions.data,
|
|
||||||
.pEnabledFeatures = &(VkPhysicalDeviceFeatures){0},
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&g_dev
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
vkGetDeviceQueue(g_dev, m_queue_family_indices.graphics.value, 0, &g_graphics_queue);
|
|
||||||
vkGetDeviceQueue(g_dev, m_queue_family_indices.present.value, 0, &g_present_queue);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create_swapchain(void) {
|
|
||||||
const SwapchainSupportInfo swapchain_support = query_swapchain_support(m_physical_dev);
|
|
||||||
|
|
||||||
const VkSurfaceFormatKHR surface_format = select_swap_surface_format(swapchain_support.formats);
|
|
||||||
const VkPresentModeKHR present_mode = select_swap_present_mode(swapchain_support.present_modes);
|
|
||||||
const VkExtent2D extent = select_swap_extent(swapchain_support.capabilities);
|
|
||||||
|
|
||||||
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
|
||||||
|
|
||||||
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount) {
|
|
||||||
image_count = swapchain_support.capabilities.maxImageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool queue_families_differ = m_queue_family_indices.graphics.value != m_queue_family_indices.present.value;
|
|
||||||
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateSwapchainKHR(
|
|
||||||
g_dev,
|
|
||||||
&(VkSwapchainCreateInfoKHR){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.surface = m_surface,
|
|
||||||
.minImageCount = image_count,
|
|
||||||
.imageFormat = surface_format.format,
|
|
||||||
.imageColorSpace = surface_format.colorSpace,
|
|
||||||
.imageExtent = extent,
|
|
||||||
.imageArrayLayers = 1,
|
|
||||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
||||||
.imageSharingMode =
|
|
||||||
queue_families_differ
|
|
||||||
? VK_SHARING_MODE_CONCURRENT
|
|
||||||
: VK_SHARING_MODE_EXCLUSIVE,
|
|
||||||
.queueFamilyIndexCount =
|
|
||||||
queue_families_differ
|
|
||||||
? 2
|
|
||||||
: 0,
|
|
||||||
.pQueueFamilyIndices =
|
|
||||||
queue_families_differ
|
|
||||||
? (const uint32_t []){
|
|
||||||
m_queue_family_indices.graphics.value,
|
|
||||||
m_queue_family_indices.present.value
|
|
||||||
}
|
|
||||||
: NULL,
|
|
||||||
.preTransform = swapchain_support.capabilities.currentTransform,
|
|
||||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
||||||
.presentMode = present_mode,
|
|
||||||
.clipped = VK_TRUE,
|
|
||||||
.oldSwapchain = VK_NULL_HANDLE,
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&g_swapchain
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
vkGetSwapchainImagesKHR(g_dev, g_swapchain, &m_swapchain_images.allocated, NULL);
|
|
||||||
m_swapchain_images = PTK_LIST_NEW(VkImage, m_swapchain_images.allocated);
|
|
||||||
vkGetSwapchainImagesKHR(g_dev, g_swapchain, &m_swapchain_images.allocated, m_swapchain_images.data);
|
|
||||||
PTK_LIST_FILLED(m_swapchain_images);
|
|
||||||
|
|
||||||
m_swapchain_image_format = surface_format.format;
|
|
||||||
m_swapchain_extent = extent;
|
|
||||||
|
|
||||||
PTK_LIST_FREE(swapchain_support.formats);
|
|
||||||
PTK_LIST_FREE(swapchain_support.present_modes);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create_image_views(void) {
|
|
||||||
m_swapchain_image_views = PTK_LIST_NEW(VkImageView, m_swapchain_images.size);
|
|
||||||
|
|
||||||
PTK_LIST_FOR_EACH_E(VkImage, m_swapchain_images, i, swapchain_image, {
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateImageView(
|
|
||||||
g_dev,
|
|
||||||
&(VkImageViewCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.image = swapchain_image,
|
|
||||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
||||||
.format = m_swapchain_image_format,
|
|
||||||
.components = (VkComponentMapping){
|
|
||||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
},
|
|
||||||
.subresourceRange = (VkImageSubresourceRange){
|
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = 1,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&m_swapchain_image_views.data[i]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
m_swapchain_image_views.size += 1;
|
|
||||||
})
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTK_STRING read_spv(const char *filename) {
|
PTK_STRING read_spv(const char *filename) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
|
@ -648,61 +167,6 @@ PTK_OPTION(VkShaderModule) create_shader_module(const PTK_STRING code) {
|
||||||
return PTK_OPTION_SOME(VkShaderModule, shader_module);
|
return PTK_OPTION_SOME(VkShaderModule, shader_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_render_pass(void) {
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateRenderPass(
|
|
||||||
g_dev,
|
|
||||||
&(VkRenderPassCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &(VkAttachmentDescription){
|
|
||||||
.flags = 0,
|
|
||||||
.format = m_swapchain_image_format,
|
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
||||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
||||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
||||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
||||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
||||||
},
|
|
||||||
.subpassCount = 1,
|
|
||||||
.pSubpasses = &(VkSubpassDescription){
|
|
||||||
.flags = 0,
|
|
||||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
.inputAttachmentCount = 0,
|
|
||||||
.pInputAttachments = NULL,
|
|
||||||
.colorAttachmentCount = 1,
|
|
||||||
.pColorAttachments = &(VkAttachmentReference){
|
|
||||||
.attachment = 0,
|
|
||||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
},
|
|
||||||
.pResolveAttachments = NULL,
|
|
||||||
.pDepthStencilAttachment = NULL,
|
|
||||||
.preserveAttachmentCount = 0,
|
|
||||||
.pPreserveAttachments = NULL,
|
|
||||||
},
|
|
||||||
.dependencyCount = 1,
|
|
||||||
.pDependencies = &(VkSubpassDependency){
|
|
||||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
||||||
.dstSubpass = 0,
|
|
||||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.srcAccessMask = 0,
|
|
||||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
.dependencyFlags = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&m_render_pass
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create_descriptor_set_layout(void) {
|
bool create_descriptor_set_layout(void) {
|
||||||
VK_TRY(false,
|
VK_TRY(false,
|
||||||
vkCreateDescriptorSetLayout(
|
vkCreateDescriptorSetLayout(
|
||||||
|
@ -812,8 +276,8 @@ bool create_graphics_pipeline(void) {
|
||||||
.pViewports = &(VkViewport){
|
.pViewports = &(VkViewport){
|
||||||
.x = 0.0f,
|
.x = 0.0f,
|
||||||
.y = 0.0f,
|
.y = 0.0f,
|
||||||
.width = (float) m_swapchain_extent.width,
|
.width = (float) g_swapchain_extent.width,
|
||||||
.height = (float) m_swapchain_extent.height,
|
.height = (float) g_swapchain_extent.height,
|
||||||
.minDepth = 0.0f,
|
.minDepth = 0.0f,
|
||||||
.maxDepth = 1.0f,
|
.maxDepth = 1.0f,
|
||||||
},
|
},
|
||||||
|
@ -823,7 +287,7 @@ bool create_graphics_pipeline(void) {
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
},
|
},
|
||||||
.extent = m_swapchain_extent,
|
.extent = g_swapchain_extent,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -918,7 +382,7 @@ bool create_graphics_pipeline(void) {
|
||||||
.pColorBlendState = &color_blending,
|
.pColorBlendState = &color_blending,
|
||||||
.pDynamicState = &dynamic_state,
|
.pDynamicState = &dynamic_state,
|
||||||
.layout = m_pipeline_layout,
|
.layout = m_pipeline_layout,
|
||||||
.renderPass = m_render_pass,
|
.renderPass = g_render_pass,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.basePipelineHandle = VK_NULL_HANDLE,
|
.basePipelineHandle = VK_NULL_HANDLE,
|
||||||
.basePipelineIndex = -1,
|
.basePipelineIndex = -1,
|
||||||
|
@ -934,36 +398,6 @@ bool create_graphics_pipeline(void) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_framebuffers(void) {
|
|
||||||
m_swapchain_framebuffers = PTK_LIST_NEW(VkFramebuffer, m_swapchain_image_views.size);
|
|
||||||
|
|
||||||
VkFramebuffer fb;
|
|
||||||
|
|
||||||
PTK_LIST_FOR_EACH(VkImageView, m_swapchain_image_views, swapchain_image_view, {
|
|
||||||
VK_TRY(false,
|
|
||||||
vkCreateFramebuffer(
|
|
||||||
g_dev,
|
|
||||||
&(VkFramebufferCreateInfo){
|
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
||||||
.pNext = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.renderPass = m_render_pass,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &swapchain_image_view,
|
|
||||||
.width = m_swapchain_extent.width,
|
|
||||||
.height = m_swapchain_extent.height,
|
|
||||||
.layers = 1,
|
|
||||||
},
|
|
||||||
NULL,
|
|
||||||
&fb
|
|
||||||
)
|
|
||||||
);
|
|
||||||
PTK_LIST_ADD(VkFramebuffer, m_swapchain_framebuffers, fb);
|
|
||||||
})
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create_command_pool(void) {
|
bool create_command_pool(void) {
|
||||||
VK_TRY(false,
|
VK_TRY(false,
|
||||||
vkCreateCommandPool(
|
vkCreateCommandPool(
|
||||||
|
@ -972,7 +406,7 @@ bool create_command_pool(void) {
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||||
.pNext = NULL,
|
.pNext = NULL,
|
||||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||||
.queueFamilyIndex = m_queue_family_indices.graphics.value,
|
.queueFamilyIndex = g_queue_family_indices.graphics.value,
|
||||||
},
|
},
|
||||||
NULL,
|
NULL,
|
||||||
&m_command_pool
|
&m_command_pool
|
||||||
|
@ -984,7 +418,7 @@ bool create_command_pool(void) {
|
||||||
|
|
||||||
PTK_OPTION(uint32_t) find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props) {
|
PTK_OPTION(uint32_t) find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props) {
|
||||||
VkPhysicalDeviceMemoryProperties mem_props;
|
VkPhysicalDeviceMemoryProperties mem_props;
|
||||||
vkGetPhysicalDeviceMemoryProperties(m_physical_dev, &mem_props);
|
vkGetPhysicalDeviceMemoryProperties(g_physical_dev, &mem_props);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
|
for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
|
||||||
if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
|
if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
|
||||||
|
@ -1345,14 +779,14 @@ bool vk_record_command_buffer(const VkCommandBuffer command_buffer, const uint32
|
||||||
&(VkRenderPassBeginInfo){
|
&(VkRenderPassBeginInfo){
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
.pNext = NULL,
|
.pNext = NULL,
|
||||||
.renderPass = m_render_pass,
|
.renderPass = g_render_pass,
|
||||||
.framebuffer = m_swapchain_framebuffers.data[image_index],
|
.framebuffer = g_swapchain_framebuffers.data[image_index],
|
||||||
.renderArea = (VkRect2D){
|
.renderArea = (VkRect2D){
|
||||||
.offset = (VkOffset2D){
|
.offset = (VkOffset2D){
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
},
|
},
|
||||||
.extent = m_swapchain_extent,
|
.extent = g_swapchain_extent,
|
||||||
},
|
},
|
||||||
.clearValueCount = 1,
|
.clearValueCount = 1,
|
||||||
.pClearValues = &(VkClearValue){
|
.pClearValues = &(VkClearValue){
|
||||||
|
@ -1423,55 +857,9 @@ bool create_sync_objects(void) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_swapchain(void) {
|
|
||||||
PTK_LIST_FOR_EACH(VkFramebuffer, m_swapchain_framebuffers, fb, {
|
|
||||||
vkDestroyFramebuffer(g_dev, fb, NULL);
|
|
||||||
})
|
|
||||||
PTK_LIST_FREE(m_swapchain_framebuffers);
|
|
||||||
|
|
||||||
PTK_LIST_FREE(m_swapchain_images);
|
|
||||||
PTK_LIST_FOR_EACH(VkImageView, m_swapchain_image_views, iv, {
|
|
||||||
vkDestroyImageView(g_dev, iv, NULL);
|
|
||||||
})
|
|
||||||
PTK_LIST_FREE(m_swapchain_image_views);
|
|
||||||
|
|
||||||
vkDestroySwapchainKHR(g_dev, g_swapchain, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vk_recreate_swapchain(void) {
|
|
||||||
int width = 0, height = 0;
|
|
||||||
glfwGetFramebufferSize(m_window, &width, &height);
|
|
||||||
|
|
||||||
while (width == 0 || height == 0) {
|
|
||||||
glfwGetFramebufferSize(m_window, &width, &height);
|
|
||||||
glfwWaitEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
vkDeviceWaitIdle(g_dev);
|
|
||||||
|
|
||||||
cleanup_swapchain();
|
|
||||||
|
|
||||||
if (!create_swapchain()) {
|
|
||||||
PTK_ERR("failed creating new swapchain");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!create_image_views()) {
|
|
||||||
PTK_ERR("failed creating new image views");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!create_framebuffers()) {
|
|
||||||
PTK_ERR("failed creating new framebuffers");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vk_update_uniform_buffer(const size_t current_frame) {
|
bool vk_update_uniform_buffer(const size_t current_frame) {
|
||||||
m_uniform_buffer_object.window_size.w = m_swapchain_extent.width;
|
m_uniform_buffer_object.window_size.w = g_swapchain_extent.width;
|
||||||
m_uniform_buffer_object.window_size.h = m_swapchain_extent.height;
|
m_uniform_buffer_object.window_size.h = g_swapchain_extent.height;
|
||||||
|
|
||||||
memcpy(m_uniform_buffers_mapped.data[current_frame], &m_uniform_buffer_object, sizeof(m_uniform_buffer_object));
|
memcpy(m_uniform_buffers_mapped.data[current_frame], &m_uniform_buffer_object, sizeof(m_uniform_buffer_object));
|
||||||
|
|
||||||
|
@ -1483,34 +871,34 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
|
||||||
m_uniform_buffer_object.initial_window_size.w = width;
|
m_uniform_buffer_object.initial_window_size.w = width;
|
||||||
m_uniform_buffer_object.initial_window_size.h = height;
|
m_uniform_buffer_object.initial_window_size.h = height;
|
||||||
|
|
||||||
if (!create_vk_instance(title, version)) {
|
if (!vk_instance_create(title, version, m_validation_layers)) {
|
||||||
PTK_ERR("failed creating VkInstance");
|
PTK_ERR("failed creating VkInstance");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!select_physical_dev()) {
|
if (!vk_select_physical_dev(g_instance)) {
|
||||||
PTK_ERR("failed selecting physical device");
|
PTK_ERR("failed selecting physical device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VK_TRY(false, glfwCreateWindowSurface(m_instance, m_window, NULL, &m_surface));
|
VK_TRY(false, glfwCreateWindowSurface(g_instance, m_window, NULL, &g_surface));
|
||||||
|
|
||||||
if (!create_logical_dev()) {
|
if (!vk_create_logical_dev(g_physical_dev, g_surface, m_validation_layers)) {
|
||||||
PTK_ERR("failed creating logical device");
|
PTK_ERR("failed creating logical device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_swapchain()) {
|
if (!vk_create_swapchain(m_window, g_dev, g_physical_dev, g_surface)) {
|
||||||
PTK_ERR("failed creating swapchain");
|
PTK_ERR("failed creating swapchain");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_image_views()) {
|
if (!vk_create_image_views(g_dev)) {
|
||||||
PTK_ERR("failed creating image views");
|
PTK_ERR("failed creating image views");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_render_pass()) {
|
if (!vk_create_render_pass()) {
|
||||||
PTK_ERR("failed creating render pass");
|
PTK_ERR("failed creating render pass");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1525,7 +913,7 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_framebuffers()) {
|
if (!vk_create_framebuffers()) {
|
||||||
PTK_ERR("failed creating framebuffers");
|
PTK_ERR("failed creating framebuffers");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1574,12 +962,12 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
|
||||||
}
|
}
|
||||||
|
|
||||||
void vk_cleanup(void) {
|
void vk_cleanup(void) {
|
||||||
cleanup_swapchain();
|
vk_cleanup_swapchain(g_dev);
|
||||||
|
|
||||||
vkDestroyPipeline(g_dev, m_pipeline, NULL);
|
vkDestroyPipeline(g_dev, m_pipeline, NULL);
|
||||||
vkDestroyPipelineLayout(g_dev, m_pipeline_layout, NULL);
|
vkDestroyPipelineLayout(g_dev, m_pipeline_layout, NULL);
|
||||||
|
|
||||||
vkDestroyRenderPass(g_dev, m_render_pass, NULL);
|
vkDestroyRenderPass(g_dev, g_render_pass, NULL);
|
||||||
|
|
||||||
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
||||||
vkDestroyBuffer(g_dev, m_uniform_buffers.data[i], NULL);
|
vkDestroyBuffer(g_dev, m_uniform_buffers.data[i], NULL);
|
||||||
|
@ -1609,8 +997,8 @@ void vk_cleanup(void) {
|
||||||
|
|
||||||
vkDestroyDevice(g_dev, NULL);
|
vkDestroyDevice(g_dev, NULL);
|
||||||
|
|
||||||
vkDestroySurfaceKHR(m_instance, m_surface, NULL);
|
vkDestroySurfaceKHR(g_instance, g_surface, NULL);
|
||||||
vkDestroyInstance(m_instance, NULL);
|
vkDestroyInstance(g_instance, NULL);
|
||||||
|
|
||||||
glfwDestroyWindow(m_window);
|
glfwDestroyWindow(m_window);
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,6 @@ PTK_LIST_DEFINE(VkCommandBuffer);
|
||||||
PTK_LIST_DEFINE(VkSemaphore);
|
PTK_LIST_DEFINE(VkSemaphore);
|
||||||
PTK_LIST_DEFINE(VkFence);
|
PTK_LIST_DEFINE(VkFence);
|
||||||
|
|
||||||
extern VkDevice g_dev;
|
|
||||||
extern VkSwapchainKHR g_swapchain;
|
|
||||||
|
|
||||||
extern VkQueue g_graphics_queue;
|
extern VkQueue g_graphics_queue;
|
||||||
extern VkQueue g_present_queue;
|
extern VkQueue g_present_queue;
|
||||||
|
|
||||||
|
@ -28,14 +25,14 @@ extern PTK_LIST(VkSemaphore) g_image_available_semaphores;
|
||||||
extern PTK_LIST(VkSemaphore) g_render_finished_semaphores;
|
extern PTK_LIST(VkSemaphore) g_render_finished_semaphores;
|
||||||
extern PTK_LIST(VkFence) g_in_flight_fences;
|
extern PTK_LIST(VkFence) g_in_flight_fences;
|
||||||
|
|
||||||
|
extern VkSurfaceKHR g_surface;
|
||||||
|
|
||||||
bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const char *title, const PtkVersion version);
|
bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const char *title, const PtkVersion version);
|
||||||
|
|
||||||
bool vk_transfer_vertex_data(void);
|
bool vk_transfer_vertex_data(void);
|
||||||
|
|
||||||
bool vk_record_command_buffer(const VkCommandBuffer command_buffer, const uint32_t image_index);
|
bool vk_record_command_buffer(const VkCommandBuffer command_buffer, const uint32_t image_index);
|
||||||
|
|
||||||
bool vk_recreate_swapchain(void);
|
|
||||||
|
|
||||||
bool vk_update_uniform_buffer(const size_t current_frame);
|
bool vk_update_uniform_buffer(const size_t current_frame);
|
||||||
|
|
||||||
void vk_cleanup(void);
|
void vk_cleanup(void);
|
||||||
|
|
89
src/ptk_vk/instance.c
Normal file
89
src/ptk_vk/instance.c
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#include <ptk_vk/instance.h>
|
||||||
|
|
||||||
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
|
#include <ptk_array.h>
|
||||||
|
|
||||||
|
#ifndef GLFW_INCLUDE_VULKAN
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#endif
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkLayerProperties);
|
||||||
|
|
||||||
|
bool check_validation_layers(const PTK_ARRAY(constcharptr) validation_layers) {
|
||||||
|
PTK_LIST(VkLayerProperties) available_layers;
|
||||||
|
|
||||||
|
vkEnumerateInstanceLayerProperties(&available_layers.allocated, NULL);
|
||||||
|
|
||||||
|
available_layers = PTK_LIST_NEW(VkLayerProperties, available_layers.allocated);
|
||||||
|
vkEnumerateInstanceLayerProperties(&available_layers.allocated, available_layers.data);
|
||||||
|
PTK_LIST_FILLED(available_layers);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < validation_layers.size; ++i) {
|
||||||
|
const char *layer_name = validation_layers.data[i];
|
||||||
|
|
||||||
|
bool layer_found = false;
|
||||||
|
|
||||||
|
PTK_LIST_FOR_EACH(const VkLayerProperties, available_layers, layer_properties, {
|
||||||
|
if (strcmp(layer_name, layer_properties.layerName) == 0) {
|
||||||
|
layer_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!layer_found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VkInstance g_instance;
|
||||||
|
|
||||||
|
bool vk_instance_create(const char *title, const PtkVersion version, const PTK_ARRAY(constcharptr) validation_layers) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!check_validation_layers(validation_layers)) {
|
||||||
|
PTK_ERR("couldn't find requested validation layer");
|
||||||
|
return PTK_OPTION_NONE(VkInstance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PTK_ARRAY(constcharptr) extension_names = PTK_ARRAY_EMPTY(constcharptr);
|
||||||
|
extension_names.data = glfwGetRequiredInstanceExtensions(&extension_names.size);
|
||||||
|
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateInstance(
|
||||||
|
&(VkInstanceCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.pApplicationInfo = &(VkApplicationInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.pApplicationName = title,
|
||||||
|
.applicationVersion = VK_MAKE_API_VERSION(0, version.major, version.minor, version.patch),
|
||||||
|
.pEngineName = PTK_ENGINE_NAME,
|
||||||
|
.engineVersion = VK_MAKE_API_VERSION(0, PTK_VERSION_MAJOR, PTK_VERSION_MINOR, PTK_VERSION_PATCH),
|
||||||
|
.apiVersion = VK_API_VERSION_1_3,
|
||||||
|
},
|
||||||
|
.enabledLayerCount = validation_layers.size,
|
||||||
|
.ppEnabledLayerNames = validation_layers.data,
|
||||||
|
.enabledExtensionCount = extension_names.size,
|
||||||
|
.ppEnabledExtensionNames = extension_names.data,
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&g_instance
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
20
src/ptk_vk/instance.h
Normal file
20
src/ptk_vk/instance.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#ifndef PTK_PTK_VK_INSTANCE_H_
|
||||||
|
#define PTK_PTK_VK_INSTANCE_H_
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
#include <ptk.h>
|
||||||
|
#include <ptk_array.h>
|
||||||
|
#include <ptk_option.h>
|
||||||
|
|
||||||
|
extern VkInstance g_instance;
|
||||||
|
|
||||||
|
PTK_OPTION_DEFINE(VkInstance);
|
||||||
|
typedef const char *constcharptr;
|
||||||
|
PTK_ARRAY_DEFINE(constcharptr);
|
||||||
|
|
||||||
|
bool vk_instance_create(const char *title, const PtkVersion version, const PTK_ARRAY(constcharptr) validation_layers);
|
||||||
|
|
||||||
|
#endif // PTK_PTK_VK_INSTANCE_H_
|
81
src/ptk_vk/physical_device.c
Normal file
81
src/ptk_vk/physical_device.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#include <ptk_vk/physical_device.h>
|
||||||
|
|
||||||
|
#include <ptk_log.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
VkPhysicalDevice g_physical_dev;
|
||||||
|
|
||||||
|
bool vk_select_physical_dev(const VkInstance instance) {
|
||||||
|
uint32_t dev_count = 0;
|
||||||
|
vkEnumeratePhysicalDevices(instance, &dev_count, NULL);
|
||||||
|
if (dev_count == 0) {
|
||||||
|
PTK_ERR("failed to find GPU with vulkan support");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VkPhysicalDevice devs[dev_count];
|
||||||
|
vkEnumeratePhysicalDevices(instance, &dev_count, devs);
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties dev_props[dev_count];
|
||||||
|
uint32_t dgpus[dev_count];
|
||||||
|
uint32_t dgpu_count = 0;
|
||||||
|
uint32_t igpus[dev_count];
|
||||||
|
uint32_t igpu_count = 0;
|
||||||
|
|
||||||
|
VkPhysicalDeviceMemoryProperties dev_mem_props[dev_count];
|
||||||
|
uint32_t dev_mem_counts[dev_count];
|
||||||
|
VkDeviceSize dev_mem_totals[dev_count];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < dev_count; ++i) {
|
||||||
|
vkGetPhysicalDeviceProperties(devs[i], &dev_props[i]);
|
||||||
|
|
||||||
|
if (dev_props[i].deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||||
|
dgpus[dgpu_count] = i;
|
||||||
|
dgpu_count += 1;
|
||||||
|
} else if (dev_props[i].deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||||
|
igpus[igpu_count] = i;
|
||||||
|
igpu_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(devs[i], &dev_mem_props[i]);
|
||||||
|
|
||||||
|
dev_mem_counts[i] = dev_mem_props[i].memoryHeapCount;
|
||||||
|
dev_mem_totals[i] = 0;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < dev_mem_counts[i]; ++j) {
|
||||||
|
dev_mem_totals[i] += dev_mem_props[i].memoryHeaps[j].size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize max_mem_size = 0;
|
||||||
|
size_t dev_best_index = 0;
|
||||||
|
|
||||||
|
if (dgpu_count != 0) {
|
||||||
|
for (size_t i = 0; i < dgpu_count; ++i) {
|
||||||
|
if (dev_mem_totals[i] > max_mem_size) {
|
||||||
|
dev_best_index = dgpus[i];
|
||||||
|
max_mem_size = dev_mem_totals[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (igpu_count != 0) {
|
||||||
|
for (size_t i = 0; i < igpu_count; ++i) {
|
||||||
|
if (dev_mem_totals[i] > max_mem_size) {
|
||||||
|
dev_best_index = igpus[i];
|
||||||
|
max_mem_size = dev_mem_totals[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PTK_DEBUG("best device index: %ld", dev_best_index);
|
||||||
|
PTK_DEBUG("device name: %s", dev_props[dev_best_index].deviceName);
|
||||||
|
|
||||||
|
PTK_DEBUG("device type: %s", (dgpu_count != 0 ? "dgpu" : (igpu_count != 0 ? "igpu" : "probably cpu")));
|
||||||
|
|
||||||
|
PTK_DEBUG("total memory: %lu", dev_mem_totals[dev_best_index]);
|
||||||
|
|
||||||
|
g_physical_dev = devs[dev_best_index];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
16
src/ptk_vk/physical_device.h
Normal file
16
src/ptk_vk/physical_device.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#ifndef PTK_PTK_VK_PHYSICAL_DEVICE_H_
|
||||||
|
#define PTK_PTK_VK_PHYSICAL_DEVICE_H_
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
#include <ptk_option.h>
|
||||||
|
|
||||||
|
extern VkPhysicalDevice g_physical_dev;
|
||||||
|
|
||||||
|
PTK_OPTION_DEFINE(VkPhysicalDevice);
|
||||||
|
|
||||||
|
bool vk_select_physical_dev(const VkInstance instance);
|
||||||
|
|
||||||
|
#endif // PTK_PTK_VK_PHYSICAL_DEVICE_H_
|
66
src/ptk_vk/render_pass.c
Normal file
66
src/ptk_vk/render_pass.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
|
||||||
|
#include <ptk_vk/render_pass.h>
|
||||||
|
#include <ptk_vk/swapchain.h>
|
||||||
|
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
|
VkRenderPass g_render_pass;
|
||||||
|
|
||||||
|
bool vk_create_render_pass(void) {
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateRenderPass(
|
||||||
|
g_dev,
|
||||||
|
&(VkRenderPassCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &(VkAttachmentDescription){
|
||||||
|
.flags = 0,
|
||||||
|
.format = g_swapchain_image_format,
|
||||||
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
|
},
|
||||||
|
.subpassCount = 1,
|
||||||
|
.pSubpasses = &(VkSubpassDescription){
|
||||||
|
.flags = 0,
|
||||||
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
.inputAttachmentCount = 0,
|
||||||
|
.pInputAttachments = NULL,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachments = &(VkAttachmentReference){
|
||||||
|
.attachment = 0,
|
||||||
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
},
|
||||||
|
.pResolveAttachments = NULL,
|
||||||
|
.pDepthStencilAttachment = NULL,
|
||||||
|
.preserveAttachmentCount = 0,
|
||||||
|
.pPreserveAttachments = NULL,
|
||||||
|
},
|
||||||
|
.dependencyCount = 1,
|
||||||
|
.pDependencies = &(VkSubpassDependency){
|
||||||
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||||
|
.dstSubpass = 0,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = 0,
|
||||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dependencyFlags = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&g_render_pass
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
14
src/ptk_vk/render_pass.h
Normal file
14
src/ptk_vk/render_pass.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#ifndef PTK_PTK_VK_RENDER_PASS_H_
|
||||||
|
#define PTK_PTK_VK_RENDER_PASS_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
extern VkRenderPass g_render_pass;
|
||||||
|
|
||||||
|
bool vk_create_render_pass(void);
|
||||||
|
|
||||||
|
#endif // PTK_PTK_VK_RENDER_PASS_H_
|
296
src/ptk_vk/swapchain.c
Normal file
296
src/ptk_vk/swapchain.c
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#include <ptk_vk/swapchain.h>
|
||||||
|
|
||||||
|
#include <ptk_vk/device.h>
|
||||||
|
#include <ptk_vk/physical_device.h>
|
||||||
|
#include <ptk_vk/render_pass.h>
|
||||||
|
#include <ptk_vk/utils.h>
|
||||||
|
|
||||||
|
#include <ptk_list.h>
|
||||||
|
|
||||||
|
#ifndef GLFW_INCLUDE_VULKAN
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#endif
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
VkSwapchainKHR g_swapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkImage);
|
||||||
|
PTK_LIST_DEFINE(VkImageView);
|
||||||
|
|
||||||
|
static PTK_LIST(VkImage) m_swapchain_images;
|
||||||
|
static PTK_LIST(VkImageView) m_swapchain_image_views;
|
||||||
|
|
||||||
|
VkFormat g_swapchain_image_format;
|
||||||
|
VkExtent2D g_swapchain_extent;
|
||||||
|
|
||||||
|
PTK_LIST(VkFramebuffer) g_swapchain_framebuffers;
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR select_swap_surface_format(const PTK_LIST(VkSurfaceFormatKHR) available_formats) {
|
||||||
|
PTK_LIST_FOR_EACH(const VkSurfaceFormatKHR, available_formats, current_format, {
|
||||||
|
if (current_format.format == VK_FORMAT_B8G8R8A8_SRGB && current_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
|
return current_format;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return available_formats.data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR select_swap_present_mode(const PTK_LIST(VkPresentModeKHR) available_present_modes) {
|
||||||
|
PTK_LIST_FOR_EACH(const VkPresentModeKHR, available_present_modes, current_present_mode, {
|
||||||
|
if (current_present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||||
|
return current_present_mode;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D select_swap_extent(const VkSurfaceCapabilitiesKHR capabilities, GLFWwindow *window) {
|
||||||
|
if (capabilities.currentExtent.width != UINT32_MAX) {
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
|
||||||
|
VkExtent2D actual_extent = {
|
||||||
|
.width = (uint32_t)width,
|
||||||
|
.height = (uint32_t)height,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (actual_extent.width < capabilities.minImageExtent.width) {
|
||||||
|
actual_extent.width = capabilities.minImageExtent.width;
|
||||||
|
} else if (actual_extent.width > capabilities.maxImageExtent.width) {
|
||||||
|
actual_extent.width = capabilities.maxImageExtent.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actual_extent.height < capabilities.minImageExtent.height) {
|
||||||
|
actual_extent.height = capabilities.minImageExtent.height;
|
||||||
|
} else if (actual_extent.height > capabilities.maxImageExtent.height) {
|
||||||
|
actual_extent.height = capabilities.maxImageExtent.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return actual_extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapchainSupportInfo query_swapchain_support(const VkPhysicalDevice dev, const VkSurfaceKHR surface) {
|
||||||
|
SwapchainSupportInfo info;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, surface, &info.capabilities);
|
||||||
|
|
||||||
|
const uint32_t width = info.capabilities.currentExtent.width;
|
||||||
|
const uint32_t height = info.capabilities.currentExtent.height;
|
||||||
|
|
||||||
|
if (
|
||||||
|
info.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR
|
||||||
|
|| info.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR
|
||||||
|
) {
|
||||||
|
info.capabilities.currentExtent.height = width;
|
||||||
|
info.capabilities.currentExtent.width = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface, &info.formats.allocated, NULL);
|
||||||
|
|
||||||
|
if (info.formats.allocated != 0) {
|
||||||
|
info.formats = PTK_LIST_NEW(VkSurfaceFormatKHR, info.formats.allocated);
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface, &info.formats.allocated, info.formats.data);
|
||||||
|
info.formats.size = info.formats.allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface, &info.present_modes.allocated, NULL);
|
||||||
|
|
||||||
|
if (info.present_modes.allocated != 0) {
|
||||||
|
info.present_modes = PTK_LIST_NEW(VkPresentModeKHR, info.present_modes.allocated);
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface, &info.present_modes.allocated, info.present_modes.data);
|
||||||
|
info.present_modes.size = info.present_modes.allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vk_create_image_views(VkDevice dev) {
|
||||||
|
m_swapchain_image_views = PTK_LIST_NEW(VkImageView, m_swapchain_images.size);
|
||||||
|
|
||||||
|
PTK_LIST_FOR_EACH_E(VkImage, m_swapchain_images, i, swapchain_image, {
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateImageView(
|
||||||
|
dev,
|
||||||
|
&(VkImageViewCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.image = swapchain_image,
|
||||||
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||||
|
.format = g_swapchain_image_format,
|
||||||
|
.components = (VkComponentMapping){
|
||||||
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
},
|
||||||
|
.subresourceRange = (VkImageSubresourceRange){
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&m_swapchain_image_views.data[i]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
m_swapchain_image_views.size += 1;
|
||||||
|
})
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vk_create_swapchain(GLFWwindow *window, VkDevice dev, VkPhysicalDevice physical_dev, VkSurfaceKHR surface) {
|
||||||
|
const SwapchainSupportInfo swapchain_support = query_swapchain_support(physical_dev, surface);
|
||||||
|
|
||||||
|
const VkSurfaceFormatKHR surface_format = select_swap_surface_format(swapchain_support.formats);
|
||||||
|
const VkPresentModeKHR present_mode = select_swap_present_mode(swapchain_support.present_modes);
|
||||||
|
const VkExtent2D extent = select_swap_extent(swapchain_support.capabilities, window);
|
||||||
|
|
||||||
|
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
||||||
|
|
||||||
|
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount) {
|
||||||
|
image_count = swapchain_support.capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool queue_families_differ = g_queue_family_indices.graphics.value != g_queue_family_indices.present.value;
|
||||||
|
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateSwapchainKHR(
|
||||||
|
dev,
|
||||||
|
&(VkSwapchainCreateInfoKHR){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.surface = surface,
|
||||||
|
.minImageCount = image_count,
|
||||||
|
.imageFormat = surface_format.format,
|
||||||
|
.imageColorSpace = surface_format.colorSpace,
|
||||||
|
.imageExtent = extent,
|
||||||
|
.imageArrayLayers = 1,
|
||||||
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
|
.imageSharingMode =
|
||||||
|
queue_families_differ
|
||||||
|
? VK_SHARING_MODE_CONCURRENT
|
||||||
|
: VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
.queueFamilyIndexCount =
|
||||||
|
queue_families_differ
|
||||||
|
? 2
|
||||||
|
: 0,
|
||||||
|
.pQueueFamilyIndices =
|
||||||
|
queue_families_differ
|
||||||
|
? (const uint32_t []){
|
||||||
|
g_queue_family_indices.graphics.value,
|
||||||
|
g_queue_family_indices.present.value
|
||||||
|
}
|
||||||
|
: NULL,
|
||||||
|
.preTransform = swapchain_support.capabilities.currentTransform,
|
||||||
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
|
.presentMode = present_mode,
|
||||||
|
.clipped = VK_TRUE,
|
||||||
|
.oldSwapchain = VK_NULL_HANDLE,
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&g_swapchain
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vkGetSwapchainImagesKHR(dev, g_swapchain, &m_swapchain_images.allocated, NULL);
|
||||||
|
m_swapchain_images = PTK_LIST_NEW(VkImage, m_swapchain_images.allocated);
|
||||||
|
vkGetSwapchainImagesKHR(dev, g_swapchain, &m_swapchain_images.allocated, m_swapchain_images.data);
|
||||||
|
PTK_LIST_FILLED(m_swapchain_images);
|
||||||
|
|
||||||
|
g_swapchain_image_format = surface_format.format;
|
||||||
|
g_swapchain_extent = extent;
|
||||||
|
|
||||||
|
PTK_LIST_FREE(swapchain_support.formats);
|
||||||
|
PTK_LIST_FREE(swapchain_support.present_modes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vk_recreate_swapchain(GLFWwindow *window, VkSurfaceKHR surface) {
|
||||||
|
int width = 0, height = 0;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
|
||||||
|
while (width == 0 || height == 0) {
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
glfwWaitEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDeviceWaitIdle(g_dev);
|
||||||
|
|
||||||
|
vk_cleanup_swapchain(g_dev);
|
||||||
|
|
||||||
|
if (!vk_create_swapchain(window, g_dev, g_physical_dev, surface)) {
|
||||||
|
PTK_ERR("failed creating new swapchain");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vk_create_image_views(g_dev)) {
|
||||||
|
PTK_ERR("failed creating new image views");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vk_create_framebuffers()) {
|
||||||
|
PTK_ERR("failed creating new framebuffers");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vk_create_framebuffers(void) {
|
||||||
|
g_swapchain_framebuffers = PTK_LIST_NEW(VkFramebuffer, m_swapchain_image_views.size);
|
||||||
|
|
||||||
|
VkFramebuffer fb;
|
||||||
|
|
||||||
|
PTK_LIST_FOR_EACH(VkImageView, m_swapchain_image_views, swapchain_image_view, {
|
||||||
|
VK_TRY(false,
|
||||||
|
vkCreateFramebuffer(
|
||||||
|
g_dev,
|
||||||
|
&(VkFramebufferCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.renderPass = g_render_pass,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &swapchain_image_view,
|
||||||
|
.width = g_swapchain_extent.width,
|
||||||
|
.height = g_swapchain_extent.height,
|
||||||
|
.layers = 1,
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
&fb
|
||||||
|
)
|
||||||
|
);
|
||||||
|
PTK_LIST_ADD(VkFramebuffer, g_swapchain_framebuffers, fb);
|
||||||
|
})
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vk_cleanup_swapchain(VkDevice dev) {
|
||||||
|
PTK_LIST_FOR_EACH(VkFramebuffer, g_swapchain_framebuffers, fb, {
|
||||||
|
vkDestroyFramebuffer(dev, fb, NULL);
|
||||||
|
})
|
||||||
|
PTK_LIST_FREE(g_swapchain_framebuffers);
|
||||||
|
|
||||||
|
PTK_LIST_FREE(m_swapchain_images);
|
||||||
|
PTK_LIST_FOR_EACH(VkImageView, m_swapchain_image_views, iv, {
|
||||||
|
vkDestroyImageView(dev, iv, NULL);
|
||||||
|
})
|
||||||
|
PTK_LIST_FREE(m_swapchain_image_views);
|
||||||
|
|
||||||
|
vkDestroySwapchainKHR(dev, g_swapchain, NULL);
|
||||||
|
}
|
40
src/ptk_vk/swapchain.h
Normal file
40
src/ptk_vk/swapchain.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||||
|
|
||||||
|
#ifndef PTK_PTK_VK_SWAPCHAIN_H_
|
||||||
|
#define PTK_PTK_VK_SWAPCHAIN_H_
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <ptk_list.h>
|
||||||
|
#include <ptk_option.h>
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkFramebuffer);
|
||||||
|
|
||||||
|
extern VkSwapchainKHR g_swapchain;
|
||||||
|
extern VkFormat g_swapchain_image_format;
|
||||||
|
extern VkExtent2D g_swapchain_extent;
|
||||||
|
extern PTK_LIST(VkFramebuffer) g_swapchain_framebuffers;
|
||||||
|
|
||||||
|
PTK_LIST_DEFINE(VkSurfaceFormatKHR);
|
||||||
|
PTK_LIST_DEFINE(VkPresentModeKHR);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
PTK_LIST(VkSurfaceFormatKHR) formats;
|
||||||
|
PTK_LIST(VkPresentModeKHR) present_modes;
|
||||||
|
} SwapchainSupportInfo;
|
||||||
|
|
||||||
|
SwapchainSupportInfo query_swapchain_support(const VkPhysicalDevice dev, const VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
bool vk_create_swapchain(GLFWwindow *window, VkDevice dev, VkPhysicalDevice physical_dev, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
bool vk_create_image_views(VkDevice dev);
|
||||||
|
|
||||||
|
bool vk_recreate_swapchain(GLFWwindow *window, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
bool vk_create_framebuffers(void);
|
||||||
|
|
||||||
|
void vk_cleanup_swapchain(VkDevice dev);
|
||||||
|
|
||||||
|
#endif // PTK_PTK_VK_SWAPCHAIN_H_
|
Loading…
Reference in a new issue