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 "util.c"
#include "arena.c" #include "arena.c"
#include "render.c" #include "render.c"
#include "game.c"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
InitPlatform(); Run();
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;
} }

View File

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

View File

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

View File

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

View File

@ -140,7 +140,8 @@ b32 _CreateWindow()
{ {
Window *window = &linux_window; Window *window = &linux_window;
window->connection = xcb_connect(NULL, NULL); int screen_index;
window->connection = xcb_connect(NULL, &screen_index);
if (!window->connection) { if (!window->connection) {
return false; return false;
@ -159,23 +160,23 @@ b32 _CreateWindow()
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
XCB_EVENT_MASK_STRUCTURE_NOTIFY|
XCB_EVENT_MASK_RESIZE_REDIRECT;
const int val_win[] = {event_mask, 0}; const int val_win[] = {screen->black_pixel, event_mask};
const int val_mask = XCB_CW_EVENT_MASK; const int val_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
window->window = xcb_generate_id(window->connection); window->window = xcb_generate_id(window->connection);
cookie = xcb_create_window_checked( cookie = xcb_create_window(
window->connection, window->connection,
XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT,
window->window, window->window,
screen->root, screen->root,
0, 0, // x/y pos 0, // x pos
window->w, window->h, 0, // y pos
10, window->w, // width
window->h, // height
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual, screen->root_visual,
val_mask, 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_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_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( cookie = xcb_change_property_checked(
window->connection, window->connection,
XCB_PROP_MODE_REPLACE, XCB_PROP_MODE_REPLACE,
@ -219,6 +224,20 @@ b32 _CreateWindow()
XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event."); XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event.");
window->close_event = r_close->atom; 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; return true;
} }
@ -236,6 +255,16 @@ WindowSize _GetWindowSize()
} }
b32 _GetWindowEvent(WindowEvent *event) 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"); Assert(event != NULL, "GetWindowEvent received a null pointer");
@ -243,8 +272,13 @@ b32 _GetWindowEvent(WindowEvent *event)
b32 no_event = false; b32 no_event = false;
do 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) if (e != NULL)
{ {
switch (e->response_type & ~0x80) switch (e->response_type & ~0x80)
@ -256,34 +290,55 @@ b32 _GetWindowEvent(WindowEvent *event)
event->type = EVENT_QUIT; event->type = EVENT_QUIT;
valid_event = true; valid_event = true;
} }
if (msg->data.data32[0] == linux_window.minimize_event)
{
event->type = EVENT_MINIMIZE;
valid_event = true;
linux_window.w = 0;
linux_window.h = 0;
}
break; break;
case XCB_RESIZE_REQUEST: 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)
{
Printfln("inner w %d h %d", configure_event->width, configure_event->height);
event->type = EVENT_RESIZE; event->type = EVENT_RESIZE;
valid_event = true; valid_event = true;
xcb_resize_request_event_t *resize = (xcb_resize_request_event_t *)e; event->resize.w = configure_event->width;
event->resize.h = configure_event->height;
if (resize->width > 0) linux_window.w = configure_event->width;
{ linux_window.h = configure_event->height;
linux_window.w = resize->width;
event->resize.w = resize->width;
}
if (resize->height > 0)
{
linux_window.h = resize->height;
event->resize.h = resize->height;
} }
break; break;
default: default:
break; break;
} }
free(e);
} }
else else
{ {
break; break;
} }
} while(!valid_event);
} while(!valid_event && !wait_for_event);
return valid_event; return valid_event;
} }

View File

@ -62,6 +62,7 @@ typedef size_t usize;
typedef float f32; typedef float f32;
typedef double f64; typedef double f64;
typedef uint8_t b8;
typedef uint32_t b32; typedef uint32_t b32;
typedef void * rawptr; typedef void * rawptr;
@ -70,6 +71,7 @@ typedef struct {
xcb_connection_t *connection; xcb_connection_t *connection;
xcb_window_t window; xcb_window_t window;
xcb_atom_t close_event; xcb_atom_t close_event;
xcb_atom_t minimize_event;
u16 w, h; u16 w, h;
} Window; } Window;
@ -81,6 +83,36 @@ typedef struct {
void *fn; void *fn;
} Function; } 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 // Platform API
// Init Functions // Init Functions
@ -103,7 +135,9 @@ i32 _EPrintf(const char *fmt, va_list arg);
b32 _CreateWindow(); b32 _CreateWindow();
Window *_GetWindow(); Window *_GetWindow();
b32 _GetWindowEvent(WindowEvent *event); b32 _GetWindowEvent(WindowEvent *event);
void _WaitForWindowEvent(WindowEvent *event);
WindowSize _GetWindowSize(); WindowSize _GetWindowSize();
b32 HandleWindowEvent(WindowEvent *event, b32 wait_for_event);
// Platform API END // Platform API END

View File

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

View File

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

View File

@ -15,22 +15,45 @@ void _DestroyRenderer()
DestroyVulkan(); 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 _BeginFrame()
{ {
b32 success = true; b32 success = true;
VkResult result; VkResult result;
u8 f_ix = renderer.frame_state.frame_cnt % FRAME_OVERLAP;
VkDevice device = renderer.vk.device; 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; 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 // 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) if (result != VK_SUCCESS)
{ {
Printf("vkWaitForFences failure: %s", VkResultStr(result)); Printf("vkWaitForFences failure: %s", VkResultStr(result));
@ -39,20 +62,22 @@ b32 _BeginFrame()
if (success) if (success)
{ {
result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix); result = vkResetFences(device, 1, fence);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result)); Printf("vkResetFences failure: %s", VkResultStr(result));
success = false; success = false;
} }
} }
if (success) if (success)
{ {
result = vkResetFences(device, 1, &fence); result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix);
if (result != VK_SUCCESS) 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; success = false;
} }
} }
@ -67,6 +92,7 @@ b32 _BeginFrame()
} }
} }
if (success) if (success)
{ {
VkCommandBufferBeginInfo cmd_info = { VkCommandBufferBeginInfo cmd_info = {
@ -85,9 +111,14 @@ b32 _BeginFrame()
return success; return success;
} }
void _ClearScreen()
{
}
void _DrawTriangle() 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]; VkCommandBuffer cmd = renderer.vk.frame.buffers[f_ix];
@ -106,7 +137,7 @@ void _DrawTriangle()
.sType = STYPE(RENDERING_ATTACHMENT_INFO), .sType = STYPE(RENDERING_ATTACHMENT_INFO),
.imageView = renderer.vk.sc.depth_img.view, .imageView = renderer.vk.sc.depth_img.view,
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, .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, .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
}; };
@ -146,7 +177,7 @@ void _DrawTriangle()
vkCmdSetScissor(cmd, 0, 1, &scissor); 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 // TODO(MA): maybe store current image layout between functions
} }
@ -156,26 +187,27 @@ b32 _FinishFrame()
b32 success = true; b32 success = true;
VkResult result; 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]; VkCommandBuffer cmd = renderer.vk.frame.buffers[f_ix];
VkSemaphore sc_sem = renderer.vk.frame.swapchain_sems[f_ix]; VkSemaphore sc_sem = renderer.vk.frame.swapchain_sems[f_ix];
VkSemaphore rndr_sem = renderer.vk.frame.render_sems[f_ix]; VkSemaphore rndr_sem = renderer.vk.frame.render_sems[f_ix];
VkFence fence = renderer.vk.frame.render_fences[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); 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.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 = { VkExtent2D extent = {
.width = renderer.vk.sc.extent.width, .width = renderer.vk.sc.extent.width,
.height = renderer.vk.sc.extent.height, .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); result = vkEndCommandBuffer(cmd);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
@ -231,20 +263,34 @@ b32 _FinishFrame()
.swapchainCount = 1, .swapchainCount = 1,
.pWaitSemaphores = &rndr_sem, .pWaitSemaphores = &rndr_sem,
.waitSemaphoreCount = 1, .waitSemaphoreCount = 1,
.pImageIndices = &f_ix, .pImageIndices = &renderer.frame_state.img_ix,
}; };
result = vkQueuePresentKHR(renderer.vk.queues.graphics_queue, &present_info); 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)); Printf("vkQueuePresentKHR failure: %s", VkResultStr(result));
success = false; success = false;
} }
} }
renderer.frame_state.frame_cnt++;
return success; 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 * BACK END API END
@ -254,6 +300,21 @@ b32 _FinishFrame()
* INTERNAL API * 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 // UTIL
static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext) 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 = { VkBlitImageInfo2 blit_info = {
.sType = STYPE(BLIT_IMAGE_INFO_2), .sType = STYPE(BLIT_IMAGE_INFO_2),
.srcImage = src, .srcImage = src,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstImage = dst, .dstImage = dst,
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.filter = VK_FILTER_LINEAR, .filter = VK_FILTER_LINEAR,
@ -350,9 +411,10 @@ static b32 InitVulkan(Arena *arena)
Assert(CreateDevice(), "Unable to create device"); Assert(CreateDevice(), "Unable to create device");
Assert(CreateVmaAllocator(), "Unable to create VMA allocator"); 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(CreateFrameStructures(), "Unable to create frame structures");
Assert(CreateImmediateStructures(), "Unable to create immediate structures"); Assert(CreateImmediateStructures(), "Unable to create immediate structures");
Assert(CreateSwapchain(), "Unable to initialize swapchain and draw images");
Assert(CreateDescriptors(), "Unable to initialize descriptors."); Assert(CreateDescriptors(), "Unable to initialize descriptors.");
Assert(CreatePipelines(), "Unable to initialize pipelines."); Assert(CreatePipelines(), "Unable to initialize pipelines.");
@ -661,6 +723,8 @@ static b32 InitVkDeviceFunctions() {
INIT_DEV_FN(vkDestroyDescriptorSetLayout); INIT_DEV_FN(vkDestroyDescriptorSetLayout);
INIT_DEV_FN(vkDestroyShaderModule); INIT_DEV_FN(vkDestroyShaderModule);
INIT_DEV_FN(vkQueuePresentKHR); INIT_DEV_FN(vkQueuePresentKHR);
INIT_DEV_FN(vkCmdDraw);
INIT_DEV_FN(vkDeviceWaitIdle);
return true; return true;
} }
@ -727,9 +791,17 @@ static b32 CreateFrameStructures()
{ {
b32 success = true; b32 success = true;
FrameStructures *data = &renderer.vk.frame; FrameStructures *data = &renderer.vk.frame;
u32 img_count = renderer.vk.sc.img_count;
pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics; 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; VkResult result;
VkDevice device = renderer.vk.device; VkDevice device = renderer.vk.device;
@ -795,11 +867,14 @@ static b32 CreateSwapchain()
VkSurfaceCapabilitiesKHR capabilities; VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &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; 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.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = u32Clamp((u32)win_size.h, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
u32 format_count; u32 format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL); vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL);
@ -827,11 +902,6 @@ static b32 CreateSwapchain()
if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR) if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR)
present_mode = VK_PRESENT_MODE_FIFO_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.minImageCount = capabilities.minImageCount + 1;
swapchain_create_info.surface = surface; swapchain_create_info.surface = surface;
swapchain_create_info.imageFormat = renderer.vk.sc.format; swapchain_create_info.imageFormat = renderer.vk.sc.format;
@ -848,7 +918,7 @@ static b32 CreateSwapchain()
u32 image_count; u32 image_count;
vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, NULL); vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, NULL);
VkImage *sc_images = ArenaAlloc(renderer.perm_arena, sizeof(VkImage) * image_count); 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); vkGetSwapchainImagesKHR(device, renderer.vk.swapchain, &image_count, sc_images);
for (u32 i = 0; i < image_count; i++) for (u32 i = 0; i < image_count; i++)
@ -864,13 +934,21 @@ static b32 CreateSwapchain()
renderer.vk.sc.imgs = sc_images; renderer.vk.sc.imgs = sc_images;
renderer.vk.sc.views = sc_views; renderer.vk.sc.views = sc_views;
renderer.vk.sc.img_count = image_count; 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(); VkFormat image_format = GetImageFormat();
VkExtent3D extent_3d = { VkExtent3D extent = renderer.vk.sc.extent;
.width = extent.width, VkDevice device = renderer.vk.device;
.height = extent.height,
.depth = 1,
};
VmaAllocationCreateInfo alloc_create_info = { VmaAllocationCreateInfo alloc_create_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY, .usage = VMA_MEMORY_USAGE_GPU_ONLY,
@ -879,7 +957,7 @@ static b32 CreateSwapchain()
// Draw Image // Draw Image
draw_image_create_info.format = image_format; 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, 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); &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; success = false;
// Depth Image // Depth Image
depth_image_create_info.extent = extent_3d; depth_image_create_info.extent = extent;
result = vmaCreateImage(renderer.vk.alloc, &depth_image_create_info, 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); &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; success = false;
// Setting values // 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.depth_img.fmt = depth_image_create_info.format;
renderer.vk.sc.draw_img.fmt = draw_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; 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() static void DestroyVulkan()
{ {
VkDevice device = renderer.vk.device; VkDevice device = renderer.vk.device;
@ -1069,6 +1170,8 @@ static void DestroyVulkan()
VkSwapchainKHR swapchain = renderer.vk.swapchain; VkSwapchainKHR swapchain = renderer.vk.swapchain;
PipelineStructures pipe = renderer.vk.pipe; PipelineStructures pipe = renderer.vk.pipe;
vkDeviceWaitIdle(device);
for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++) for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++)
vkDestroyPipeline(device, pipe.pipelines[i], NULL); vkDestroyPipeline(device, pipe.pipelines[i], NULL);
@ -1079,24 +1182,15 @@ static void DestroyVulkan()
vkDestroyDescriptorPool(device, pipe.pool, NULL); vkDestroyDescriptorPool(device, pipe.pool, NULL);
vkDestroyImageView(device, sc.draw_img.view, NULL); DestroyDrawImages();
vmaDestroyImage(vma_alloc, sc.draw_img.img, sc.draw_img.alloc);
vkDestroyImageView(device, sc.depth_img.view, NULL); DestroySwapchain();
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);
vkDestroyFence(device, imm.fence, NULL); vkDestroyFence(device, imm.fence, NULL);
vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer); vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer);
vkDestroyCommandPool(device, imm.pool, NULL); 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.render_sems[i], NULL);
vkDestroySemaphore(device, data.swapchain_sems[i], NULL); vkDestroySemaphore(device, data.swapchain_sems[i], NULL);

View File

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