hello triangle completed

This commit is contained in:
Matthew 2025-03-02 17:09:19 +11:00
parent e04111aefb
commit 3279fabb1b
12 changed files with 381 additions and 121 deletions

71
src/game.c Normal file
View File

@ -0,0 +1,71 @@
static void Run()
{
InitPlatform();
u8 *mem = (u8 *)MemAllocZeroed(MB(512));
Arena *arena = CreateArenaDebug(mem, MB(512), __LINE__);
isize renderer_mem_size = MB(8);
rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size);
Arena *renderer_arena = CreateArenaDebug(renderer_mem, MB(8), __LINE__);
Assert(CreateWindow(), "Failed to initialize the window");
Assert(InitRenderer(renderer_arena), "Failed to initialize the renderer");
b32 quit = false;
while (!quit)
{
if (HandleEvents()) break;
BeginFrame();
DrawTriangle();
FinishFrame();
}
DestroyRenderer();
}
static b32 HandleEvents()
{
b32 quit = false;
WindowEvent e;
while (GetWindowEvent(&e))
{
quit = ProcessEvent(&e);
}
return quit;
}
static b32 WaitForAndHandleEvent()
{
WindowEvent e;
WaitForWindowEvent(&e);
return ProcessEvent(&e);
}
static b32 ProcessEvent(WindowEvent *e)
{
b32 quit = false;
switch (e->type)
{
case EVENT_QUIT:
quit = true;
break;
case EVENT_RESIZE:
SetRenderResolution(e->resize.w, e->resize.h);
break;
case EVENT_MINIMIZE:
break;
case EVENT_SHOW:
break;
default:
break;
}
return quit;
}

6
src/game.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
static void Run();
static b32 HandleEvents();
static b32 WaitForAndHandleEvent();
static b32 ProcessEvent(WindowEvent *e);

View File

@ -4,44 +4,9 @@
#include "util.c"
#include "arena.c"
#include "render.c"
#include "game.c"
int main(int argc, char **argv)
{
InitPlatform();
u8 *mem = (u8 *)MemAllocZeroed(MB(512));
Arena *arena = CreateArenaDebug(mem, MB(512), __LINE__);
isize renderer_mem_size = MB(8);
rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size);
Arena *renderer_arena = CreateArenaDebug(renderer_mem, MB(8), __LINE__);
Assert(CreateWindow(), "Failed to initialize the window");
Assert(InitRenderer(renderer_arena), "Failed to initialize the renderer");
b32 quit = false;
WindowEvent e;
while (!quit)
{
while (GetWindowEvent(&e))
{
switch (e.type)
{
case EVENT_QUIT:
quit = true;
break;
default:
break;
}
}
BeginFrame();
DrawTriangle();
FinishFrame();
}
DestroyRenderer();
return 0;
Run();
}

View File

@ -12,5 +12,6 @@
#include "util.h"
#include "arena.h"
#include "render.h"
#include "game.h"
int main(int argc, char **argv);

View File

@ -97,6 +97,11 @@ b32 GetWindowEvent(WindowEvent *event)
return _GetWindowEvent(event);
}
void WaitForWindowEvent(WindowEvent *event)
{
_WaitForWindowEvent(event);
}
WindowSize GetWindowSize()
{
return _GetWindowSize();

View File

@ -25,6 +25,8 @@ enum Event_e
EVENT_NONE = 0,
EVENT_QUIT,
EVENT_RESIZE,
EVENT_MINIMIZE,
EVENT_SHOW,
};
struct WindowSize
@ -62,6 +64,7 @@ i32 EPrintf(const char *fmt, ...);
b32 CreateWindow();
Window *GetWindow();
b32 GetWindowEvent(WindowEvent *event);
void WaitForWindowEvent(WindowEvent *event);
WindowSize GetWindowSize();
// Directory Functions

View File

@ -140,7 +140,8 @@ b32 _CreateWindow()
{
Window *window = &linux_window;
window->connection = xcb_connect(NULL, NULL);
int screen_index;
window->connection = xcb_connect(NULL, &screen_index);
if (!window->connection) {
return false;
@ -159,23 +160,23 @@ b32 _CreateWindow()
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_MOTION |
XCB_EVENT_MASK_STRUCTURE_NOTIFY|
XCB_EVENT_MASK_RESIZE_REDIRECT;
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
const int val_win[] = {event_mask, 0};
const int val_mask = XCB_CW_EVENT_MASK;
const int val_win[] = {screen->black_pixel, event_mask};
const int val_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
window->window = xcb_generate_id(window->connection);
cookie = xcb_create_window_checked(
cookie = xcb_create_window(
window->connection,
XCB_COPY_FROM_PARENT,
window->window,
screen->root,
0, 0, // x/y pos
window->w, window->h,
10,
0, // x pos
0, // y pos
window->w, // width
window->h, // height
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
val_mask,
@ -206,6 +207,10 @@ b32 _CreateWindow()
xcb_intern_atom_reply_t *r_close = xcb_intern_atom_reply(window->connection, c_close, &error);
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_DELETE_WINDOW.");
xcb_intern_atom_cookie_t c_minimize = xcb_intern_atom(window->connection, 0, 20, "_NET_WM_STATE_HIDDEN");
xcb_intern_atom_reply_t *r_minimize = xcb_intern_atom_reply(window->connection, c_minimize, &error);
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get _NET_WM_STATE_HIDDEN");
cookie = xcb_change_property_checked(
window->connection,
XCB_PROP_MODE_REPLACE,
@ -219,6 +224,20 @@ b32 _CreateWindow()
XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event.");
window->close_event = r_close->atom;
window->minimize_event = r_minimize->atom;
free(r_proto);
free(r_close);
free(r_minimize);
xcb_map_window(window->connection, window->window);
i32 stream_result = xcb_flush(window->connection);
if (stream_result <= 0)
{
Printfln("Error flushing the stream: %d", stream_result);
return false;
}
return true;
}
@ -236,6 +255,16 @@ WindowSize _GetWindowSize()
}
b32 _GetWindowEvent(WindowEvent *event)
{
return HandleWindowEvent(event, false);
}
void _WaitForWindowEvent(WindowEvent *event)
{
HandleWindowEvent(event, true);
}
b32 HandleWindowEvent(WindowEvent *event, b32 wait_for_event)
{
Assert(event != NULL, "GetWindowEvent received a null pointer");
@ -243,8 +272,13 @@ b32 _GetWindowEvent(WindowEvent *event)
b32 no_event = false;
do
{
xcb_generic_event_t *e = xcb_poll_for_event(linux_window.connection);
xcb_generic_event_t *e;
if (wait_for_event)
e = xcb_wait_for_event(linux_window.connection);
else
e = xcb_poll_for_event(linux_window.connection);
// XCB_UNMAP_NOTIFY
if (e != NULL)
{
switch (e->response_type & ~0x80)
@ -256,34 +290,55 @@ b32 _GetWindowEvent(WindowEvent *event)
event->type = EVENT_QUIT;
valid_event = true;
}
break;
case XCB_RESIZE_REQUEST:
event->type = EVENT_RESIZE;
valid_event = true;
xcb_resize_request_event_t *resize = (xcb_resize_request_event_t *)e;
if (resize->width > 0)
if (msg->data.data32[0] == linux_window.minimize_event)
{
linux_window.w = resize->width;
event->resize.w = resize->width;
event->type = EVENT_MINIMIZE;
valid_event = true;
linux_window.w = 0;
linux_window.h = 0;
}
if (resize->height > 0)
break;
case XCB_UNMAP_NOTIFY:
break;
case XCB_EXPOSE:
event->type = EVENT_SHOW;
xcb_expose_event_t *expose_e = (xcb_expose_event_t *)e;
linux_window.w = expose_e->width;
linux_window.h = expose_e->height;
break;
case XCB_CONFIGURE_NOTIFY:
Printfln("configure notify");
xcb_configure_notify_event_t *configure_event = (xcb_configure_notify_event_t *)e;
if (linux_window.w != configure_event->width || linux_window.h != configure_event->height)
{
linux_window.h = resize->height;
event->resize.h = resize->height;
Printfln("inner w %d h %d", configure_event->width, configure_event->height);
event->type = EVENT_RESIZE;
valid_event = true;
event->resize.w = configure_event->width;
event->resize.h = configure_event->height;
linux_window.w = configure_event->width;
linux_window.h = configure_event->height;
}
break;
default:
break;
}
free(e);
}
else
{
break;
}
} while(!valid_event);
} while(!valid_event && !wait_for_event);
return valid_event;
}

View File

@ -62,6 +62,7 @@ typedef size_t usize;
typedef float f32;
typedef double f64;
typedef uint8_t b8;
typedef uint32_t b32;
typedef void * rawptr;
@ -70,6 +71,7 @@ typedef struct {
xcb_connection_t *connection;
xcb_window_t window;
xcb_atom_t close_event;
xcb_atom_t minimize_event;
u16 w, h;
} Window;
@ -81,6 +83,36 @@ typedef struct {
void *fn;
} Function;
// X11
typedef struct
{
} XConnectRequest;
typedef struct {
u8 opcode;
u16 len; // length in units of 4 bytes
u8 data;
// Extra data
} XRequest;
typedef struct {
u32 len;
} XReply;
typedef struct {
} XError;
typedef struct {
} XEvent;
typedef u32 XWindow;
typedef u32 XAtom;
typedef u32 XVisID;
// Platform API
// Init Functions
@ -103,7 +135,9 @@ i32 _EPrintf(const char *fmt, va_list arg);
b32 _CreateWindow();
Window *_GetWindow();
b32 _GetWindowEvent(WindowEvent *event);
void _WaitForWindowEvent(WindowEvent *event);
WindowSize _GetWindowSize();
b32 HandleWindowEvent(WindowEvent *event, b32 wait_for_event);
// Platform API END

View File

@ -36,3 +36,8 @@ b32 FinishFrame()
{
return _FinishFrame();
}
void SetRenderResolution(u32 x, u32 y)
{
_SetRenderResolution(x, y);
}

View File

@ -23,4 +23,4 @@ void DestroyRenderer();
static b32 DrawFrame();
static void DrawTriangle();
static b32 FinishFrame();
static void SetRenderResolution(u32 x, u32 y);

View File

@ -15,22 +15,45 @@ void _DestroyRenderer()
DestroyVulkan();
}
static u32 GetFrameIndex()
{
return renderer.frame_state.frame_cnt % renderer.vk.sc.img_count;
}
static VkCommandBuffer GetFrameCmdBuf()
{
return renderer.vk.frame.buffers[GetFrameIndex()];
}
static VkFence *GetFrameRenderFence()
{
return &renderer.vk.frame.render_fences[GetFrameIndex()];
}
static VkSemaphore GetFrameRenderSem()
{
return renderer.vk.frame.render_sems[GetFrameIndex()];
}
static VkSemaphore GetFrameSwapSem()
{
return renderer.vk.frame.swapchain_sems[GetFrameIndex()];
}
b32 _BeginFrame()
{
b32 success = true;
VkResult result;
u8 f_ix = renderer.frame_state.frame_cnt % FRAME_OVERLAP;
VkDevice device = renderer.vk.device;
VkCommandBuffer cmd = renderer.vk.frame.buffers[f_ix];
VkFence fence = renderer.vk.frame.render_fences[f_ix];
VkSemaphore sc_sem = renderer.vk.frame.swapchain_sems[f_ix];
VkSemaphore rndr_sem = renderer.vk.frame.render_sems[f_ix];
VkSwapchainKHR swapchain = renderer.vk.swapchain;
VkCommandBuffer cmd = GetFrameCmdBuf();
VkFence *fence = GetFrameRenderFence();
VkSemaphore sc_sem = GetFrameSwapSem();
VkSemaphore rndr_sem = GetFrameRenderSem();
// TODO(MA): make this work with VK_PRESENT_MODE_MAILBOX_KHR and remove assignment of present mode to FIFO
result = vkWaitForFences(device, 1, &fence, VK_TRUE, 1000000000);
result = vkWaitForFences(device, 1, fence, VK_TRUE, 1000000000);
if (result != VK_SUCCESS)
{
Printf("vkWaitForFences failure: %s", VkResultStr(result));
@ -39,20 +62,22 @@ b32 _BeginFrame()
if (success)
{
result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix);
result = vkResetFences(device, 1, fence);
if (result != VK_SUCCESS)
{
Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result));
Printf("vkResetFences failure: %s", VkResultStr(result));
success = false;
}
}
if (success)
{
result = vkResetFences(device, 1, &fence);
if (result != VK_SUCCESS)
result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
ResizeSwapchain();
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
Printf("vkResetFences failure: %s", VkResultStr(result));
Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result));
success = false;
}
}
@ -67,6 +92,7 @@ b32 _BeginFrame()
}
}
if (success)
{
VkCommandBufferBeginInfo cmd_info = {
@ -85,9 +111,14 @@ b32 _BeginFrame()
return success;
}
void _ClearScreen()
{
}
void _DrawTriangle()
{
u8 f_ix = renderer.frame_state.frame_cnt % FRAME_OVERLAP;
u32 f_ix = renderer.frame_state.frame_cnt % renderer.vk.sc.img_count;
VkCommandBuffer cmd = renderer.vk.frame.buffers[f_ix];
@ -106,7 +137,7 @@ void _DrawTriangle()
.sType = STYPE(RENDERING_ATTACHMENT_INFO),
.imageView = renderer.vk.sc.depth_img.view,
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
};
@ -146,7 +177,7 @@ void _DrawTriangle()
vkCmdSetScissor(cmd, 0, 1, &scissor);
vkCmdDrawIndexed(cmd, 3, 1, 0, 0, 0);
vkCmdDraw(cmd, 3, 1, 0, 0);
// TODO(MA): maybe store current image layout between functions
}
@ -156,26 +187,27 @@ b32 _FinishFrame()
b32 success = true;
VkResult result;
u32 f_ix = renderer.frame_state.frame_cnt % FRAME_OVERLAP;
u32 f_ix = renderer.frame_state.frame_cnt % renderer.vk.sc.img_count;
VkCommandBuffer cmd = renderer.vk.frame.buffers[f_ix];
VkSemaphore sc_sem = renderer.vk.frame.swapchain_sems[f_ix];
VkSemaphore rndr_sem = renderer.vk.frame.render_sems[f_ix];
VkFence fence = renderer.vk.frame.render_fences[f_ix];
VkImage curr_img = renderer.vk.sc.imgs[renderer.frame_state.img_ix];
vkCmdEndRendering(cmd);
TransitionImage(cmd, renderer.vk.sc.draw_img.img, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
TransitionImage(cmd, renderer.vk.sc.imgs[f_ix], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
TransitionImage(cmd, curr_img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkExtent2D extent = {
.width = renderer.vk.sc.extent.width,
.height = renderer.vk.sc.extent.height,
};
CopyImageToImage(cmd, renderer.vk.sc.draw_img.img, renderer.vk.sc.imgs[f_ix], extent, extent);
CopyImageToImage(cmd, renderer.vk.sc.draw_img.img, curr_img, extent, extent);
TransitionImage(cmd, renderer.vk.sc.imgs[f_ix], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
TransitionImage(cmd, curr_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
result = vkEndCommandBuffer(cmd);
if (result != VK_SUCCESS)
@ -231,20 +263,34 @@ b32 _FinishFrame()
.swapchainCount = 1,
.pWaitSemaphores = &rndr_sem,
.waitSemaphoreCount = 1,
.pImageIndices = &f_ix,
.pImageIndices = &renderer.frame_state.img_ix,
};
result = vkQueuePresentKHR(renderer.vk.queues.graphics_queue, &present_info);
if (result != VK_SUCCESS)
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || renderer.resize_requested)
{
renderer.resize_requested = false;
ResizeSwapchain();
}
else if (result != VK_SUCCESS)
{
Printf("vkQueuePresentKHR failure: %s", VkResultStr(result));
success = false;
}
}
renderer.frame_state.frame_cnt++;
return success;
}
static void _SetRenderResolution(u32 x, u32 y)
{
renderer.vk.sc.extent.width = x;
renderer.vk.sc.extent.height = y;
renderer.resize_requested = true;
}
/**
* BACK END API END
@ -254,6 +300,21 @@ b32 _FinishFrame()
* INTERNAL API
*/
// Swapchain
static void ResizeSwapchain()
{
vkDeviceWaitIdle(renderer.vk.device);
DestroySwapchain();
DestroyDrawImages();
Assert(CreateSwapchain(), "Unable to recreate swapchain");
Assert(CreateDrawImages(), "Unable to recreate draw images");
renderer.resize_requested = false;
}
// UTIL
static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext)
@ -285,7 +346,7 @@ static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkEx
VkBlitImageInfo2 blit_info = {
.sType = STYPE(BLIT_IMAGE_INFO_2),
.srcImage = src,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstImage = dst,
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.filter = VK_FILTER_LINEAR,
@ -350,9 +411,10 @@ static b32 InitVulkan(Arena *arena)
Assert(CreateDevice(), "Unable to create device");
Assert(CreateVmaAllocator(), "Unable to create VMA allocator");
Assert(CreateSwapchain(), "Unable to initialize swapchain and draw images");
Assert(CreateDrawImages(), "Unable to create draw images");
Assert(CreateFrameStructures(), "Unable to create frame structures");
Assert(CreateImmediateStructures(), "Unable to create immediate structures");
Assert(CreateSwapchain(), "Unable to initialize swapchain and draw images");
Assert(CreateDescriptors(), "Unable to initialize descriptors.");
Assert(CreatePipelines(), "Unable to initialize pipelines.");
@ -661,6 +723,8 @@ static b32 InitVkDeviceFunctions() {
INIT_DEV_FN(vkDestroyDescriptorSetLayout);
INIT_DEV_FN(vkDestroyShaderModule);
INIT_DEV_FN(vkQueuePresentKHR);
INIT_DEV_FN(vkCmdDraw);
INIT_DEV_FN(vkDeviceWaitIdle);
return true;
}
@ -727,9 +791,17 @@ static b32 CreateFrameStructures()
{
b32 success = true;
FrameStructures *data = &renderer.vk.frame;
u32 img_count = renderer.vk.sc.img_count;
pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics;
for (u32 i = 0; i < FRAME_OVERLAP; i++)
renderer.vk.frame.pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * img_count);
renderer.vk.frame.buffers = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * img_count);
renderer.vk.frame.swapchain_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * img_count);
for (u32 i = 0; i < renderer.vk.sc.img_count; i++)
{
VkResult result;
VkDevice device = renderer.vk.device;
@ -795,11 +867,14 @@ static b32 CreateSwapchain()
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities);
// Maybe reconsider handling window sizing within here and only handle it from events themselves
// causes issues when the window size is out of sync with the current swapchain
VkExtent2D extent;
WindowSize win_size = GetWindowSize();
u32 width = renderer.vk.sc.extent.width;
u32 height = renderer.vk.sc.extent.height;
extent.width = u32Clamp((u32)win_size.w, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = u32Clamp((u32)win_size.h, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
extent.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
u32 format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL);
@ -827,11 +902,6 @@ static b32 CreateSwapchain()
if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR)
present_mode = VK_PRESENT_MODE_FIFO_KHR;
//
// TODO(MA): REMOVE THIS LATER
present_mode = VK_PRESENT_MODE_FIFO_KHR;
swapchain_create_info.minImageCount = capabilities.minImageCount + 1;
swapchain_create_info.surface = surface;
swapchain_create_info.imageFormat = renderer.vk.sc.format;
@ -848,7 +918,7 @@ static b32 CreateSwapchain()
u32 image_count;
vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, NULL);
VkImage *sc_images = ArenaAlloc(renderer.perm_arena, sizeof(VkImage) * image_count);
VkImageView *sc_views = ArenaAlloc(renderer.perm_arena, sizeof(VkImage) * image_count);
VkImageView *sc_views = ArenaAlloc(renderer.perm_arena, sizeof(VkImageView) * image_count);
vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, sc_images);
for (u32 i = 0; i < image_count; i++)
@ -864,13 +934,21 @@ static b32 CreateSwapchain()
renderer.vk.sc.imgs = sc_images;
renderer.vk.sc.views = sc_views;
renderer.vk.sc.img_count = image_count;
renderer.vk.sc.extent.width = extent.width;
renderer.vk.sc.extent.height = extent.height;
renderer.vk.sc.extent.depth = 1;
return success;
}
static b32 CreateDrawImages()
{
b32 success = true;
VkResult result;
VkFormat image_format = GetImageFormat();
VkExtent3D extent_3d = {
.width = extent.width,
.height = extent.height,
.depth = 1,
};
VkExtent3D extent = renderer.vk.sc.extent;
VkDevice device = renderer.vk.device;
VmaAllocationCreateInfo alloc_create_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
@ -879,7 +957,7 @@ static b32 CreateSwapchain()
// Draw Image
draw_image_create_info.format = image_format;
draw_image_create_info.extent = extent_3d;
draw_image_create_info.extent = extent;
result = vmaCreateImage(renderer.vk.alloc, &draw_image_create_info,
&alloc_create_info, &renderer.vk.sc.draw_img.img, &renderer.vk.sc.draw_img.alloc, NULL);
@ -895,7 +973,7 @@ static b32 CreateSwapchain()
success = false;
// Depth Image
depth_image_create_info.extent = extent_3d;
depth_image_create_info.extent = extent;
result = vmaCreateImage(renderer.vk.alloc, &depth_image_create_info,
&alloc_create_info, &renderer.vk.sc.depth_img.img, &renderer.vk.sc.depth_img.alloc, NULL);
@ -909,7 +987,7 @@ static b32 CreateSwapchain()
success = false;
// Setting values
renderer.vk.sc.extent = extent_3d;
renderer.vk.sc.extent = extent;
renderer.vk.sc.depth_img.fmt = depth_image_create_info.format;
renderer.vk.sc.draw_img.fmt = draw_image_create_info.format;
@ -1058,6 +1136,29 @@ static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module)
return success;
}
static void DestroySwapchain()
{
for (u32 i = 0; i < renderer.vk.sc.img_count; i++)
{
vkDestroyImageView(renderer.vk.device, renderer.vk.sc.views[i], NULL);
}
vkDestroySwapchainKHR(renderer.vk.device, renderer.vk.swapchain, NULL);
}
static void DestroyDrawImages()
{
SwapchainStructures *sc = &renderer.vk.sc;
VkDevice device = renderer.vk.device;
VmaAllocator vma_alloc = renderer.vk.alloc;
vkDestroyImageView(device, sc->draw_img.view, NULL);
vmaDestroyImage(vma_alloc, sc->draw_img.img, sc->draw_img.alloc);
vkDestroyImageView(device, sc->depth_img.view, NULL);
vmaDestroyImage(vma_alloc, sc->depth_img.img, sc->depth_img.alloc);
}
static void DestroyVulkan()
{
VkDevice device = renderer.vk.device;
@ -1069,6 +1170,8 @@ static void DestroyVulkan()
VkSwapchainKHR swapchain = renderer.vk.swapchain;
PipelineStructures pipe = renderer.vk.pipe;
vkDeviceWaitIdle(device);
for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++)
vkDestroyPipeline(device, pipe.pipelines[i], NULL);
@ -1079,24 +1182,15 @@ static void DestroyVulkan()
vkDestroyDescriptorPool(device, pipe.pool, NULL);
vkDestroyImageView(device, sc.draw_img.view, NULL);
vmaDestroyImage(vma_alloc, sc.draw_img.img, sc.draw_img.alloc);
DestroyDrawImages();
vkDestroyImageView(device, sc.depth_img.view, NULL);
vmaDestroyImage(vma_alloc, sc.depth_img.img, sc.depth_img.alloc);
for (u32 i = 0; i < sc.img_count; i++)
{
vkDestroyImageView(device, sc.views[i], NULL);
}
vkDestroySwapchainKHR(device, swapchain, NULL);
DestroySwapchain();
vkDestroyFence(device, imm.fence, NULL);
vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer);
vkDestroyCommandPool(device, imm.pool, NULL);
for (u32 i = 0; i < FRAME_OVERLAP; i++)
for (u32 i = 0; i < sc.img_count; i++)
{
vkDestroySemaphore(device, data.render_sems[i], NULL);
vkDestroySemaphore(device, data.swapchain_sems[i], NULL);

View File

@ -118,6 +118,8 @@ VK_DECLARE(vkFreeCommandBuffers);
VK_DECLARE(vkDestroyDescriptorSetLayout);
VK_DECLARE(vkDestroyShaderModule);
VK_DECLARE(vkQueuePresentKHR);
VK_DECLARE(vkCmdDraw);
VK_DECLARE(vkDeviceWaitIdle);
// Vulkan Functions END
@ -170,11 +172,11 @@ typedef struct
typedef struct
{
VkCommandPool pools[FRAME_OVERLAP];
VkCommandBuffer buffers[FRAME_OVERLAP];
VkSemaphore swapchain_sems[FRAME_OVERLAP];
VkSemaphore render_sems[FRAME_OVERLAP];
VkFence render_fences[FRAME_OVERLAP];
VkCommandPool *pools;
VkCommandBuffer *buffers;
VkSemaphore *swapchain_sems;
VkSemaphore *render_sems;
VkFence *render_fences;
} FrameStructures;
typedef struct
@ -210,6 +212,8 @@ typedef struct {
typedef struct {
u32 img_ix;
u64 frame_cnt;
b8 comp_started;
b8 gfx_started;
} FrameState;
typedef struct {
@ -233,6 +237,7 @@ typedef struct {
typedef struct {
Vulkan_t vk;
FrameState frame_state;
b32 resize_requested;
Arena *arena;
Arena *perm_arena;
} Renderer_t;
@ -265,18 +270,33 @@ static b32 CreateVmaAllocator();
static b32 CreateFrameStructures();
static b32 CreateImmediateStructures();
static b32 CreateSwapchain();
static b32 CreateDrawImages();
static VkFormat GetImageFormat();
static b32 CreateDescriptors();
static b32 CreatePipelines();
static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module);
// Util
static VkCommandBuffer GetFrameCmdBuf();
static VkFence *GetFrameRenderFence();
static VkSemaphore GetFrameRenderSem();
static VkSemaphore GetFrameSwapSem();
static u32 GetFrameIndex();
// Destroy
static void DestroyVulkan();
static void DestroySwapchain();
static void DestroyDrawImages();
// Util
static void TransitionImage(VkCommandBuffer cmd, VkImage img, VkImageLayout curr, VkImageLayout new);
static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext);
// Swapchain
static VkExtent2D SelectSwapchainExtent(VkSurfaceCapabilitiesKHR *capabilities);
static VkSurfaceFormatKHR SelectSwapchainFormat(VkSurfaceFormatKHR *formats);
static void ResizeSwapchain();
// Renderer Functions Declarations END
#include "vulkan_config.c"
@ -322,3 +342,4 @@ void _DestroyRenderer();
static b32 _BeginFrame();
static void _DrawTriangle();
static b32 _FinishFrame();
static void _SetRenderSize(u32 x, u32 y);