huge refactor merge
builds and partly works but spams a fuckton of errors because the descriptor set layout is set up to expect an image sampler with an image view BUT the descriptors are already created before doing anything with images both the amogus and button examples work but they spam errors the image example crashes because of some sampler fuckery that I think I got a hang of back when I started doing this but right now I don't remember, I'm hoping to move this forward this weekend
This commit is contained in:
parent
94aed050bd
commit
4dd6d1a518
45 changed files with 2264 additions and 1915 deletions
2
Makefile
2
Makefile
|
@ -25,7 +25,7 @@ CFLAGS += -DPTK_VERSION_PATCH=0
|
|||
|
||||
INCLUDE = include
|
||||
SRC = src
|
||||
CFLAGS += -I$(INCLUDE) -I$(SRC)
|
||||
CFLAGS += -I$(INCLUDE) -iquote$(SRC)
|
||||
|
||||
BIN = target
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ in stdenv.mkDerivation {
|
|||
'';
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://git.jacekpoz.pl/jacekpoz/${pname}";
|
||||
homepage = "https://git.jacekpoz.pl/poz/${pname}";
|
||||
description = "poz toolkit";
|
||||
license = licenses.eupl12;
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef PTK_PTK_H_
|
||||
#define PTK_PTK_H_
|
||||
|
||||
#include <ptk_color.h>
|
||||
#include <ptk_list.h>
|
||||
#include <ptk_vec.h>
|
||||
#include "ptk_color.h"
|
||||
#include "ptk_list.h"
|
||||
#include "ptk_vec.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
57
src/ptk.c
57
src/ptk.c
|
@ -1,14 +1,11 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk.h>
|
||||
#include <ptk_log.h>
|
||||
#include <ptk_list.h>
|
||||
#include <ptk_option.h>
|
||||
#include "ptk.h"
|
||||
#include "ptk_log.h"
|
||||
#include "ptk_option.h"
|
||||
|
||||
#include <ptk_vk/components.h>
|
||||
#include <ptk_vk/draw.h>
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/utils.h>
|
||||
#include "ptk_vk/backend.h"
|
||||
#include "ptk_vk/components.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
|
@ -21,29 +18,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static GLFWwindow *m_window = NULL;
|
||||
|
||||
static void framebuffer_resize_callback(GLFWwindow *window, int width, int height) {
|
||||
(void)window; (void)width; (void)height;
|
||||
g_framebuffer_resized = true;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||
(void)window; (void)scancode; (void)action; (void)mods;
|
||||
if (key == GLFW_KEY_SPACE) {
|
||||
PTK_LIST_FOR_EACH_P(Vertex, g_vertices, vertex, {
|
||||
vertex->pos.x += 1.0f;
|
||||
});
|
||||
vk_transfer_vertex_data();
|
||||
}
|
||||
}
|
||||
|
||||
static void mouse_button_callback(GLFWwindow *window, int button, int action, int mods) {
|
||||
double x, y;
|
||||
glfwGetCursorPos(window, &x, &y);
|
||||
vk_handle_mouse_button_input((PtkPos){ .x = x, .y = y }, button, action, mods);
|
||||
}
|
||||
|
||||
PTK_OPTION_DEFINE(PtkLogLevel);
|
||||
|
||||
PTK_OPTION(PtkLogLevel) get_log_level(void) {
|
||||
|
@ -111,19 +85,13 @@ bool ptk_init(const size_t width, const size_t height, const char *title, const
|
|||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
m_window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
GLFWwindow *window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
|
||||
if (m_window == NULL) {
|
||||
if (window == NULL) {
|
||||
PTK_ERR("failed creating GLFW window");
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetFramebufferSizeCallback(m_window, framebuffer_resize_callback);
|
||||
glfwSetKeyCallback(m_window, key_callback);
|
||||
glfwSetMouseButtonCallback(m_window, mouse_button_callback);
|
||||
|
||||
vk_init_vertices();
|
||||
|
||||
// on tiling desktops (most standalone X11 WMs / Wayland compositors)
|
||||
// the size of the window won't necessarily be what the user set due to tiling
|
||||
// so we do this ugly workaround where we fetch the size again
|
||||
|
@ -132,9 +100,9 @@ bool ptk_init(const size_t width, const size_t height, const char *title, const
|
|||
// this fixes an issue where components would get drawn squished
|
||||
// and their hitboxes wouldn't match up with them visually
|
||||
int actual_width = 0, actual_height = 0;
|
||||
glfwGetFramebufferSize(m_window, &actual_width, &actual_height);
|
||||
glfwGetFramebufferSize(window, &actual_width, &actual_height);
|
||||
|
||||
if (!vk_init(m_window, actual_width, actual_height, title, application_version)) {
|
||||
if (!vk_init(window, actual_width, actual_height, title, application_version)) {
|
||||
PTK_ERR("failed initializing vulkan");
|
||||
return false;
|
||||
}
|
||||
|
@ -198,17 +166,14 @@ PtkHandle ptk_image(const char *path, const PtkPos top_left, const PtkSize size)
|
|||
int ptk_run(PtkHandle root) {
|
||||
vk_init_components(root);
|
||||
|
||||
while (!glfwWindowShouldClose(m_window)) {
|
||||
while (!vk_is_done()) {
|
||||
glfwPollEvents();
|
||||
if (!vk_draw_frame()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(g_dev);
|
||||
|
||||
vk_cleanup();
|
||||
vk_components_cleanup();
|
||||
vk_finish();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <ptk_color.h>
|
||||
#include "ptk_color.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk_list.h>
|
||||
#include "ptk_list.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#define PTK_PTK_LIST_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PTK_LIST(T) struct PtkList_##T
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk_log.h>
|
||||
#include "ptk_log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
346
src/ptk_vk/backend.c
Normal file
346
src/ptk_vk/backend.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/backend.h"
|
||||
|
||||
#include "ptk_vk/buffer.h"
|
||||
#include "ptk_vk/command_buffers.h"
|
||||
#include "ptk_vk/command_pool.h"
|
||||
#include "ptk_vk/components.h"
|
||||
#include "ptk_vk/descriptors.h"
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/init.h"
|
||||
#include "ptk_vk/instance.h"
|
||||
#include "ptk_vk/physical_device.h"
|
||||
|
||||
#include "ptk_log.h"
|
||||
#include "ptk_vk/pipeline.h"
|
||||
#include "ptk_vk/render_pass.h"
|
||||
#include "ptk_vk/swapchain.h"
|
||||
#include "ptk_vk/sync_objects.h"
|
||||
#include "ptk_vk/uniform_buffers.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool g_framebuffer_resized = false;
|
||||
|
||||
GLFWwindow *g_window;
|
||||
VkSurfaceKHR g_surface;
|
||||
|
||||
VkBuffer g_vertex_buffer;
|
||||
VkDeviceMemory g_vertex_buffer_memory;
|
||||
VkBuffer g_index_buffer;
|
||||
VkDeviceMemory g_index_buffer_memory;
|
||||
|
||||
#ifdef DEBUG
|
||||
const PTK_ARRAY(constcharptr) g_validation_layers = PTK_ARRAY_NEW(constcharptr, {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
});
|
||||
#else
|
||||
const PTK_ARRAY(constcharptr) g_validation_layers = PTK_ARRAY_EMPTY(constcharptr);
|
||||
#endif
|
||||
|
||||
static uint32_t m_current_frame = 0;
|
||||
|
||||
static void mouse_button_callback(GLFWwindow *window, int button, int action, int mods) {
|
||||
double x, y;
|
||||
glfwGetCursorPos(window, &x, &y);
|
||||
vk_handle_mouse_button_input((PtkPos){ .x = x, .y = y }, button, action, mods);
|
||||
}
|
||||
|
||||
static void framebuffer_resized(GLFWwindow *window, int width, int height) {
|
||||
(void)window; (void)width; (void)height;
|
||||
g_framebuffer_resized = true;
|
||||
}
|
||||
|
||||
bool record_command_buffer(const VkCommandBuffer command_buffer, const uint32_t image_index) {
|
||||
VK_TRY(false,
|
||||
vkBeginCommandBuffer(
|
||||
command_buffer,
|
||||
&(VkCommandBufferBeginInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.pInheritanceInfo = NULL,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
vkCmdBeginRenderPass(
|
||||
command_buffer,
|
||||
&(VkRenderPassBeginInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.pNext = NULL,
|
||||
.renderPass = g_render_pass,
|
||||
.framebuffer = g_swapchain_framebuffers.data[image_index],
|
||||
.renderArea = (VkRect2D){
|
||||
.offset = (VkOffset2D){
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
},
|
||||
.extent = g_swapchain_extent,
|
||||
},
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = &(VkClearValue){
|
||||
.color = (VkClearColorValue){
|
||||
.float32[0] = 0.0f,
|
||||
.float32[1] = 0.0f,
|
||||
.float32[2] = 0.0f,
|
||||
.float32[3] = 1.0f,
|
||||
},
|
||||
},
|
||||
},
|
||||
VK_SUBPASS_CONTENTS_INLINE
|
||||
);
|
||||
|
||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline);
|
||||
|
||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, (VkBuffer []){g_vertex_buffer}, (VkDeviceSize []){0});
|
||||
|
||||
vkCmdBindIndexBuffer(command_buffer, g_index_buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1, &g_descriptor_sets.data[m_current_frame], 0, NULL);
|
||||
|
||||
vkCmdDrawIndexed(command_buffer, g_indices.size, 1, 0, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
|
||||
VK_TRY(false,
|
||||
vkEndCommandBuffer(command_buffer)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const char *title, const PtkVersion version) {
|
||||
g_window = window;
|
||||
g_uniform_buffer_object.initial_window_size.w = width;
|
||||
g_uniform_buffer_object.initial_window_size.h = height;
|
||||
|
||||
vk_init_vertices();
|
||||
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_resized);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
|
||||
if (!vk_instance_create(title, version)) {
|
||||
PTK_ERR("failed creating VkInstance");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_select_physical_dev()) {
|
||||
PTK_ERR("failed selecting physical device");
|
||||
return false;
|
||||
}
|
||||
|
||||
VK_TRY(false, glfwCreateWindowSurface(g_instance, g_window, NULL, &g_surface));
|
||||
|
||||
if (!vk_create_logical_dev()) {
|
||||
PTK_ERR("failed creating logical device");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_swapchain()) {
|
||||
PTK_ERR("failed creating swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_image_views()) {
|
||||
PTK_ERR("failed creating image views");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_render_pass()) {
|
||||
PTK_ERR("failed creating render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_descriptor_set_layout()) {
|
||||
PTK_ERR("failed creating descriptor set layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_pipeline()) {
|
||||
PTK_ERR("failed creating graphics pipeline");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_framebuffers()) {
|
||||
PTK_ERR("failed creating framebuffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_command_pool()) {
|
||||
PTK_ERR("failed creating command pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkDeviceSize buffer_size = 65536;
|
||||
|
||||
PTK_OPTION(BufferStuff) vertex_buffer_stuff_opt = vk_create_buffer(
|
||||
g_dev,
|
||||
g_physical_dev,
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
);
|
||||
|
||||
if (!vertex_buffer_stuff_opt.exists) {
|
||||
PTK_ERR("failed creating vertex buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_vertex_buffer = vertex_buffer_stuff_opt.value.buffer;
|
||||
g_vertex_buffer_memory = vertex_buffer_stuff_opt.value.buffer_memory;
|
||||
|
||||
PTK_OPTION(BufferStuff) index_buffer_stuff_opt = vk_create_buffer(
|
||||
g_dev,
|
||||
g_physical_dev,
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
);
|
||||
|
||||
if (!index_buffer_stuff_opt.exists) {
|
||||
PTK_ERR("failed creating index buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_index_buffer = index_buffer_stuff_opt.value.buffer;
|
||||
g_index_buffer_memory = index_buffer_stuff_opt.value.buffer_memory;
|
||||
|
||||
if (!vk_create_uniform_buffers()) {
|
||||
PTK_ERR("failed creating uniform buffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_descriptor_pool()) {
|
||||
PTK_ERR("failed creating descriptor pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_descriptor_sets()) {
|
||||
PTK_ERR("failed creating descriptor sets");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_allocate_command_buffers()) {
|
||||
PTK_ERR("failed allocating command buffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_sync_objects()) {
|
||||
PTK_ERR("failed creating sync objects");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vk_is_done(void) {
|
||||
return glfwWindowShouldClose(g_window);
|
||||
}
|
||||
|
||||
bool update_uniform_buffer(const size_t current_frame) {
|
||||
g_uniform_buffer_object.window_size.w = g_swapchain_extent.width;
|
||||
g_uniform_buffer_object.window_size.h = g_swapchain_extent.height;
|
||||
|
||||
memcpy(g_uniform_buffers_mapped.data[current_frame], &g_uniform_buffer_object, sizeof(g_uniform_buffer_object));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vk_draw_frame(void) {
|
||||
vkWaitForFences(g_dev, 1, &g_in_flight_fences.data[m_current_frame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t image_index;
|
||||
const VkResult acquire_next_image_result = vkAcquireNextImageKHR(
|
||||
g_dev,
|
||||
g_swapchain,
|
||||
UINT64_MAX,
|
||||
g_image_available_semaphores.data[m_current_frame],
|
||||
VK_NULL_HANDLE,
|
||||
&image_index
|
||||
);
|
||||
|
||||
if (acquire_next_image_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (acquire_next_image_result != VK_SUCCESS && acquire_next_image_result != VK_SUBOPTIMAL_KHR) {
|
||||
PTK_ERR("%s", vk_result_string(acquire_next_image_result));
|
||||
return false;
|
||||
}
|
||||
|
||||
update_uniform_buffer(m_current_frame);
|
||||
|
||||
vkResetFences(g_dev, 1, &g_in_flight_fences.data[m_current_frame]);
|
||||
|
||||
vkResetCommandBuffer(g_command_buffers.data[m_current_frame], 0);
|
||||
if (!record_command_buffer(g_command_buffers.data[m_current_frame], image_index)) {
|
||||
PTK_ERR("failed recording command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkSemaphore signal_semaphores[] = {g_render_finished_semaphores.data[m_current_frame]};
|
||||
|
||||
VK_TRY(false,
|
||||
vkQueueSubmit(
|
||||
g_graphics_queue,
|
||||
1,
|
||||
&(VkSubmitInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &g_image_available_semaphores.data[m_current_frame],
|
||||
.pWaitDstStageMask = &(VkPipelineStageFlags){VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &g_command_buffers.data[m_current_frame],
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = signal_semaphores,
|
||||
},
|
||||
g_in_flight_fences.data[m_current_frame]
|
||||
)
|
||||
);
|
||||
|
||||
const VkResult queue_present_result = vkQueuePresentKHR(
|
||||
g_present_queue,
|
||||
&(VkPresentInfoKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = signal_semaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &(VkSwapchainKHR){g_swapchain},
|
||||
.pImageIndices = &image_index,
|
||||
.pResults = NULL,
|
||||
}
|
||||
);
|
||||
|
||||
if (
|
||||
queue_present_result == VK_ERROR_OUT_OF_DATE_KHR ||
|
||||
queue_present_result == VK_SUBOPTIMAL_KHR ||
|
||||
g_framebuffer_resized
|
||||
) {
|
||||
g_framebuffer_resized = false;
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
PTK_TRACE("recreated swapchain");
|
||||
} else if (queue_present_result != VK_SUCCESS) {
|
||||
PTK_ERR("%s", vk_result_string(queue_present_result));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_current_frame = (m_current_frame + 1) % g_max_frames_in_flight;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void vk_finish(void) {
|
||||
vkDeviceWaitIdle(g_dev);
|
||||
|
||||
vk_cleanup();
|
||||
vk_components_cleanup();
|
||||
}
|
39
src/ptk_vk/backend.h
Normal file
39
src/ptk_vk/backend.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_BACKEND_H_
|
||||
#define PTK_PTK_VK_BACKEND_H_
|
||||
|
||||
#include "ptk.h"
|
||||
#include "ptk_array.h"
|
||||
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool g_framebuffer_resized;
|
||||
|
||||
extern GLFWwindow *g_window;
|
||||
extern VkSurfaceKHR g_surface;
|
||||
|
||||
extern VkBuffer g_vertex_buffer;
|
||||
extern VkDeviceMemory g_vertex_buffer_memory;
|
||||
extern VkBuffer g_index_buffer;
|
||||
extern VkDeviceMemory g_index_buffer_memory;
|
||||
|
||||
typedef const char *constcharptr;
|
||||
PTK_ARRAY_DEFINE(constcharptr);
|
||||
|
||||
extern const PTK_ARRAY(constcharptr) g_validation_layers;
|
||||
|
||||
bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const char *title, const PtkVersion version);
|
||||
|
||||
bool vk_is_done(void);
|
||||
|
||||
bool vk_draw_frame(void);
|
||||
|
||||
void vk_finish(void);
|
||||
|
||||
#endif // PTK_PTK_VK_BACKEND_H_
|
130
src/ptk_vk/buffer.c
Normal file
130
src/ptk_vk/buffer.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/buffer.h"
|
||||
|
||||
#include "ptk_vk/command_pool.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
PTK_OPTION(uint32_t) vk_find_memory_type(VkPhysicalDevice physical_dev, const uint32_t type_filter, const VkMemoryPropertyFlags props) {
|
||||
VkPhysicalDeviceMemoryProperties mem_props;
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_dev, &mem_props);
|
||||
|
||||
for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
|
||||
if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
|
||||
return PTK_OPTION_SOME(uint32_t, i);
|
||||
}
|
||||
}
|
||||
|
||||
return PTK_OPTION_NONE(uint32_t);
|
||||
}
|
||||
|
||||
PTK_OPTION(BufferStuff) vk_create_buffer(VkDevice dev, VkPhysicalDevice physical_dev, const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props) {
|
||||
BufferStuff ret;
|
||||
|
||||
VK_TRY(PTK_OPTION_NONE(BufferStuff),
|
||||
vkCreateBuffer(
|
||||
dev,
|
||||
&(VkBufferCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.size = size,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
},
|
||||
NULL,
|
||||
&ret.buffer
|
||||
)
|
||||
);
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetBufferMemoryRequirements(dev, ret.buffer, &mem_reqs);
|
||||
|
||||
const PTK_OPTION(uint32_t) memory_type = vk_find_memory_type(physical_dev, mem_reqs.memoryTypeBits, props);
|
||||
|
||||
if (!memory_type.exists) {
|
||||
PTK_ERR("failed to find suitable memory type");
|
||||
return PTK_OPTION_NONE(BufferStuff);
|
||||
}
|
||||
|
||||
VK_TRY(PTK_OPTION_NONE(BufferStuff),
|
||||
vkAllocateMemory(
|
||||
dev,
|
||||
&(VkMemoryAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = NULL,
|
||||
.allocationSize = mem_reqs.size,
|
||||
.memoryTypeIndex = memory_type.value,
|
||||
},
|
||||
NULL,
|
||||
&ret.buffer_memory
|
||||
)
|
||||
);
|
||||
|
||||
vkBindBufferMemory(dev, ret.buffer, ret.buffer_memory, 0);
|
||||
|
||||
return PTK_OPTION_SOME(BufferStuff, ret);
|
||||
}
|
||||
|
||||
bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size) {
|
||||
PTK_OPTION(VkCommandBuffer) command_buffer_opt = vk_begin_single_time_commands();
|
||||
|
||||
if (!command_buffer_opt.exists) {
|
||||
PTK_ERR("failed to create command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer command_buffer = command_buffer_opt.value;
|
||||
|
||||
vkCmdCopyBuffer(command_buffer, src, dst, 1, &(VkBufferCopy){
|
||||
.srcOffset = 0,
|
||||
.dstOffset = 0,
|
||||
.size = size,
|
||||
});
|
||||
|
||||
if (!vk_end_single_time_commands(command_buffer)) {
|
||||
PTK_ERR("failed to end command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool transfer_to_buffer(VkDevice dev, VkPhysicalDevice physical_dev, void *src, size_t src_size, VkBuffer buffer) {
|
||||
const VkDeviceSize buffer_size = src_size;
|
||||
|
||||
PTK_OPTION(BufferStuff) staging_buffer_stuff_opt = vk_create_buffer(
|
||||
dev,
|
||||
physical_dev,
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
);
|
||||
|
||||
if (!staging_buffer_stuff_opt.exists) {
|
||||
PTK_ERR("failed creating staging vertex buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkBuffer staging_buffer = staging_buffer_stuff_opt.value.buffer;
|
||||
VkDeviceMemory staging_buffer_memory = staging_buffer_stuff_opt.value.buffer_memory;
|
||||
|
||||
void *data;
|
||||
vkMapMemory(dev, staging_buffer_memory, 0, buffer_size, 0, &data);
|
||||
memcpy(data, src, (size_t)buffer_size);
|
||||
vkUnmapMemory(dev, staging_buffer_memory);
|
||||
|
||||
if (!copy_buffer(staging_buffer, buffer, buffer_size)) {
|
||||
PTK_ERR("failed copying staging buffer to vertex buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
vkDestroyBuffer(dev, staging_buffer, NULL);
|
||||
vkFreeMemory(dev, staging_buffer_memory, NULL);
|
||||
|
||||
return true;
|
||||
}
|
24
src/ptk_vk/buffer.h
Normal file
24
src/ptk_vk/buffer.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_BUFFER_H_
|
||||
#define PTK_PTK_VK_BUFFER_H_
|
||||
|
||||
#include "ptk_option.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
typedef struct {
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory buffer_memory;
|
||||
} BufferStuff;
|
||||
|
||||
PTK_OPTION_DEFINE(BufferStuff);
|
||||
PTK_OPTION_DEFINE(uint32_t);
|
||||
|
||||
PTK_OPTION(uint32_t) vk_find_memory_type(VkPhysicalDevice physical_dev, const uint32_t type_filter, const VkMemoryPropertyFlags props);
|
||||
|
||||
PTK_OPTION(BufferStuff) vk_create_buffer(VkDevice dev, VkPhysicalDevice physical_dev, const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props);
|
||||
|
||||
bool transfer_to_buffer(VkDevice dev, VkPhysicalDevice physical_dev, void *src, size_t src_size, VkBuffer buffer);
|
||||
|
||||
#endif // PTK_PTK_VK_BUFFER_H_
|
31
src/ptk_vk/command_buffers.c
Normal file
31
src/ptk_vk/command_buffers.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/command_buffers.h"
|
||||
|
||||
#include "ptk_vk/command_pool.h"
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/sync_objects.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
PTK_LIST(VkCommandBuffer) g_command_buffers;
|
||||
|
||||
bool vk_allocate_command_buffers(void) {
|
||||
g_command_buffers = PTK_LIST_NEW(VkCommandBuffer, g_max_frames_in_flight);
|
||||
|
||||
VK_TRY(false,
|
||||
vkAllocateCommandBuffers(
|
||||
g_dev,
|
||||
&(VkCommandBufferAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = NULL,
|
||||
.commandPool = g_command_pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = g_command_buffers.allocated,
|
||||
},
|
||||
g_command_buffers.data
|
||||
)
|
||||
);
|
||||
PTK_LIST_FILLED(g_command_buffers);
|
||||
|
||||
return true;
|
||||
}
|
18
src/ptk_vk/command_buffers.h
Normal file
18
src/ptk_vk/command_buffers.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_COMMAND_BUFFERS_H_
|
||||
#define PTK_PTK_VK_COMMAND_BUFFERS_H_
|
||||
|
||||
#include "ptk_list.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
PTK_LIST_DEFINE(VkCommandBuffer);
|
||||
|
||||
extern PTK_LIST(VkCommandBuffer) g_command_buffers;
|
||||
|
||||
bool vk_allocate_command_buffers(void);
|
||||
|
||||
#endif // PTK_PTK_VK_COMMAND_BUFFERS_H_
|
87
src/ptk_vk/command_pool.c
Normal file
87
src/ptk_vk/command_pool.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/command_pool.h"
|
||||
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void) {
|
||||
VkCommandBuffer command_buffer;
|
||||
|
||||
VK_TRY(PTK_OPTION_NONE(VkCommandBuffer),
|
||||
vkAllocateCommandBuffers(
|
||||
g_dev,
|
||||
&(VkCommandBufferAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = NULL,
|
||||
.commandPool = g_command_pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
},
|
||||
&command_buffer
|
||||
)
|
||||
);
|
||||
|
||||
VK_TRY(PTK_OPTION_NONE(VkCommandBuffer),
|
||||
vkBeginCommandBuffer(
|
||||
command_buffer,
|
||||
&(VkCommandBufferBeginInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
.pInheritanceInfo = NULL,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return PTK_OPTION_SOME(VkCommandBuffer, command_buffer);
|
||||
}
|
||||
|
||||
bool vk_end_single_time_commands(VkCommandBuffer command_buffer) {
|
||||
VK_TRY(false, vkEndCommandBuffer(command_buffer));
|
||||
|
||||
VK_TRY(false,
|
||||
vkQueueSubmit(
|
||||
g_graphics_queue,
|
||||
1,
|
||||
&(VkSubmitInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = NULL,
|
||||
.pWaitDstStageMask = NULL,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer,
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = NULL,
|
||||
},
|
||||
VK_NULL_HANDLE
|
||||
);
|
||||
);
|
||||
|
||||
VK_TRY(false, vkQueueWaitIdle(g_graphics_queue));
|
||||
|
||||
vkFreeCommandBuffers(g_dev, g_command_pool, 1, &command_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VkCommandPool g_command_pool;
|
||||
|
||||
bool vk_create_command_pool(void) {
|
||||
VK_TRY(false,
|
||||
vkCreateCommandPool(
|
||||
g_dev,
|
||||
&(VkCommandPoolCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = g_queue_family_indices.graphics.value,
|
||||
},
|
||||
NULL,
|
||||
&g_command_pool
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
22
src/ptk_vk/command_pool.h
Normal file
22
src/ptk_vk/command_pool.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_COMMAND_POOL_H_
|
||||
#define PTK_PTK_VK_COMMAND_POOL_H_
|
||||
|
||||
#include "ptk_option.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
PTK_OPTION_DEFINE(VkCommandBuffer);
|
||||
|
||||
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void);
|
||||
|
||||
bool vk_end_single_time_commands(VkCommandBuffer command_buffer);
|
||||
|
||||
extern VkCommandPool g_command_pool;
|
||||
|
||||
bool vk_create_command_pool(void);
|
||||
|
||||
#endif // PTK_PTK_VK_COMMAND_POOL_H_
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk.h>
|
||||
#include <ptk_log.h>
|
||||
#include <ptk_vk/components.h>
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/image.h>
|
||||
#include "ptk_vk/components.h"
|
||||
#include "ptk_vk/init.h"
|
||||
#include "ptk_vk/image.h"
|
||||
|
||||
#include "ptk.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#ifndef PTK_PTK_VK_COMPONENTS_H_
|
||||
#define PTK_PTK_VK_COMPONENTS_H_
|
||||
|
||||
#include <ptk.h>
|
||||
#include <ptk_list.h>
|
||||
#include "ptk.h"
|
||||
#include "ptk_list.h"
|
||||
|
||||
typedef struct {
|
||||
PtkPos pos;
|
||||
|
|
163
src/ptk_vk/descriptors.c
Normal file
163
src/ptk_vk/descriptors.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/descriptors.h"
|
||||
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/image.h"
|
||||
#include "ptk_vk/sync_objects.h"
|
||||
#include "ptk_vk/uniform_buffers.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include "ptk_array.h"
|
||||
|
||||
VkDescriptorSetLayout g_descriptor_set_layout;
|
||||
VkDescriptorPool g_descriptor_pool;
|
||||
PTK_LIST(VkDescriptorSet) g_descriptor_sets;
|
||||
|
||||
bool vk_create_descriptor_set_layout(void) {
|
||||
VK_TRY(false,
|
||||
vkCreateDescriptorSetLayout(
|
||||
g_dev,
|
||||
&(VkDescriptorSetLayoutCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.bindingCount = 2,
|
||||
.pBindings = (VkDescriptorSetLayoutBinding []){
|
||||
(VkDescriptorSetLayoutBinding){
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.pImmutableSamplers = NULL,
|
||||
},
|
||||
(VkDescriptorSetLayoutBinding){
|
||||
.binding = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.pImmutableSamplers = NULL,
|
||||
},
|
||||
},
|
||||
},
|
||||
NULL,
|
||||
&g_descriptor_set_layout
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vk_create_descriptor_pool(void) {
|
||||
VK_TRY(false,
|
||||
vkCreateDescriptorPool(
|
||||
g_dev,
|
||||
&(VkDescriptorPoolCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.maxSets = g_max_frames_in_flight,
|
||||
.poolSizeCount = 2,
|
||||
.pPoolSizes = (VkDescriptorPoolSize []){
|
||||
(VkDescriptorPoolSize){
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = g_max_frames_in_flight,
|
||||
},
|
||||
(VkDescriptorPoolSize){
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = g_max_frames_in_flight,
|
||||
},
|
||||
},
|
||||
},
|
||||
NULL,
|
||||
&g_descriptor_pool
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PTK_LIST_DEFINE(VkDescriptorSetLayout);
|
||||
|
||||
bool vk_create_descriptor_sets(void) {
|
||||
PTK_LIST(VkDescriptorSetLayout) layouts = PTK_LIST_NEW(VkDescriptorSetLayout, g_max_frames_in_flight);
|
||||
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
||||
PTK_LIST_ADD(VkDescriptorSetLayout, layouts, g_descriptor_set_layout);
|
||||
}
|
||||
|
||||
g_descriptor_sets = PTK_LIST_NEW(VkDescriptorSet, g_max_frames_in_flight);
|
||||
|
||||
VK_TRY(false,
|
||||
vkAllocateDescriptorSets(
|
||||
g_dev,
|
||||
&(VkDescriptorSetAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.pNext = NULL,
|
||||
.descriptorPool = g_descriptor_pool,
|
||||
.descriptorSetCount = layouts.size,
|
||||
.pSetLayouts = layouts.data,
|
||||
},
|
||||
g_descriptor_sets.data
|
||||
)
|
||||
);
|
||||
|
||||
vk_update_descriptor_sets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PTK_ARRAY_DEFINE(VkWriteDescriptorSet);
|
||||
|
||||
void vk_update_descriptor_sets(void) {
|
||||
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
||||
VkWriteDescriptorSet uniform_buffer_descriptor_set = (VkWriteDescriptorSet){
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.pNext = NULL,
|
||||
.dstSet = g_descriptor_sets.data[i],
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.pImageInfo = NULL,
|
||||
.pBufferInfo = &(VkDescriptorBufferInfo){
|
||||
.buffer = g_uniform_buffers.data[i],
|
||||
.offset = 0,
|
||||
.range = sizeof(UniformBufferObject),
|
||||
},
|
||||
.pTexelBufferView = NULL,
|
||||
};
|
||||
|
||||
PTK_ARRAY(VkWriteDescriptorSet) descriptor_writes;
|
||||
if (g_image_view == VK_NULL_HANDLE) {
|
||||
descriptor_writes = PTK_ARRAY_NEW(VkWriteDescriptorSet, {uniform_buffer_descriptor_set});
|
||||
} else {
|
||||
descriptor_writes = PTK_ARRAY_NEW(VkWriteDescriptorSet, {
|
||||
uniform_buffer_descriptor_set,
|
||||
(VkWriteDescriptorSet){
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.pNext = NULL,
|
||||
.dstSet = g_descriptor_sets.data[i],
|
||||
.dstBinding = 1,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = g_sampler,
|
||||
.imageView = g_image_view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
},
|
||||
.pBufferInfo = NULL,
|
||||
.pTexelBufferView = NULL,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
vkUpdateDescriptorSets(
|
||||
g_dev,
|
||||
descriptor_writes.size,
|
||||
descriptor_writes.data,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
}
|
22
src/ptk_vk/descriptors.h
Normal file
22
src/ptk_vk/descriptors.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_DESCRIPTORS_H_
|
||||
#define PTK_PTK_VK_DESCRIPTORS_H_
|
||||
|
||||
#include "ptk_list.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
PTK_LIST_DEFINE(VkDescriptorSet);
|
||||
|
||||
extern VkDescriptorSetLayout g_descriptor_set_layout;
|
||||
extern VkDescriptorPool g_descriptor_pool;
|
||||
extern PTK_LIST(VkDescriptorSet) g_descriptor_sets;
|
||||
|
||||
bool vk_create_descriptor_set_layout(void);
|
||||
bool vk_create_descriptor_pool(void);
|
||||
bool vk_create_descriptor_sets(void);
|
||||
|
||||
void vk_update_descriptor_sets(void);
|
||||
|
||||
#endif // PTK_PTK_VK_DESCRIPTORS_H_
|
140
src/ptk_vk/device.c
Normal file
140
src/ptk_vk/device.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/device.h"
|
||||
|
||||
#include "ptk_vk/backend.h"
|
||||
#include "ptk_vk/physical_device.h"
|
||||
#include "ptk_vk/swapchain.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include "ptk_array.h"
|
||||
#include "ptk_list.h"
|
||||
#include "ptk_log.h"
|
||||
#include "ptk_option.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
VkDevice g_dev;
|
||||
QueueFamilyIndices g_queue_family_indices;
|
||||
VkQueue g_graphics_queue;
|
||||
VkQueue g_present_queue;
|
||||
|
||||
static const size_t m_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(void) {
|
||||
if (!is_device_suitable(g_physical_dev, g_surface)) {
|
||||
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) *)&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(
|
||||
g_physical_dev,
|
||||
&(VkDeviceCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = m_queue_family_count,
|
||||
.pQueueCreateInfos = queue_create_infos,
|
||||
.enabledLayerCount = g_validation_layers.size,
|
||||
.ppEnabledLayerNames = g_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;
|
||||
}
|
25
src/ptk_vk/device.h
Normal file
25
src/ptk_vk/device.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_DEVICE_H_
|
||||
#define PTK_PTK_VK_DEVICE_H_
|
||||
|
||||
// PTK_OPTION(uint32_t)
|
||||
#include "ptk_vk/buffer.h"
|
||||
|
||||
#include "ptk_option.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
typedef struct {
|
||||
PTK_OPTION(uint32_t) graphics;
|
||||
PTK_OPTION(uint32_t) present;
|
||||
} QueueFamilyIndices;
|
||||
|
||||
extern VkDevice g_dev;
|
||||
extern QueueFamilyIndices g_queue_family_indices;
|
||||
extern VkQueue g_graphics_queue;
|
||||
extern VkQueue g_present_queue;
|
||||
|
||||
bool vk_create_logical_dev(void);
|
||||
|
||||
#endif // PTK_PTK_VK_DEVICE_H_
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk_vk/draw.h>
|
||||
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/utils.h>
|
||||
|
||||
#include <ptk_log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
bool g_framebuffer_resized = false;
|
||||
uint32_t g_current_frame = 0;
|
||||
|
||||
bool vk_draw_frame(void) {
|
||||
vkWaitForFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t image_index;
|
||||
const VkResult acquire_next_image_result = vkAcquireNextImageKHR(
|
||||
g_dev,
|
||||
g_swapchain,
|
||||
UINT64_MAX,
|
||||
g_image_available_semaphores.data[g_current_frame],
|
||||
VK_NULL_HANDLE,
|
||||
&image_index
|
||||
);
|
||||
|
||||
if (acquire_next_image_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (acquire_next_image_result != VK_SUCCESS && acquire_next_image_result != VK_SUBOPTIMAL_KHR) {
|
||||
PTK_ERR("%s", vk_result_string(acquire_next_image_result));
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_update_uniform_buffer(g_current_frame);
|
||||
|
||||
vkResetFences(g_dev, 1, &g_in_flight_fences.data[g_current_frame]);
|
||||
|
||||
vkResetCommandBuffer(g_command_buffers.data[g_current_frame], 0);
|
||||
if (!vk_record_command_buffer(g_command_buffers.data[g_current_frame], image_index)) {
|
||||
PTK_ERR("failed recording command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkSemaphore signal_semaphores[] = {g_render_finished_semaphores.data[g_current_frame]};
|
||||
|
||||
VK_TRY(false,
|
||||
vkQueueSubmit(
|
||||
g_graphics_queue,
|
||||
1,
|
||||
&(VkSubmitInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &g_image_available_semaphores.data[g_current_frame],
|
||||
.pWaitDstStageMask = &(VkPipelineStageFlags){VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &g_command_buffers.data[g_current_frame],
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = signal_semaphores,
|
||||
},
|
||||
g_in_flight_fences.data[g_current_frame]
|
||||
)
|
||||
);
|
||||
|
||||
const VkResult queue_present_result = vkQueuePresentKHR(g_present_queue, &(VkPresentInfoKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = signal_semaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &g_swapchain,
|
||||
.pImageIndices = &image_index,
|
||||
.pResults = NULL,
|
||||
});
|
||||
|
||||
if (
|
||||
queue_present_result == VK_ERROR_OUT_OF_DATE_KHR ||
|
||||
queue_present_result == VK_SUBOPTIMAL_KHR ||
|
||||
g_framebuffer_resized
|
||||
) {
|
||||
g_framebuffer_resized = false;
|
||||
if (!vk_recreate_swapchain()) {
|
||||
return false;
|
||||
}
|
||||
PTK_TRACE("recreated swapchain");
|
||||
} else if (queue_present_result != VK_SUCCESS) {
|
||||
PTK_ERR("%s", vk_result_string(queue_present_result));
|
||||
return false;
|
||||
}
|
||||
|
||||
g_current_frame = (g_current_frame + 1) % g_max_frames_in_flight;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_DRAW_H_
|
||||
#define PTK_PTK_VK_DRAW_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern bool g_framebuffer_resized;
|
||||
extern uint32_t g_current_frame;
|
||||
|
||||
bool vk_draw_frame(void);
|
||||
|
||||
#endif // PTK_PTK_VK_DRAW_H_
|
|
@ -1,18 +1,23 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk_vk/image.h>
|
||||
#include "ptk_vk/image.h"
|
||||
|
||||
#include <ptk_vk/init.h>
|
||||
#include <ptk_vk/utils.h>
|
||||
#include "ptk_vk/buffer.h"
|
||||
#include "ptk_vk/command_pool.h"
|
||||
#include "ptk_vk/descriptors.h"
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/physical_device.h"
|
||||
// PTK_LIST(VkDeviceMemory)
|
||||
#include "ptk_vk/uniform_buffers.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include <ptk_log.h>
|
||||
#include <ptk_option.h>
|
||||
#include "ptk_log.h"
|
||||
#include "ptk_option.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
PTK_LIST_DEFINE(VkImage);
|
||||
PTK_LIST_DEFINE(VkDeviceMemory);
|
||||
|
||||
const size_t g_max_images = 64;
|
||||
|
||||
|
@ -56,7 +61,7 @@ bool create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTilin
|
|||
VkMemoryRequirements mem_reqs;
|
||||
vkGetImageMemoryRequirements(g_dev, *image, &mem_reqs);
|
||||
|
||||
PTK_OPTION(uint32_t) mem_type = vk_find_memory_type(mem_reqs.memoryTypeBits, props);
|
||||
PTK_OPTION(uint32_t) mem_type = vk_find_memory_type(g_physical_dev, mem_reqs.memoryTypeBits, props);
|
||||
|
||||
if (!mem_type.exists) {
|
||||
PTK_ERR("failed to find suitable memory type");
|
||||
|
@ -91,13 +96,15 @@ bool create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTilin
|
|||
|
||||
bool transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
|
||||
(void)format;
|
||||
PTK_OPTION(VkCommandBuffer) command_buffer = vk_begin_single_time_commands();
|
||||
PTK_OPTION(VkCommandBuffer) command_buffer_opt = vk_begin_single_time_commands();
|
||||
|
||||
if (!command_buffer.exists) {
|
||||
if (!command_buffer_opt.exists) {
|
||||
PTK_ERR("failed to create command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer command_buffer = command_buffer_opt.value;
|
||||
|
||||
VkAccessFlags source_access_mask;
|
||||
VkAccessFlags destination_access_mask;
|
||||
VkPipelineStageFlags source_stage;
|
||||
|
@ -127,7 +134,7 @@ bool transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_l
|
|||
}
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
command_buffer.value,
|
||||
command_buffer,
|
||||
source_stage,
|
||||
destination_stage,
|
||||
0,
|
||||
|
@ -156,7 +163,7 @@ bool transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_l
|
|||
}
|
||||
);
|
||||
|
||||
if (!vk_end_single_time_commands(command_buffer.value)) {
|
||||
if (!vk_end_single_time_commands(command_buffer)) {
|
||||
PTK_ERR("failed to end command buffer");
|
||||
return false;
|
||||
}
|
||||
|
@ -165,15 +172,17 @@ bool transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_l
|
|||
}
|
||||
|
||||
bool copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
|
||||
PTK_OPTION(VkCommandBuffer) command_buffer = vk_begin_single_time_commands();
|
||||
PTK_OPTION(VkCommandBuffer) command_buffer_opt = vk_begin_single_time_commands();
|
||||
|
||||
if (!command_buffer.exists) {
|
||||
if (!command_buffer_opt.exists) {
|
||||
PTK_ERR("failed to create command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer command_buffer = command_buffer_opt.value;
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
command_buffer.value,
|
||||
command_buffer,
|
||||
buffer,
|
||||
image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
|
@ -201,7 +210,7 @@ bool copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32
|
|||
}
|
||||
);
|
||||
|
||||
if (!vk_end_single_time_commands(command_buffer.value)) {
|
||||
if (!vk_end_single_time_commands(command_buffer)) {
|
||||
PTK_ERR("failed to end command buffer");
|
||||
return false;
|
||||
}
|
||||
|
@ -292,20 +301,22 @@ bool vk_create_image(const char *path) {
|
|||
|
||||
VkBuffer staging_buffer;
|
||||
VkDeviceMemory staging_buffer_memory;
|
||||
PTK_OPTION(BufferStuff) staging_buffer_stuff_opt = vk_create_buffer(
|
||||
g_dev,
|
||||
g_physical_dev,
|
||||
image_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
);
|
||||
|
||||
if (
|
||||
!vk_create_buffer(
|
||||
image_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
&staging_buffer,
|
||||
&staging_buffer_memory
|
||||
)
|
||||
) {
|
||||
if (!staging_buffer_stuff_opt.exists) {
|
||||
PTK_ERR("failed creating staging image buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
staging_buffer = staging_buffer_stuff_opt.value.buffer;
|
||||
staging_buffer_memory = staging_buffer_stuff_opt.value.buffer_memory;
|
||||
|
||||
void *data;
|
||||
vkMapMemory(g_dev, staging_buffer_memory, 0, image_size, 0, &data);
|
||||
memcpy(data, pixels, image_size);
|
||||
|
|
|
@ -3,15 +3,11 @@
|
|||
#ifndef PTK_PTK_VK_IMAGE_H_
|
||||
#define PTK_PTK_VK_IMAGE_H_
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <ptk_list.h>
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
extern const size_t g_max_images;
|
||||
|
||||
extern size_t g_image_count;
|
||||
|
|
1702
src/ptk_vk/init.c
1702
src/ptk_vk/init.c
File diff suppressed because it is too large
Load diff
|
@ -3,55 +3,14 @@
|
|||
#ifndef PTK_PTK_VK_INIT_H_
|
||||
#define PTK_PTK_VK_INIT_H_
|
||||
|
||||
#ifndef GLFW_INCLUDE_VULKAN
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <ptk.h>
|
||||
#include <ptk_list.h>
|
||||
#include <ptk_option.h>
|
||||
#include "ptk_vk/uniform_buffers.h"
|
||||
|
||||
PTK_LIST_DEFINE(VkCommandBuffer);
|
||||
PTK_LIST_DEFINE(VkSemaphore);
|
||||
PTK_LIST_DEFINE(VkFence);
|
||||
PTK_OPTION_DEFINE(VkCommandBuffer);
|
||||
PTK_OPTION_DEFINE(uint32_t);
|
||||
#include <stdbool.h>
|
||||
|
||||
extern VkDevice g_dev;
|
||||
extern VkPhysicalDevice g_physical_dev;
|
||||
extern VkSwapchainKHR g_swapchain;
|
||||
|
||||
extern VkQueue g_graphics_queue;
|
||||
extern VkQueue g_present_queue;
|
||||
|
||||
extern const size_t g_max_frames_in_flight;
|
||||
|
||||
extern PTK_LIST(VkCommandBuffer) g_command_buffers;
|
||||
|
||||
extern PTK_LIST(VkSemaphore) g_image_available_semaphores;
|
||||
extern PTK_LIST(VkSemaphore) g_render_finished_semaphores;
|
||||
extern PTK_LIST(VkFence) g_in_flight_fences;
|
||||
|
||||
bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const char *title, const PtkVersion version);
|
||||
extern UniformBufferObject g_uniform_buffer_object;
|
||||
|
||||
bool vk_transfer_vertex_data(void);
|
||||
|
||||
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_create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory);
|
||||
|
||||
PTK_OPTION(uint32_t) vk_find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props);
|
||||
|
||||
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void);
|
||||
|
||||
bool vk_end_single_time_commands(VkCommandBuffer command_buffer);
|
||||
|
||||
void vk_update_descriptor_sets(void);
|
||||
|
||||
void vk_cleanup(void);
|
||||
|
||||
#endif // PTK_PTK_VK_INIT_H_
|
||||
|
|
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/backend.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) {
|
||||
#ifdef DEBUG
|
||||
if (!check_validation_layers(g_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 = g_validation_layers.size,
|
||||
.ppEnabledLayerNames = g_validation_layers.data,
|
||||
.enabledExtensionCount = extension_names.size,
|
||||
.ppEnabledExtensionNames = extension_names.data,
|
||||
},
|
||||
NULL,
|
||||
&g_instance
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
14
src/ptk_vk/instance.h
Normal file
14
src/ptk_vk/instance.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_INSTANCE_H_
|
||||
#define PTK_PTK_VK_INSTANCE_H_
|
||||
|
||||
#include "ptk.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
extern VkInstance g_instance;
|
||||
|
||||
bool vk_instance_create(const char *title, const PtkVersion version);
|
||||
|
||||
#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_vk/instance.h"
|
||||
|
||||
#include "ptk_log.h"
|
||||
|
||||
VkPhysicalDevice g_physical_dev;
|
||||
|
||||
bool vk_select_physical_dev(void) {
|
||||
uint32_t dev_count = 0;
|
||||
vkEnumeratePhysicalDevices(g_instance, &dev_count, NULL);
|
||||
if (dev_count == 0) {
|
||||
PTK_ERR("failed to find GPU with vulkan support");
|
||||
return false;
|
||||
}
|
||||
VkPhysicalDevice devs[dev_count];
|
||||
vkEnumeratePhysicalDevices(g_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;
|
||||
}
|
14
src/ptk_vk/physical_device.h
Normal file
14
src/ptk_vk/physical_device.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
// 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 <stdbool.h>
|
||||
|
||||
extern VkPhysicalDevice g_physical_dev;
|
||||
|
||||
bool vk_select_physical_dev(void);
|
||||
|
||||
#endif // PTK_PTK_VK_PHYSICAL_DEVICE_H_
|
339
src/ptk_vk/pipeline.c
Normal file
339
src/ptk_vk/pipeline.c
Normal file
|
@ -0,0 +1,339 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/pipeline.h"
|
||||
|
||||
#include "ptk_vk/components.h"
|
||||
#include "ptk_vk/descriptors.h"
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/image.h"
|
||||
#include "ptk_vk/render_pass.h"
|
||||
#include "ptk_vk/swapchain.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
#include "ptk_array.h"
|
||||
#include "ptk_option.h"
|
||||
#include "ptk_log.h"
|
||||
|
||||
#include "errno.h"
|
||||
#include "stdio.h"
|
||||
|
||||
VkPipeline g_pipeline;
|
||||
VkPipelineLayout g_pipeline_layout;
|
||||
|
||||
PTK_OPTION_DEFINE(VkShaderModule);
|
||||
PTK_ARRAY_DEFINE(VkVertexInputAttributeDescription);
|
||||
|
||||
static const VkVertexInputBindingDescription m_vertex_binding_description = {
|
||||
.binding = 0,
|
||||
.stride = sizeof(Vertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
||||
};
|
||||
|
||||
static PTK_ARRAY(VkVertexInputAttributeDescription) m_vertex_attribute_descriptions = PTK_ARRAY_NEW(VkVertexInputAttributeDescription, {
|
||||
(VkVertexInputAttributeDescription){
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(Vertex, pos),
|
||||
},
|
||||
(VkVertexInputAttributeDescription){
|
||||
.location = 1,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = offsetof(Vertex, color),
|
||||
},
|
||||
(VkVertexInputAttributeDescription){
|
||||
.location = 2,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32_SINT,
|
||||
.offset = offsetof(Vertex, shape_type),
|
||||
},
|
||||
(VkVertexInputAttributeDescription){
|
||||
.location = 3,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(Vertex, uv),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
PTK_STRING read_spv(const char *filename) {
|
||||
errno = 0;
|
||||
FILE *file = fopen(filename, "r");
|
||||
|
||||
if (errno != 0) {
|
||||
switch (errno) {
|
||||
case EACCES: PTK_ERR("insufficient permissions to open %s", filename); break;
|
||||
default: PTK_ERR("unknown error while reading %s", filename); break;
|
||||
}
|
||||
return PTK_LIST_NEW(char, 0);
|
||||
}
|
||||
|
||||
PTK_STRING buffer;
|
||||
|
||||
fseek(file, 0L, SEEK_END);
|
||||
buffer.allocated = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
buffer = PTK_STRING_NEW(buffer.allocated);
|
||||
|
||||
const size_t items_read = fread(buffer.data, sizeof(char), buffer.allocated, file);
|
||||
|
||||
if (items_read != buffer.allocated) {
|
||||
if (feof(file)) {
|
||||
PTK_ERR("unexpected end of file while reading %s", filename);
|
||||
} else if (ferror(file)) {
|
||||
PTK_ERR("error reading %s", filename);
|
||||
}
|
||||
return PTK_STRING_NEW(0);
|
||||
}
|
||||
|
||||
PTK_LIST_FILLED(buffer);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
PTK_OPTION(VkShaderModule) create_shader_module(VkDevice dev, const PTK_STRING code) {
|
||||
VkShaderModule shader_module;
|
||||
|
||||
VK_TRY(PTK_OPTION_NONE(VkShaderModule),
|
||||
vkCreateShaderModule(
|
||||
dev,
|
||||
&(VkShaderModuleCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.codeSize = code.size,
|
||||
.pCode = (const uint32_t *)code.data,
|
||||
},
|
||||
NULL,
|
||||
&shader_module
|
||||
)
|
||||
);
|
||||
|
||||
return PTK_OPTION_SOME(VkShaderModule, shader_module);
|
||||
}
|
||||
|
||||
bool vk_create_pipeline(void) {
|
||||
const PTK_STRING vert_shader_code = read_spv("target/shaders/shader.vert.spv");
|
||||
const PTK_STRING frag_shader_code = read_spv("target/shaders/shader.frag.spv");
|
||||
|
||||
const PTK_OPTION(VkShaderModule) vert_shader_module = create_shader_module(g_dev, vert_shader_code);
|
||||
|
||||
if (!vert_shader_module.exists) {
|
||||
PTK_ERR("failed creating vert shader module");
|
||||
return false;
|
||||
}
|
||||
|
||||
const PTK_OPTION(VkShaderModule) frag_shader_module = create_shader_module(g_dev, frag_shader_code);
|
||||
|
||||
if (!frag_shader_module.exists) {
|
||||
PTK_ERR("failed creating frag shader module");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkSpecializationInfo spec_info = {
|
||||
.mapEntryCount = 3,
|
||||
.pMapEntries = (VkSpecializationMapEntry []){
|
||||
(VkSpecializationMapEntry){
|
||||
.constantID = 0,
|
||||
.offset = 0,
|
||||
.size = sizeof(int),
|
||||
},
|
||||
(VkSpecializationMapEntry){
|
||||
.constantID = 1,
|
||||
.offset = sizeof(int),
|
||||
.size = sizeof(int),
|
||||
},
|
||||
(VkSpecializationMapEntry){
|
||||
.constantID = 2,
|
||||
.offset = 2 * sizeof(int),
|
||||
.size = sizeof(int),
|
||||
},
|
||||
},
|
||||
.dataSize = 3 * sizeof(int),
|
||||
.pData = (int []){
|
||||
PTK_COMPONENT_TYPE_ELLIPSE,
|
||||
PTK_COMPONENT_TYPE_IMAGE,
|
||||
g_max_images
|
||||
},
|
||||
};
|
||||
|
||||
const VkPipelineShaderStageCreateInfo shader_stages[] = {
|
||||
(VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vert_shader_module.value,
|
||||
.pName = "main",
|
||||
.pSpecializationInfo = NULL,
|
||||
},
|
||||
(VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = frag_shader_module.value,
|
||||
.pName = "main",
|
||||
.pSpecializationInfo = &spec_info,
|
||||
},
|
||||
};
|
||||
|
||||
const VkPipelineVertexInputStateCreateInfo vertex_input_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &m_vertex_binding_description,
|
||||
.vertexAttributeDescriptionCount = m_vertex_attribute_descriptions.size,
|
||||
.pVertexAttributeDescriptions = m_vertex_attribute_descriptions.data,
|
||||
};
|
||||
|
||||
const VkPipelineDynamicStateCreateInfo dynamic_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.dynamicStateCount = 0,
|
||||
.pDynamicStates = NULL,
|
||||
};
|
||||
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
const VkPipelineViewportStateCreateInfo viewport_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &(VkViewport){
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = (float) g_swapchain_extent.width,
|
||||
.height = (float) g_swapchain_extent.height,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
},
|
||||
.scissorCount = 1,
|
||||
.pScissors = &(VkRect2D){
|
||||
.offset = (VkOffset2D){
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
},
|
||||
.extent = g_swapchain_extent,
|
||||
},
|
||||
};
|
||||
|
||||
const VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f,
|
||||
.depthBiasClamp = 0.0f,
|
||||
.depthBiasSlopeFactor = 0.0f,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
const VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.minSampleShading = 1.0f,
|
||||
.pSampleMask = NULL,
|
||||
.alphaToCoverageEnable = VK_FALSE,
|
||||
.alphaToOneEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
const VkPipelineColorBlendAttachmentState color_blend_attachment = {
|
||||
.blendEnable = VK_TRUE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
const VkPipelineColorBlendStateCreateInfo color_blending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &color_blend_attachment,
|
||||
.blendConstants[0] = 0.0f,
|
||||
.blendConstants[1] = 0.0f,
|
||||
.blendConstants[2] = 0.0f,
|
||||
.blendConstants[3] = 0.0f,
|
||||
};
|
||||
|
||||
VK_TRY(false,
|
||||
vkCreatePipelineLayout(
|
||||
g_dev,
|
||||
&(VkPipelineLayoutCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &g_descriptor_set_layout,
|
||||
.pushConstantRangeCount = 0,
|
||||
.pPushConstantRanges = NULL,
|
||||
},
|
||||
NULL,
|
||||
&g_pipeline_layout
|
||||
)
|
||||
);
|
||||
|
||||
VK_TRY(false,
|
||||
vkCreateGraphicsPipelines(
|
||||
g_dev,
|
||||
VK_NULL_HANDLE,
|
||||
1,
|
||||
&(VkGraphicsPipelineCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.stageCount = 2,
|
||||
.pStages = shader_stages,
|
||||
.pVertexInputState = &vertex_input_info,
|
||||
.pInputAssemblyState = &input_assembly,
|
||||
.pTessellationState = NULL,
|
||||
.pViewportState = &viewport_state,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pDepthStencilState = NULL,
|
||||
.pColorBlendState = &color_blending,
|
||||
.pDynamicState = &dynamic_state,
|
||||
.layout = g_pipeline_layout,
|
||||
.renderPass = g_render_pass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1,
|
||||
},
|
||||
NULL,
|
||||
&g_pipeline
|
||||
)
|
||||
);
|
||||
|
||||
vkDestroyShaderModule(g_dev, vert_shader_module.value, NULL);
|
||||
vkDestroyShaderModule(g_dev, frag_shader_module.value, NULL);
|
||||
|
||||
return true;
|
||||
}
|
15
src/ptk_vk/pipeline.h
Normal file
15
src/ptk_vk/pipeline.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_PIPELINE_H_
|
||||
#define PTK_PTK_VK_PIPELINE_H_
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern VkPipeline g_pipeline;
|
||||
extern VkPipelineLayout g_pipeline_layout;
|
||||
|
||||
bool vk_create_pipeline(void);
|
||||
|
||||
#endif // PTK_PTK_VK_PIPELINE_H_
|
64
src/ptk_vk/render_pass.c
Normal file
64
src/ptk_vk/render_pass.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/render_pass.h"
|
||||
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/swapchain.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 <vulkan/vulkan.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern VkRenderPass g_render_pass;
|
||||
|
||||
bool vk_create_render_pass(void);
|
||||
|
||||
#endif // PTK_PTK_VK_RENDER_PASS_H_
|
295
src/ptk_vk/swapchain.c
Normal file
295
src/ptk_vk/swapchain.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/swapchain.h"
|
||||
|
||||
#include "ptk_vk/backend.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>
|
||||
|
||||
PTK_LIST_DEFINE(VkImage);
|
||||
PTK_LIST_DEFINE(VkImageView);
|
||||
|
||||
static PTK_LIST(VkImage) m_swapchain_images;
|
||||
static PTK_LIST(VkImageView) m_swapchain_image_views;
|
||||
|
||||
VkSwapchainKHR g_swapchain;
|
||||
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_swapchain(void) {
|
||||
const SwapchainSupportInfo swapchain_support = query_swapchain_support(g_physical_dev, g_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, g_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(
|
||||
g_dev,
|
||||
&(VkSwapchainCreateInfoKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.surface = g_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(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);
|
||||
|
||||
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_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 = 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_recreate_swapchain(void) {
|
||||
int width = 0, height = 0;
|
||||
glfwGetFramebufferSize(g_window, &width, &height);
|
||||
|
||||
while (width == 0 || height == 0) {
|
||||
glfwGetFramebufferSize(g_window, &width, &height);
|
||||
glfwWaitEvents();
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(g_dev);
|
||||
|
||||
vk_cleanup_swapchain();
|
||||
|
||||
if (!vk_create_swapchain()) {
|
||||
PTK_ERR("failed creating new swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vk_create_image_views()) {
|
||||
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(void) {
|
||||
PTK_LIST_FOR_EACH(VkFramebuffer, g_swapchain_framebuffers, fb, {
|
||||
vkDestroyFramebuffer(g_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(g_dev, iv, NULL);
|
||||
})
|
||||
PTK_LIST_FREE(m_swapchain_image_views);
|
||||
|
||||
vkDestroySwapchainKHR(g_dev, g_swapchain, NULL);
|
||||
}
|
39
src/ptk_vk/swapchain.h
Normal file
39
src/ptk_vk/swapchain.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_SWAPCHAIN_H_
|
||||
#define PTK_PTK_VK_SWAPCHAIN_H_
|
||||
|
||||
#include "ptk_list.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
PTK_LIST_DEFINE(VkFramebuffer);
|
||||
|
||||
PTK_LIST_DEFINE(VkSurfaceFormatKHR);
|
||||
PTK_LIST_DEFINE(VkPresentModeKHR);
|
||||
|
||||
extern VkSwapchainKHR g_swapchain;
|
||||
extern VkFormat g_swapchain_image_format;
|
||||
extern VkExtent2D g_swapchain_extent;
|
||||
extern PTK_LIST(VkFramebuffer) g_swapchain_framebuffers;
|
||||
|
||||
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(void);
|
||||
|
||||
bool vk_create_image_views(void);
|
||||
|
||||
bool vk_recreate_swapchain(void);
|
||||
|
||||
bool vk_create_framebuffers(void);
|
||||
|
||||
void vk_cleanup_swapchain(void);
|
||||
|
||||
#endif // PTK_PTK_VK_SWAPCHAIN_H_
|
49
src/ptk_vk/sync_objects.c
Normal file
49
src/ptk_vk/sync_objects.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/sync_objects.h"
|
||||
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
PTK_LIST(VkSemaphore) g_image_available_semaphores;
|
||||
PTK_LIST(VkSemaphore) g_render_finished_semaphores;
|
||||
PTK_LIST(VkFence) g_in_flight_fences;
|
||||
|
||||
const size_t g_max_frames_in_flight = 2;
|
||||
|
||||
bool vk_create_sync_objects(void) {
|
||||
g_image_available_semaphores = PTK_LIST_NEW(VkSemaphore, g_max_frames_in_flight);
|
||||
g_render_finished_semaphores = PTK_LIST_NEW(VkSemaphore, g_max_frames_in_flight);
|
||||
g_in_flight_fences = PTK_LIST_NEW(VkFence, g_max_frames_in_flight);
|
||||
|
||||
const VkSemaphoreCreateInfo semaphore_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
||||
VK_TRY(false,
|
||||
vkCreateSemaphore(g_dev, &semaphore_info, NULL, &g_image_available_semaphores.data[i])
|
||||
);
|
||||
|
||||
VK_TRY(false,
|
||||
vkCreateSemaphore(g_dev, &semaphore_info, NULL, &g_render_finished_semaphores.data[i])
|
||||
);
|
||||
|
||||
VK_TRY(false,
|
||||
vkCreateFence(
|
||||
g_dev,
|
||||
&(VkFenceCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
},
|
||||
NULL,
|
||||
&g_in_flight_fences.data[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
21
src/ptk_vk/sync_objects.h
Normal file
21
src/ptk_vk/sync_objects.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_SYNC_OBJECTS_H_
|
||||
#define PTK_PTK_VK_SYNC_OBJECTS_H_
|
||||
|
||||
#include "ptk_list.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
PTK_LIST_DEFINE(VkSemaphore);
|
||||
PTK_LIST_DEFINE(VkFence);
|
||||
|
||||
extern PTK_LIST(VkSemaphore) g_image_available_semaphores;
|
||||
extern PTK_LIST(VkSemaphore) g_render_finished_semaphores;
|
||||
extern PTK_LIST(VkFence) g_in_flight_fences;
|
||||
|
||||
extern const size_t g_max_frames_in_flight;
|
||||
|
||||
bool vk_create_sync_objects(void);
|
||||
|
||||
#endif // PTK_PTK_VK_SYNC_OBJECTS_H_
|
44
src/ptk_vk/uniform_buffers.c
Normal file
44
src/ptk_vk/uniform_buffers.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include "ptk_vk/uniform_buffers.h"
|
||||
|
||||
#include "ptk_vk/buffer.h"
|
||||
#include "ptk_vk/device.h"
|
||||
#include "ptk_vk/physical_device.h"
|
||||
#include "ptk_vk/sync_objects.h"
|
||||
|
||||
#include "ptk_log.h"
|
||||
|
||||
PTK_LIST(VkBuffer) g_uniform_buffers;
|
||||
PTK_LIST(VkDeviceMemory) g_uniform_buffer_memories;
|
||||
PTK_LIST(voidptr) g_uniform_buffers_mapped;
|
||||
|
||||
bool vk_create_uniform_buffers(void) {
|
||||
const VkDeviceSize buffer_size = sizeof(UniformBufferObject);
|
||||
|
||||
g_uniform_buffers = PTK_LIST_NEW(VkBuffer, g_max_frames_in_flight);
|
||||
g_uniform_buffer_memories = PTK_LIST_NEW(VkDeviceMemory, g_max_frames_in_flight);
|
||||
g_uniform_buffers_mapped = PTK_LIST_NEW(voidptr, g_max_frames_in_flight);
|
||||
|
||||
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
|
||||
PTK_OPTION(BufferStuff) uniform_buffer_stuff_opt = vk_create_buffer(
|
||||
g_dev,
|
||||
g_physical_dev,
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
);
|
||||
|
||||
if (!uniform_buffer_stuff_opt.exists) {
|
||||
PTK_ERR("failed creating index buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_uniform_buffers.data[i] = uniform_buffer_stuff_opt.value.buffer;
|
||||
g_uniform_buffer_memories.data[i] = uniform_buffer_stuff_opt.value.buffer_memory;
|
||||
|
||||
vkMapMemory(g_dev, g_uniform_buffer_memories.data[i], 0, buffer_size, 0, &g_uniform_buffers_mapped.data[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
27
src/ptk_vk/uniform_buffers.h
Normal file
27
src/ptk_vk/uniform_buffers.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#ifndef PTK_PTK_VK_UNIFORM_BUFFERS_H_
|
||||
#define PTK_PTK_VK_UNIFORM_BUFFERS_H_
|
||||
|
||||
#include "ptk_list.h"
|
||||
#include "ptk_vec.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
typedef struct {
|
||||
PtkSize initial_window_size;
|
||||
PtkSize window_size;
|
||||
} UniformBufferObject;
|
||||
|
||||
PTK_LIST_DEFINE(VkBuffer);
|
||||
PTK_LIST_DEFINE(VkDeviceMemory);
|
||||
typedef void *voidptr;
|
||||
PTK_LIST_DEFINE(voidptr);
|
||||
|
||||
extern PTK_LIST(VkBuffer) g_uniform_buffers;
|
||||
extern PTK_LIST(VkDeviceMemory) g_uniform_buffer_memories;
|
||||
extern PTK_LIST(voidptr) g_uniform_buffers_mapped;
|
||||
|
||||
bool vk_create_uniform_buffers(void);
|
||||
|
||||
#endif // PTK_PTK_VK_UNIFORM_BUFFERS_H_
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <ptk_vk/utils.h>
|
||||
#include "ptk_vk/utils.h"
|
||||
|
||||
const char *vk_result_string(VkResult res) {
|
||||
const char *str;
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
#ifndef PTK_PTK_VK_UTILS_H_
|
||||
#define PTK_PTK_VK_UTILS_H_
|
||||
|
||||
#include "ptk_log.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <ptk_log.h>
|
||||
|
||||
const char *vk_result_string(VkResult res);
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
|
||||
|
||||
#include <test.h>
|
||||
#include <ptk_list.h>
|
||||
#include "test.h"
|
||||
|
||||
#include "ptk_list.h"
|
||||
|
||||
PTK_LIST_DEFINE(uint32_t);
|
||||
|
||||
|
|
Loading…
Reference in a new issue