From b20395fc1c6409edb19b9584c7e9b7c1bea08e3f Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Sat, 30 Nov 2024 21:08:25 -0600 Subject: [PATCH] Rework engine --- CMakeLists.txt | 1 + bootstrap/bloat-buster/bb_core.c | 347 ++-- bootstrap/bloat-buster/main.c | 4 +- bootstrap/include/bloat-buster/bb_core.h | 2 +- bootstrap/include/std/base.h | 5 + bootstrap/include/std/font_provider.h | 7 +- bootstrap/include/std/graphics.h | 37 +- bootstrap/include/std/render.h | 99 +- bootstrap/include/std/ui_core.h | 5 + bootstrap/shaders/font.frag | 2 +- bootstrap/std/font_provider.c | 10 +- bootstrap/std/graphics.c | 87 +- bootstrap/std/image_loader.c | 2 +- bootstrap/std/render.c | 1989 ++++++++++++---------- bootstrap/std/shader_compilation.c | 4 + bootstrap/std/ui_core.c | 3 + 16 files changed, 1408 insertions(+), 1196 deletions(-) create mode 100644 bootstrap/include/std/ui_core.h create mode 100644 bootstrap/std/ui_core.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 89b4849..0f3dbe8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,6 +226,7 @@ if (NOT BB_IS_CI) "bootstrap/std/font_provider.c" "bootstrap/std/graphics.c" "bootstrap/std/render.c" + "bootstrap/std/ui_core.c" ) target_include_directories(${COMPILER_NAME} PRIVATE dependencies/stb) diff --git a/bootstrap/bloat-buster/bb_core.c b/bootstrap/bloat-buster/bb_core.c index e18bfcb..9e9a626 100644 --- a/bootstrap/bloat-buster/bb_core.c +++ b/bootstrap/bloat-buster/bb_core.c @@ -11,7 +11,7 @@ STRUCT(Vec4) { f32 v[4]; -}; +}__attribute__((aligned(16))); STRUCT(Vertex) { @@ -25,12 +25,23 @@ STRUCT(Vertex) }; decl_vb(Vertex); -STRUCT(GPUDrawPushConstants) +fn TextureIndex white_texture_create(Arena* arena, Renderer* renderer) { - u64 vertex_buffer; - f32 width; - f32 height; -}; + u32 white_texture_width = 1024; + u32 white_texture_height = white_texture_width; + auto* white_texture_buffer = arena_allocate(arena, u32, white_texture_width * white_texture_height); + memset(white_texture_buffer, 0xff, white_texture_width * white_texture_height * sizeof(u32)); + + auto white_texture = renderer_texture_create(renderer, (TextureMemory) { + .pointer = white_texture_buffer, + .width = white_texture_width, + .height = white_texture_height, + .depth = 1, + .format = TEXTURE_FORMAT_R8G8B8A8_SRGB, + }); + + return white_texture; +} fn void draw_string(Renderer* renderer, VirtualBuffer(Vertex)* vertices, VirtualBuffer(u32)* indices, u32 width, u32 height, Vec4 color, String string, TextureAtlas texture_atlas, u32 texture_index) { @@ -49,8 +60,6 @@ fn void draw_string(Renderer* renderer, VirtualBuffer(Vertex)* vertices, Virtual auto uv_width = character->width; auto uv_height = character->height; - print("UV x: {u32}. UV y: {u32}\n", uv_x, uv_y); - *vb_add(vertices, 1) = (Vertex) { .x = pos_x, .y = pos_y, @@ -97,11 +106,27 @@ fn void draw_string(Renderer* renderer, VirtualBuffer(Vertex)* vertices, Virtual } } -void run_app(Arena* arena) +STRUCT(BBWindow) { + OSWindow os; + RenderWindow* render; +}; + +STRUCT(BBGUIState) +{ + Arena* arena; + BBWindow* first; + BBWindow* last; +}; +global_variable BBGUIState state; + +void run_app() +{ + state.arena = arena_init(MB(512), MB(2), MB(2)); + u8 use_x11 = 1; - graphics_init(use_x11); - GraphicsWindow* window = graphics_window_create((GraphicsWindowCreate) { + os_graphics_init(use_x11); + OSWindow os_window = os_window_create((OSWindowCreate) { .name = strlit("Bloat Buster"), .size = { .width = 1024, @@ -109,67 +134,13 @@ void run_app(Arena* arena) }, }); - if (!window) + if (!os_window) { failed_execution(); } - auto initial_window_size = graphics_window_size_get(window); - - Renderer* renderer = renderer_initialize(); - RenderWindow* render_window = renderer_window_initialize(renderer, window); - - String shader_source_paths[] = { - strlit("bootstrap/shaders/font.vert"), - strlit("bootstrap/shaders/font.frag"), - }; - PipelineLayoutCreate pipeline_layouts[] = { - (PipelineLayoutCreate) { - .push_constant_ranges = array_to_slice(((PushConstantRange[]){ - (PushConstantRange) { - .offset = 0, - .size = sizeof(GPUDrawPushConstants), - .stage = SHADER_STAGE_VERTEX, - }, - })), - .descriptor_set_layouts = array_to_slice(((DescriptorSetLayout[]){ - (DescriptorSetLayout) { - .bindings = array_to_slice(((DescriptorSetLayoutBinding[]) { - { - .binding = 0, - .type = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, - .stage = SHADER_STAGE_FRAGMENT, - .count = 2, - }, - })), - }, - })), - }, - }; - PipelineCreate pipeline_create[] = { - (PipelineCreate) { - .shader_source_indices = array_to_slice(((u16[]){0, 1})), - .layout_index = 0, - }, - }; - auto pipeline_index = renderer_graphics_pipelines_create(renderer, arena, (GraphicsPipelinesCreate){ - .layouts = array_to_slice(pipeline_layouts), - .pipelines = array_to_slice(pipeline_create), - .shader_sources = array_to_slice(shader_source_paths), - }); - - u32 white_texture_width = 1024; - u32 white_texture_height = white_texture_width; - auto* white_texture_buffer = arena_allocate(arena, u32, white_texture_width * white_texture_height / sizeof(u32)); - memset(white_texture_buffer, 0xff, white_texture_width * white_texture_height); - - auto white_texture = renderer_texture_create(renderer, (TextureMemory) { - .pointer = white_texture_buffer, - .width = white_texture_width, - .height = white_texture_height, - .depth = 1, - .format = R8G8B8A8_SRGB, - }); + Renderer* renderer = renderer_initialize(state.arena); + RenderWindow* render_window = renderer_window_initialize(renderer, os_window); auto font_path = #ifdef _WIN32 @@ -179,122 +150,154 @@ strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf") #else #endif ; - auto texture_atlas = font_create_texture_atlas(arena, (TextureAtlasCreate) { - .font_path = font_path, - .text_height = 72, - }); - auto texture_atlas_image = renderer_texture_create(renderer, (TextureMemory) { - .pointer = texture_atlas.pointer, - .width = texture_atlas.width, - .height = texture_atlas.height, - .depth = 1, - .format = R8G8B8A8_SRGB, - }); - DescriptorSetUpdate descriptor_set_updates[] = { - { - .set = { .value = 0 }, - .type = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, - .binding = 0, - .descriptor_count = 2, - .textures = { - [0] = white_texture, - [1] = texture_atlas_image, - }, - }, - }; - renderer_update_pipeline_resources(renderer, pipeline_index, (Slice(DescriptorSetUpdate)) array_to_slice(descriptor_set_updates)); - - VirtualBuffer(Vertex) vertices = {}; - VirtualBuffer(u32) indices = {}; - - Vec4 color = {1, 1, 1, 1}; - static_assert(sizeof(color) == 4 * sizeof(float)); - - u32 texture_index = 1; - draw_string(renderer, &vertices, &indices, initial_window_size.width, initial_window_size.height, color, strlit("He"), texture_atlas, texture_index); - - auto vertex_buffer_size = sizeof(*vertices.pointer) * vertices.length; - auto index_buffer_size = sizeof(*indices.pointer) * indices.length; - - auto vertex_buffer = renderer_buffer_create(renderer, vertex_buffer_size, BUFFER_TYPE_VERTEX); - auto vertex_buffer_device_address = buffer_address(vertex_buffer); - auto index_buffer = renderer_buffer_create(renderer, index_buffer_size, BUFFER_TYPE_INDEX); - auto staging_buffer = renderer_buffer_create(renderer, vertex_buffer_size + index_buffer_size, BUFFER_TYPE_STAGING); - - renderer_copy_to_host(staging_buffer, (Slice(HostBufferCopy)) array_to_slice(((HostBufferCopy[]) { - { - .destination_offset = 0, - .source = { - .pointer = (u8*)vertices.pointer, - .length = vertex_buffer_size, - }, - }, - { - .destination_offset = vertex_buffer_size, - .source = { - .pointer = (u8*)indices.pointer, - .length = index_buffer_size, - }, - }, - }))); - - renderer_copy_to_local(renderer, (Slice(LocalBufferCopy)) array_to_slice(((LocalBufferCopy[]) { - { - .destination = vertex_buffer, - .source = staging_buffer, - .regions = array_to_slice(((LocalBufferCopyRegion[]) { - { - .source_offset = 0, - .destination_offset = 0, - .size = vertex_buffer_size, - }, - })), - }, - { - .destination = index_buffer, - .source = staging_buffer, - .regions = array_to_slice(((LocalBufferCopyRegion[]) { - { - .source_offset = vertex_buffer_size, - .destination_offset = 0, - .size = index_buffer_size, - }, - })), - }, - }))); - - while (!graphics_window_should_close(window)) + window_rect_texture_update_begin(render_window); { - graphics_poll_events(); + auto white_texture = white_texture_create(state.arena, renderer); + auto monospace_font = font_texture_atlas_create(state.arena, renderer, (TextureAtlasCreate) { + .font_path = font_path, + .text_height = 180, + }); + auto proportional_font = font_texture_atlas_create(state.arena, renderer, (TextureAtlasCreate) { + .font_path = font_path, + .text_height = 180, + }); + window_queue_rect_texture_update(render_window, RECT_TEXTURE_SLOT_WHITE, white_texture); + renderer_queue_font_update(renderer, render_window, RENDER_FONT_TYPE_MONOSPACE, monospace_font); + renderer_queue_font_update(renderer, render_window, RENDER_FONT_TYPE_PROPORTIONAL, proportional_font); + } + window_rect_texture_update_end(renderer, render_window); - auto mouse_position = graphics_window_cursor_position_get(window); + // Vec4 color = {1, 1, 1, 1}; + // static_assert(sizeof(color) == 4 * sizeof(float)); + // + // u32 texture_index = 1; + // // draw_string(renderer, &vertices, &indices, window_size.width, window_size.height, color, strlit("He"), texture_atlas, texture_index); + // + // + // vb_copy_array(&vertices, box_vertices); + // vb_copy_array(&indices, box_indices); + // + // auto vertex_buffer_size = sizeof(*vertices.pointer) * vertices.length; + // auto index_buffer_size = sizeof(*indices.pointer) * indices.length; + // + // auto vertex_buffer = renderer_buffer_create(renderer, vertex_buffer_size, BUFFER_TYPE_VERTEX); + // auto vertex_buffer_device_address = buffer_address(vertex_buffer); + // auto index_buffer = renderer_buffer_create(renderer, index_buffer_size, BUFFER_TYPE_INDEX); + // auto staging_buffer = renderer_buffer_create(renderer, vertex_buffer_size + index_buffer_size, BUFFER_TYPE_STAGING); + // + // renderer_copy_to_host(staging_buffer, (Slice(HostBufferCopy)) array_to_slice(((HostBufferCopy[]) { + // { + // .destination_offset = 0, + // .source = { + // .pointer = (u8*)vertices.pointer, + // .length = vertex_buffer_size, + // }, + // }, + // { + // .destination_offset = vertex_buffer_size, + // .source = { + // .pointer = (u8*)indices.pointer, + // .length = index_buffer_size, + // }, + // }, + // }))); + // + // renderer_copy_to_local(renderer, (Slice(LocalBufferCopy)) array_to_slice(((LocalBufferCopy[]) { + // { + // .destination = vertex_buffer, + // .source = staging_buffer, + // .regions = array_to_slice(((LocalBufferCopyRegion[]) { + // { + // .source_offset = 0, + // .destination_offset = 0, + // .size = vertex_buffer_size, + // }, + // })), + // }, + // { + // .destination = index_buffer, + // .source = staging_buffer, + // .regions = array_to_slice(((LocalBufferCopyRegion[]) { + // { + // .source_offset = vertex_buffer_size, + // .destination_offset = 0, + // .size = index_buffer_size, + // }, + // })), + // }, + // }))); + + while (!os_window_should_close(os_window)) + { + os_poll_events(); + + auto mouse_position = os_window_cursor_position_get(os_window); // print("Mouse position: ({f64}, {f64})\n", mouse_position.x, mouse_position.y); - auto frame_window_size = renderer_window_frame_begin(renderer, render_window); + renderer_window_frame_begin(renderer, render_window); + u32 box_x = 200; + u32 box_y = 200; + u32 box_width = 100; + u32 box_height = 100; + Vec4 box_color = { 1, 0, 0, 1 }; - window_command_begin(render_window); - - window_bind_pipeline(render_window, pipeline_index); - window_bind_pipeline_descriptor_sets(render_window, pipeline_index); - window_bind_index_buffer(render_window, index_buffer, 0, INDEX_TYPE_U32); - GPUDrawPushConstants push_constants = { - .vertex_buffer = vertex_buffer_device_address, - .width = (f32)frame_window_size.width, - .height = (f32)frame_window_size.height, + Vertex box_vertices[] = { + { + .x = box_x, + .y = box_y, + .color = box_color, + }, + { + .x = box_x + box_width, + .y = box_y, + .color = box_color, + }, + { + .x = box_x, + .y = box_y + box_height, + .color = box_color, + }, + { + .x = box_x + box_width, + .y = box_y + box_height, + .color = box_color, + }, }; - window_push_constants(render_window, pipeline_index, (SliceP(void)) array_to_slice(((void*[]) {&push_constants}))); - window_render_begin(render_window); - { - window_draw_indexed(render_window, indices.length, 1, 0, 0, 0); - } - window_render_end(render_window); + u32 box_indices[] = { + 0, 1, 2, + 1, 3, 2, + }; - window_command_end(render_window); + window_pipeline_add_vertices(render_window, BB_PIPELINE_RECT, (String)array_to_bytes(box_vertices)); + window_pipeline_add_indices(render_window, BB_PIPELINE_RECT, (Slice(u32))array_to_slice(box_indices)); renderer_window_frame_end(renderer, render_window); + // window_size = os_window_size_get(os_window); + // + // window_command_begin(render_window); + // + // // window_bind_pipeline(render_window, pipeline_index); + // // window_bind_pipeline_descriptor_sets(render_window, pipeline_index); + // // window_bind_index_buffer(render_window, index_buffer, 0, INDEX_TYPE_U32); + // // GPUDrawPushConstants push_constants = { + // // .vertex_buffer = vertex_buffer_device_address, + // // .width = (f32)window_size.width, + // // .height = (f32)window_size.height, + // // }; + // // window_push_constants(render_window, pipeline_index, (SliceP(void)) array_to_slice(((void*[]) {&push_constants}))); + // + // window_render_begin(render_window); + // { + // // window_draw_indexed(render_window, indices.length, 1, 0, 0, 0); + // } + // window_render_end(render_window); + // + // window_command_end(render_window); + // + // renderer_window_frame_end(renderer, render_window); } // TODO: deinitialization diff --git a/bootstrap/bloat-buster/main.c b/bootstrap/bloat-buster/main.c index 9c95adc..8154522 100644 --- a/bootstrap/bloat-buster/main.c +++ b/bootstrap/bloat-buster/main.c @@ -24781,8 +24781,8 @@ void entry_point(int argc, char* argv[], char* envp[]) unit_tests(); #endif - Arena* global_arena = arena_init(MB(16), KB(64), KB(64)); #if BB_CI + Arena* global_arena = arena_init(MB(512), KB(64), KB(64)); { arguments.length = cast_to(u64, s32, argc); @@ -24850,6 +24850,6 @@ void entry_point(int argc, char* argv[], char* envp[]) thread_clear(thread); #else - run_app(global_arena); + run_app(); #endif } diff --git a/bootstrap/include/bloat-buster/bb_core.h b/bootstrap/include/bloat-buster/bb_core.h index 297648f..f24381e 100644 --- a/bootstrap/include/bloat-buster/bb_core.h +++ b/bootstrap/include/bloat-buster/bb_core.h @@ -2,6 +2,6 @@ #include #include -EXPORT void run_app(Arena* arena); +EXPORT void run_app(); #endif diff --git a/bootstrap/include/std/base.h b/bootstrap/include/std/base.h index 637ded7..3d39423 100644 --- a/bootstrap/include/std/base.h +++ b/bootstrap/include/std/base.h @@ -252,3 +252,8 @@ Hash64 hash_bytes(String bytes); Hash32 hash64_to_hash32(Hash64 hash64); u64 round_up_to_next_power_of_2(u64 n); + +STRUCT(TextureIndex) +{ + u32 value; +}; diff --git a/bootstrap/include/std/font_provider.h b/bootstrap/include/std/font_provider.h index 7786eba..dcaeed0 100644 --- a/bootstrap/include/std/font_provider.h +++ b/bootstrap/include/std/font_provider.h @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -23,6 +25,7 @@ STRUCT(TextureAtlas) s32 ascent; s32 descent; s32 line_gap; + TextureIndex texture; }; STRUCT(TextureAtlasCreate) @@ -31,4 +34,6 @@ STRUCT(TextureAtlasCreate) u32 text_height; }; -EXPORT TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create); +#include + +EXPORT TextureAtlas font_texture_atlas_create(Arena* arena, Renderer* renderer, TextureAtlasCreate create); diff --git a/bootstrap/include/std/graphics.h b/bootstrap/include/std/graphics.h index c406a7a..d2cfffa 100644 --- a/bootstrap/include/std/graphics.h +++ b/bootstrap/include/std/graphics.h @@ -3,43 +3,48 @@ #include #include -STRUCT(GraphicsWindowSize) +typedef void* OSWindow; + +typedef void OSWindowResize(OSWindow window, void* context, u32 width, u32 height); +typedef void OSWindowRefresh(OSWindow window, void* context); + +STRUCT(OSWindowSize) { u32 width; u32 height; }; -STRUCT(GraphicsWindowCreate) +STRUCT(OSWindowCreate) { String name; - GraphicsWindowSize size; + OSWindowSize size; + void* context; + OSWindowResize* resize_callback; + OSWindowRefresh* refresh_callback; }; -STRUCT(GraphicsCursorPosition) +STRUCT(OSCursorPosition) { f64 x; f64 y; }; -typedef struct GraphicsWindow GraphicsWindow; - -EXPORT void graphics_init(u8 should_use_x11); -EXPORT GraphicsWindow* graphics_window_create(GraphicsWindowCreate create); -EXPORT u8 graphics_window_should_close(GraphicsWindow* window); -EXPORT void graphics_poll_events(); -EXPORT GraphicsWindowSize graphics_window_size_get(GraphicsWindow* window); -EXPORT void graphics_window_consume_resize(GraphicsWindow* window); -EXPORT GraphicsCursorPosition graphics_window_cursor_position_get(GraphicsWindow* window); +EXPORT void os_graphics_init(u8 should_use_x11); +EXPORT OSWindow os_window_create(OSWindowCreate create); +EXPORT u8 os_window_should_close(OSWindow window); +EXPORT void os_poll_events(); +EXPORT OSWindowSize os_window_size_get(OSWindow window); +EXPORT OSCursorPosition os_window_cursor_position_get(OSWindow window); #ifdef __linux__ typedef unsigned long XID; typedef struct _XDisplay Display; typedef XID Window; -EXPORT Display* graphics_x11_display_get(); -EXPORT Window graphics_x11_window_get(GraphicsWindow* window); +EXPORT Display* x11_display_get(); +EXPORT Window x11_window_get(OSWindow window); #endif #ifdef _WIN32 -EXPORT HANDLE graphics_win32_window_get(GraphicsWindow* window); +EXPORT HANDLE win32_window_get(GraphicsWindow* window); #endif diff --git a/bootstrap/include/std/render.h b/bootstrap/include/std/render.h index d19520a..a837c64 100644 --- a/bootstrap/include/std/render.h +++ b/bootstrap/include/std/render.h @@ -1,25 +1,46 @@ #pragma once + #include -#include - -#define frame_overlap (2) - typedef struct Renderer Renderer; + +#include +#include + typedef struct RenderWindow RenderWindow; typedef struct Pipeline Pipeline; +typedef enum BBPipeline +{ + BB_PIPELINE_RECT, + BB_PIPELINE_COUNT, +} BBPipeline; + +typedef enum RenderFontType +{ + RENDER_FONT_TYPE_MONOSPACE, + RENDER_FONT_TYPE_PROPORTIONAL, + RENDER_FONT_TYPE_COUNT, +} RenderFontType; + +typedef enum RectTextureSlot +{ + RECT_TEXTURE_SLOT_WHITE, + RECT_TEXTURE_SLOT_MONOSPACE_FONT, + RECT_TEXTURE_SLOT_PROPORTIONAL_FONT, + RECT_TEXTURE_SLOT_COUNT +} RectTextureSlot; + typedef enum IndexType : u8 { - INDEX_TYPE_U16, INDEX_TYPE_U32, } IndexType; typedef enum TextureFormat : u8 { - R8_UNORM, - R8G8B8A8_SRGB, + TEXTURE_FORMAT_R8_UNORM, + TEXTURE_FORMAT_R8G8B8A8_SRGB, } TextureFormat; STRUCT(TextureMemory) @@ -67,16 +88,16 @@ STRUCT(DescriptorSetLayoutBinding) }; declare_slice(DescriptorSetLayoutBinding); -STRUCT(DescriptorSetLayout) +STRUCT(DescriptorSetLayoutCreate) { Slice(DescriptorSetLayoutBinding) bindings; }; -declare_slice(DescriptorSetLayout); +declare_slice(DescriptorSetLayoutCreate); STRUCT(PipelineLayoutCreate) { Slice(PushConstantRange) push_constant_ranges; - Slice(DescriptorSetLayout) descriptor_set_layouts; + Slice(DescriptorSetLayoutCreate) descriptor_set_layouts; }; declare_slice(PipelineLayoutCreate); @@ -87,11 +108,6 @@ STRUCT(GraphicsPipelinesCreate) Slice(PipelineCreate) pipelines; }; -STRUCT(TextureIndex) -{ - u32 value; -}; - STRUCT(PipelineIndex) { u32 value; @@ -107,21 +123,6 @@ STRUCT(DescriptorSetIndex) u32 value; }; -#define MAX_TEXTURE_UPDATE_COUNT (32) -#define MAX_DESCRIPTOR_SET_UPDATE_COUNT (16) -STRUCT(DescriptorSetUpdate) -{ - DescriptorSetIndex set; - DescriptorType type; - u32 binding; - u32 descriptor_count; - union - { - TextureIndex textures[MAX_TEXTURE_UPDATE_COUNT]; - }; -}; -declare_slice(DescriptorSetUpdate); - typedef enum BufferType : u8 { BUFFER_TYPE_VERTEX, @@ -129,11 +130,6 @@ typedef enum BufferType : u8 BUFFER_TYPE_STAGING, } BufferType; -STRUCT(BufferIndex) -{ - u32 value; -}; - STRUCT(HostBufferCopy) { String source; @@ -149,35 +145,24 @@ STRUCT(LocalBufferCopyRegion) }; declare_slice(LocalBufferCopyRegion); -STRUCT(LocalBufferCopy) -{ - BufferIndex destination; - BufferIndex source; - Slice(LocalBufferCopyRegion) regions; -}; -declare_slice(LocalBufferCopy); - -#define MAX_LOCAL_BUFFER_COPY_COUNT (16) - -EXPORT Renderer* renderer_initialize(); -EXPORT RenderWindow* renderer_window_initialize(Renderer* renderer, GraphicsWindow* window); +EXPORT Renderer* renderer_initialize(Arena* arena); +EXPORT RenderWindow* renderer_window_initialize(Renderer* renderer, OSWindow window); EXPORT PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* arena, GraphicsPipelinesCreate create_data); EXPORT PipelineLayoutIndex renderer_pipeline_get_layout(PipelineIndex pipeline); -EXPORT GraphicsWindowSize renderer_window_frame_begin(Renderer* renderer, RenderWindow* window); +EXPORT void renderer_window_frame_begin(Renderer* renderer, RenderWindow* window); EXPORT void renderer_window_frame_end(Renderer* renderer, RenderWindow* window); EXPORT TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_memory); -EXPORT BufferIndex renderer_buffer_create(Renderer* renderer, u64 size, BufferType type); -EXPORT void renderer_update_pipeline_resources(Renderer* renderer, PipelineIndex pipeline_index, Slice(DescriptorSetUpdate) descriptor_updates); -EXPORT void renderer_copy_to_host(BufferIndex buffer_index, Slice(HostBufferCopy) regions); -EXPORT void renderer_copy_to_local(Renderer* renderer, Slice(LocalBufferCopy) copies); EXPORT void window_command_begin(RenderWindow* window); EXPORT void window_command_end(RenderWindow* window); EXPORT void window_render_begin(RenderWindow* window); EXPORT void window_render_end(RenderWindow* window); -EXPORT void window_bind_pipeline(RenderWindow* window, PipelineIndex pipeline_index); -EXPORT void window_bind_pipeline_descriptor_sets(RenderWindow* window, PipelineIndex pipeline_index); -EXPORT void window_bind_index_buffer(RenderWindow* window, BufferIndex index_buffer, u64 offset, IndexType index_type); -EXPORT void window_push_constants(RenderWindow* window, PipelineIndex pipeline_index, SliceP(void) memories); -EXPORT u64 buffer_address(BufferIndex buffer_index); EXPORT void window_draw_indexed(RenderWindow* window, u32 index_count, u32 instance_count, u32 first_index, s32 vertex_offset, u32 first_instance); + +EXPORT void window_rect_texture_update_begin(RenderWindow* window); +EXPORT void renderer_queue_font_update(Renderer* renderer, RenderWindow* window, RenderFontType type, TextureAtlas atlas); +EXPORT void window_queue_rect_texture_update(RenderWindow* window, RectTextureSlot slot, TextureIndex texture_index); +EXPORT void window_rect_texture_update_end(Renderer* renderer, RenderWindow* window); + +EXPORT void window_pipeline_add_vertices(RenderWindow* window, BBPipeline pipeline_index, String vertex_memory); +EXPORT void window_pipeline_add_indices(RenderWindow* window, BBPipeline pipeline_index, Slice(u32) indices); diff --git a/bootstrap/include/std/ui_core.h b/bootstrap/include/std/ui_core.h new file mode 100644 index 0000000..9574641 --- /dev/null +++ b/bootstrap/include/std/ui_core.h @@ -0,0 +1,5 @@ +#include + +STRUCT(UI_State) +{ +}; diff --git a/bootstrap/shaders/font.frag b/bootstrap/shaders/font.frag index d3bb2dd..30bd07b 100644 --- a/bootstrap/shaders/font.frag +++ b/bootstrap/shaders/font.frag @@ -15,8 +15,8 @@ layout(set = 0, binding = 0) uniform sampler2D textures[]; void main() { vec2 texture_size = textureSize(textures[texture_index], 0); - //debugPrintfEXT("texture uv: (%f, %f)\n", in_screen_uv.x, in_screen_uv.y); vec2 uv = vec2(in_screen_uv.x / texture_size.x, in_screen_uv.y / texture_size.y); vec4 sampled = texture(textures[texture_index], uv); + // debugPrintfEXT("In color: (%f, %f, %f, %f). Sampled: (%f, %f, %f, %f)\n", in_color.x, in_color.y, in_color.z, in_color.w, sampled.x, sampled.y, sampled.z, sampled.w); out_frag_color = in_color * sampled; } diff --git a/bootstrap/std/font_provider.c b/bootstrap/std/font_provider.c index d50cef4..0ee5411 100644 --- a/bootstrap/std/font_provider.c +++ b/bootstrap/std/font_provider.c @@ -7,7 +7,7 @@ #include #pragma clang diagnostic pop -TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create) +TextureAtlas font_texture_atlas_create(Arena* arena, Renderer* renderer, TextureAtlasCreate create) { auto font_file = file_read(arena, create.font_path); stbtt_fontinfo font_info; @@ -114,5 +114,13 @@ TextureAtlas font_create_texture_atlas(Arena* arena, TextureAtlasCreate create) stbtt_FreeBitmap(bitmap, 0); } + result.texture = renderer_texture_create(renderer, (TextureMemory) { + .pointer = result.pointer, + .width = result.width, + .height = result.height, + .depth = 1, + .format = TEXTURE_FORMAT_R8G8B8A8_SRGB, + }); + return result; } diff --git a/bootstrap/std/graphics.c b/bootstrap/std/graphics.c index dd97e86..667a86e 100644 --- a/bootstrap/std/graphics.c +++ b/bootstrap/std/graphics.c @@ -6,18 +6,7 @@ global_variable u8 use_x11 = 0; -STRUCT(GraphicsWindow) -{ - GLFWwindow* handle; - u8 resized:1; - u32 width; - u32 height; -}; -#define MAX_WINDOW_COUNT (32) -global_variable GraphicsWindow windows[MAX_WINDOW_COUNT]; -global_variable u32 window_count = 0; - -void graphics_init(u8 should_use_x11) +void os_graphics_init(u8 should_use_x11) { #ifdef __linux__ use_x11 = should_use_x11; @@ -31,78 +20,80 @@ void graphics_init(u8 should_use_x11) } } -fn void framebuffer_size_callback(GLFWwindow* w, int width, int height) +global_variable OSWindowResize* resize_callback; +global_variable OSWindowRefresh* refresh_callback; + +fn void os_framebuffer_size_callback(GLFWwindow* w, int width, int height) { - GraphicsWindow* window = glfwGetWindowUserPointer(w); - assert(window->handle == w); - window->width = width; - window->height = height; - window->resized = 1; + void* context = glfwGetWindowUserPointer(w); + if (resize_callback) + { + resize_callback(w, context, width, height); + } } -typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); +fn void os_window_refresh_callback(GLFWwindow* w) +{ + void* context = glfwGetWindowUserPointer(w); + if (refresh_callback) + { + refresh_callback(w, context); + } +} -GraphicsWindow* graphics_window_create(GraphicsWindowCreate create) +OSWindow os_window_create(OSWindowCreate create) { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GraphicsWindow* window = &windows[window_count]; - *window = (GraphicsWindow) { - .handle = glfwCreateWindow(create.size.width, create.size.height, string_to_c(create.name), 0, 0), - }; - glfwSetWindowUserPointer(window->handle, window); - glfwSetFramebufferSizeCallback(window->handle, &framebuffer_size_callback); - window->width = create.size.width; - window->height = create.size.height; + GLFWwindow* window = glfwCreateWindow(create.size.width, create.size.height, string_to_c(create.name), 0, 0); + glfwSetWindowUserPointer(window, create.context); + glfwSetFramebufferSizeCallback(window, &os_framebuffer_size_callback); + glfwSetWindowRefreshCallback(window, &os_window_refresh_callback); + resize_callback = create.resize_callback; + refresh_callback = create.refresh_callback; return window; } -void graphics_window_consume_resize(GraphicsWindow* window) +u8 os_window_should_close(OSWindow window) { - assert(window->resized); - window->resized = 0; + return glfwWindowShouldClose(window); } -u8 graphics_window_should_close(GraphicsWindow* window) -{ - return glfwWindowShouldClose(window->handle); -} - -void graphics_poll_events() +void os_poll_events() { glfwPollEvents(); } -GraphicsWindowSize graphics_window_size_get(GraphicsWindow* window) +OSWindowSize os_window_size_get(OSWindow window) { - GraphicsWindowSize result; - glfwGetWindowSize(window->handle, (int*)&result.width, (int*)&result.height); + OSWindowSize result; + glfwGetWindowSize(window, (int*)&result.width, (int*)&result.height); return result; } -GraphicsCursorPosition graphics_window_cursor_position_get(GraphicsWindow* window) +OSCursorPosition os_window_cursor_position_get(OSWindow window) { - GraphicsCursorPosition result; - glfwGetCursorPos(window->handle, &result.x, &result.y); + OSCursorPosition result; + glfwGetCursorPos(window, &result.x, &result.y); return result; } #ifdef _WIN32 -HANDLE graphics_win32_window_get(GraphicsWindow* window) +HANDLE win32_window_get(OSWindow window) { - return glfwGetWin32Window(window->handle); + return glfwGetWin32Window(window); } #endif #ifdef __linux__ -Display* graphics_x11_display_get() +Display* x11_display_get() { return glfwGetX11Display(); } -Window graphics_x11_window_get(GraphicsWindow* window) +Window x11_window_get(OSWindow window) { - return glfwGetX11Window(window->handle); + return glfwGetX11Window(window); } #endif diff --git a/bootstrap/std/image_loader.c b/bootstrap/std/image_loader.c index e5be1de..4cbe667 100644 --- a/bootstrap/std/image_loader.c +++ b/bootstrap/std/image_loader.c @@ -21,7 +21,7 @@ EXPORT TextureMemory texture_load_from_file(Arena* arena, String path) .pointer = buffer, .width = width, .height = height, - .format = R8G8B8A8_SRGB, + .format = TEXTURE_FORMAT_R8G8B8A8_SRGB, .depth = 1, }; } diff --git a/bootstrap/std/render.c b/bootstrap/std/render.c index eef0276..b8a1b17 100644 --- a/bootstrap/std/render.c +++ b/bootstrap/std/render.c @@ -2,9 +2,35 @@ #include #include #include +#include #include +#define vkok(call) do {\ + VkResult _r_e_s_u_l_t_ = call; \ + if (unlikely(_r_e_s_u_l_t_ != VK_SUCCESS)) wrong_vulkan_result(_r_e_s_u_l_t_, strlit(#call), strlit(__FILE__), __LINE__); \ +} while(0) + +#define vkok_swapchain(call) do {\ + VkResult result = call; \ + if (unlikely(result != VK_SUCCESS)) wrong_vulkan_result(result, strlit(#call), strlit(__FILE__), __LINE__); \ +} while(0) + + +#define MAX_SWAPCHAIN_IMAGE_COUNT (16) +#define MAX_FRAME_COUNT (2) +#define MAX_DESCRIPTOR_SET_COUNT (16) +#define MAX_PUSH_CONSTANT_RANGE_COUNT (16) +#define MAX_SHADER_MODULE_COUNT_PER_PIPELINE (16) +#define MAX_DESCRIPTOR_SET_LAYOUT_COUNT (16) +#define MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT (16) +#define MAX_TEXTURE_COUNT (16) +#define MAX_TEXTURE_UPDATE_COUNT (32) +#define MAX_DESCRIPTOR_SET_UPDATE_COUNT (16) +#define MAX_LOCAL_BUFFER_COPY_COUNT (16) + +#define DEFAULT_PIPELINE BB_PIPELINE_RECT + STRUCT(VulkanImageCreate) { u32 width; @@ -22,6 +48,153 @@ STRUCT(VulkanImage) VkFormat format; }; +STRUCT(GPUDrawPushConstants) +{ + u64 vertex_buffer; + f32 width; + f32 height; +}; + +STRUCT(DescriptorSetLayoutBindings) +{ + VkDescriptorSetLayoutBinding buffer[MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT]; + u32 count; +}; + +STRUCT(Pipeline) +{ + VkPipeline handle; + VkPipelineLayout layout; + u32 descriptor_set_count; + u32 push_constant_range_count; + DescriptorSetLayoutBindings descriptor_set_layout_bindings[MAX_DESCRIPTOR_SET_COUNT]; + VkDescriptorSetLayout descriptor_set_layouts[MAX_DESCRIPTOR_SET_COUNT]; + VkPushConstantRange push_constant_ranges[MAX_PUSH_CONSTANT_RANGE_COUNT]; +}; + +STRUCT(RectPipeline) +{ + Pipeline pipeline; +}; + +STRUCT(ImmediateContext) +{ + VkDevice device; + VkFence fence; + VkCommandBuffer command_buffer; + VkCommandPool command_pool; + VkQueue queue; +}; + +STRUCT(VulkanBuffer) +{ + VkBuffer handle; + VkDeviceMemory gpu_data; + u64 address; + VkDeviceSize size; + BufferType type; +}; + +STRUCT(LocalBufferCopy) +{ + VulkanBuffer destination; + VulkanBuffer source; + Slice(LocalBufferCopyRegion) regions; +}; +declare_slice(LocalBufferCopy); + +STRUCT(VertexBuffer) +{ + VulkanBuffer gpu; + VirtualBuffer(u8) cpu; +}; + +STRUCT(IndexBuffer) +{ + VulkanBuffer gpu; + VirtualBuffer(u32) cpu; +}; + +STRUCT(Renderer) +{ + VkInstance instance; + VkAllocationCallbacks* allocator; + VkPhysicalDevice physical_device; + VkDevice device; + VkQueue graphics_queue; + u32 graphics_queue_family_index; + VkSampler sampler; + ImmediateContext immediate; + VkPhysicalDeviceMemoryProperties memory_properties; + Pipeline pipelines[BB_PIPELINE_COUNT]; + TextureAtlas fonts[RENDER_FONT_TYPE_COUNT]; +}; + +STRUCT(WindowFrame) +{ + VkCommandPool command_pool; + VkCommandBuffer command_buffer; + VkSemaphore swapchain_semaphore; + VkSemaphore render_semaphore; + VkFence render_fence; + BBPipeline bound_pipeline; + VkBuffer index_buffer; + GPUDrawPushConstants push_constants; +}; + +STRUCT(PipelineInstantiation) +{ + VertexBuffer vertex_buffer; + IndexBuffer index_buffer; + VulkanBuffer transient_buffer; + VkWriteDescriptorSet descriptor_set_update; + VkDescriptorSet descriptor_sets[MAX_DESCRIPTOR_SET_COUNT]; + VkDescriptorImageInfo texture_descriptors[MAX_TEXTURE_UPDATE_COUNT]; +}; + +STRUCT(RenderWindow) +{ + VkSwapchainKHR swapchain; + VkSurfaceKHR surface; + VkFormat swapchain_image_format; + u32 width; + u32 height; + u32 last_width; + u32 last_height; + u32 frame_index; + u32 swapchain_image_index; + u32 swapchain_image_count; + VulkanImage render_image; + VkImage swapchain_images[MAX_SWAPCHAIN_IMAGE_COUNT]; + VkImageView swapchain_image_views[MAX_SWAPCHAIN_IMAGE_COUNT]; + WindowFrame frames[MAX_FRAME_COUNT]; + PipelineInstantiation pipeline_instantiations[BB_PIPELINE_COUNT]; +}; + +STRUCT(VulkanTexture) +{ + VulkanImage image; + VkSampler sampler; +}; + +STRUCT(VulkanCopyImage) +{ + VkImage handle; + VkExtent2D extent; +}; + +STRUCT(VulkanCopyImageArgs) +{ + VulkanCopyImage source; + VulkanCopyImage destination; +}; + + +global_variable Renderer renderer_memory; +global_variable RenderWindow renderer_window_memory; +global_variable VulkanTexture textures[MAX_TEXTURE_COUNT]; +global_variable u32 texture_count; + fn String vulkan_result_to_string(VkResult result) { switch (result) @@ -91,15 +264,250 @@ fn String vulkan_result_to_string(VkResult result) trap(); } -#define vkok(call) do {\ - VkResult _r_e_s_u_l_t_ = call; \ - if (unlikely(_r_e_s_u_l_t_ != VK_SUCCESS)) wrong_vulkan_result(_r_e_s_u_l_t_, strlit(#call), strlit(__FILE__), __LINE__); \ -} while(0) +fn void buffer_copy_to_local_command(VkCommandBuffer command_buffer, Slice(LocalBufferCopy) copies) +{ + for (u64 i = 0; i < copies.length; i += 1) + { + auto copy = copies.pointer[i]; + auto* source_buffer = ©.source; + auto* destination_buffer = ©.destination; -#define vkok_swapchain(call) do {\ - VkResult result = call; \ - if (unlikely(result != VK_SUCCESS)) wrong_vulkan_result(result, strlit(#call), strlit(__FILE__), __LINE__); \ -} while(0) + VkBufferCopy2 buffer_copies[MAX_LOCAL_BUFFER_COPY_COUNT]; + + for (u64 i = 0; i < copy.regions.length; i += 1) + { + auto copy_region = copy.regions.pointer[i]; + buffer_copies[i] = (VkBufferCopy2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + .pNext = 0, + .srcOffset = copy_region.source_offset, + .dstOffset = copy_region.destination_offset, + .size = copy_region.size, + }; + } + + VkCopyBufferInfo2 info = { + .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + .pNext = 0, + .srcBuffer = source_buffer->handle, + .dstBuffer = destination_buffer->handle, + .regionCount = copy.regions.length, + .pRegions = buffer_copies, + }; + + vkCmdCopyBuffer2(command_buffer, &info); + } +} + +void buffer_copy_to_host(VulkanBuffer buffer, Slice(HostBufferCopy) regions) +{ + assert(buffer.type == BUFFER_TYPE_STAGING); + + auto* buffer_pointer = (u8*)buffer.address; + + for (u64 i = 0; i < regions.length; i += 1) + { + auto region = regions.pointer[i]; + memcpy(buffer_pointer + region.destination_offset, region.source.pointer, region.source.length); + } +} + +fn VkShaderStageFlags vulkan_shader_stage_from_path(String shader_source_path) +{ + VkShaderStageFlags shader_stage; + if (string_ends_with(shader_source_path, strlit(".vert"))) + { + shader_stage = VK_SHADER_STAGE_VERTEX_BIT; + } + else if (string_ends_with(shader_source_path, strlit(".frag"))) + { + shader_stage = VK_SHADER_STAGE_FRAGMENT_BIT; + } + else + { + failed_execution(); + } + + return shader_stage; +} + +fn VkShaderStageFlags vulkan_shader_stage(ShaderStage shader_stage) +{ + VkShaderStageFlags result; + + switch (shader_stage) + { + case SHADER_STAGE_VERTEX: + result = VK_SHADER_STAGE_VERTEX_BIT; + break; + case SHADER_STAGE_FRAGMENT: + result = VK_SHADER_STAGE_FRAGMENT_BIT; + break; + } + + return result; +} + +fn VkDescriptorType vulkan_descriptor_type(DescriptorType type) +{ + VkDescriptorType result; + + switch (type) + { + case DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER: + result = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + break; + case DESCRIPTOR_TYPE_COUNT: + unreachable(); + } + + return result; +} + +fn DescriptorType descriptor_type_from_vulkan(VkDescriptorType descriptor_type) +{ + DescriptorType result; + + switch (descriptor_type) + { + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + result = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER; + break; + default: unreachable(); + } + + return result; +} + +fn ShaderStage shader_stage_from_path(String shader_source_path) +{ + ShaderStage shader_stage; + if (string_ends_with(shader_source_path, strlit(".vert"))) + { + shader_stage = SHADER_STAGE_VERTEX; + } + else if (string_ends_with(shader_source_path, strlit(".frag"))) + { + shader_stage = SHADER_STAGE_FRAGMENT; + } + else + { + failed_execution(); + } + + return shader_stage; +} + +fn VkDeviceMemory vk_allocate_memory(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VkMemoryRequirements memory_requirements, VkMemoryPropertyFlags flags, u8 use_device_address_bit) +{ + u32 memory_type_index; + for (memory_type_index = 0; memory_type_index < memory_properties.memoryTypeCount; memory_type_index += 1) + { + auto memory_type = memory_properties.memoryTypes[memory_type_index]; + + if ((memory_requirements.memoryTypeBits & (1 << memory_type_index)) != 0 && (memory_type.propertyFlags & flags) == flags) + { + break; + } + } + + if (memory_type_index == memory_properties.memoryTypeCount) + { + failed_execution(); + } + + VkMemoryAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = memory_type_index, + }; + + VkMemoryAllocateFlagsInfo flags_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + .pNext = 0, + .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + .deviceMask = 1, + }; + + if (use_device_address_bit) + { + allocate_info.pNext = &flags_info; + } + + VkDeviceMemory memory = 0; + vkok(vkAllocateMemory(device, &allocate_info, allocation_callbacks, &memory)); + + return memory; +} + +fn VulkanBuffer vk_buffer_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties physical_device_memory_properties, VkDeviceSize buffer_size, VkBufferUsageFlags usage_flags, VkMemoryPropertyFlags memory_flags) +{ + VulkanBuffer result = { + .size = buffer_size, + }; + + VkBufferCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = 0, + .flags = 0, + .size = buffer_size, + .usage = usage_flags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = 0, + }; + vkok(vkCreateBuffer(device, &create_info, allocation_callbacks, &result.handle)); + + VkMemoryRequirements memory_requirements; + vkGetBufferMemoryRequirements(device, result.handle, &memory_requirements); + + u8 use_device_address_bit = !!(create_info.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + result.gpu_data = vk_allocate_memory(device, allocation_callbacks, physical_device_memory_properties, memory_requirements, memory_flags, use_device_address_bit); + + VkDeviceSize memory_offset = 0; + vkok(vkBindBufferMemory(device, result.handle, result.gpu_data, memory_offset)); + + u8 map_memory = !!(memory_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + assert(((map_memory | use_device_address_bit) == 0) | (map_memory == !use_device_address_bit)); + if (map_memory) + { + void* data = 0; + VkDeviceSize offset = 0; + VkMemoryMapFlags map_flags = 0; + vkok(vkMapMemory(device, result.gpu_data, offset, memory_requirements.size, map_flags, &data)); + result.address = (u64)data; + } + + if (use_device_address_bit) + { + VkBufferDeviceAddressInfo device_address_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .pNext = 0, + .buffer = result.handle, + }; + result.address = vkGetBufferDeviceAddress(device, &device_address_info); + } + + return result; +} + +fn VulkanBuffer buffer_create(Renderer* renderer, u64 size, BufferType type) +{ + u8 is_dst = (type == BUFFER_TYPE_VERTEX) | (type == BUFFER_TYPE_INDEX); + u8 is_src = type == BUFFER_TYPE_STAGING; + + VkBufferUsageFlags usage = + (VK_BUFFER_USAGE_TRANSFER_DST_BIT * is_dst) | + (VK_BUFFER_USAGE_TRANSFER_SRC_BIT * is_src) | + ((VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) * (type == BUFFER_TYPE_VERTEX)) | + (VK_BUFFER_USAGE_INDEX_BUFFER_BIT * (type == BUFFER_TYPE_INDEX)); + VkMemoryPropertyFlags memory_flags = + (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT * is_dst) | + ((VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) * is_src); + auto result = vk_buffer_create(renderer->device, renderer->allocator, renderer->memory_properties, size, usage, memory_flags); + result.type = type; + return result; +} fn u8 vk_layer_is_supported(String layer_name) { @@ -188,57 +596,6 @@ fn VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT mes #endif -fn VkDeviceMemory vk_allocate_memory(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties memory_properties, VkMemoryRequirements memory_requirements, VkMemoryPropertyFlags flags, u8 use_device_address_bit) -{ - u32 memory_type_index; - for (memory_type_index = 0; memory_type_index < memory_properties.memoryTypeCount; memory_type_index += 1) - { - auto memory_type = memory_properties.memoryTypes[memory_type_index]; - - if ((memory_requirements.memoryTypeBits & (1 << memory_type_index)) != 0 && (memory_type.propertyFlags & flags) == flags) - { - break; - } - } - - if (memory_type_index == memory_properties.memoryTypeCount) - { - failed_execution(); - } - - VkMemoryAllocateInfo allocate_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .allocationSize = memory_requirements.size, - .memoryTypeIndex = memory_type_index, - }; - - VkMemoryAllocateFlagsInfo flags_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, - .pNext = 0, - .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - .deviceMask = 1, - }; - - if (use_device_address_bit) - { - allocate_info.pNext = &flags_info; - } - - VkDeviceMemory memory = 0; - vkok(vkAllocateMemory(device, &allocate_info, allocation_callbacks, &memory)); - - return memory; -} - -STRUCT(ImmediateContext) -{ - VkDevice device; - VkFence fence; - VkCommandBuffer command_buffer; - VkCommandPool command_pool; - VkQueue queue; -}; - fn void immediate_start(ImmediateContext context) { VkFence fences[] = { context.fence }; @@ -378,18 +735,6 @@ fn void vk_image_transition(VkCommandBuffer command_buffer, VkImage image, VkIma vkCmdPipelineBarrier2(command_buffer, &dependency_info); } -STRUCT(VulkanCopyImage) -{ - VkImage handle; - VkExtent2D extent; -}; - -STRUCT(VulkanCopyImageArgs) -{ - VulkanCopyImage source; - VulkanCopyImage destination; -}; - fn void vk_image_copy(VkCommandBuffer command_buffer, VulkanCopyImageArgs args) { VkImageSubresourceLayers subresource_layers = { @@ -436,56 +781,10 @@ fn void vk_image_copy(VkCommandBuffer command_buffer, VulkanCopyImageArgs args) vkCmdBlitImage2(command_buffer, &blit_info); } -STRUCT(Renderer) + +Renderer* renderer_initialize(Arena* arena) { - VkInstance instance; - VkAllocationCallbacks* allocator; - VkPhysicalDevice physical_device; - VkDevice device; - VkQueue graphics_queue; - u32 graphics_queue_family_index; - VkSampler sampler; - ImmediateContext immediate; - VkPhysicalDeviceMemoryProperties memory_properties; -}; - -#define MAX_SWAPCHAIN_IMAGE_COUNT (16) -#define MAX_FRAMES (2) - -STRUCT(WindowFrame) -{ - VkCommandPool command_pool; - VkCommandBuffer command_buffer; - VkSemaphore swapchain_semaphore; - VkSemaphore render_semaphore; - VkFence render_fence; -}; - -STRUCT(RenderWindow) -{ - GraphicsWindow* graphics_window; - VkSwapchainKHR swapchain; - VkSurfaceKHR surface; - VkFormat swapchain_image_format; - u32 width; - u32 height; - u32 last_width; - u32 last_height; - u32 frame_index; - u32 swapchain_image_index; - u32 swapchain_image_count; - VulkanImage render_image; - VkImage swapchain_images[MAX_SWAPCHAIN_IMAGE_COUNT]; - VkImageView swapchain_image_views[MAX_SWAPCHAIN_IMAGE_COUNT]; - WindowFrame frames[MAX_FRAMES]; -}; - -global_variable Renderer renderer_memory; -global_variable RenderWindow renderer_window_memory; - -Renderer* renderer_initialize() -{ - Renderer* result = &renderer_memory; + Renderer* renderer = &renderer_memory; vkok(volkInitialize()); auto api_version = volkGetInstanceVersion(); @@ -577,21 +876,19 @@ Renderer* renderer_initialize() .pNext = pNext, }; - vkok(vkCreateInstance(&ci, result->allocator, &result->instance)); - volkLoadInstance(result->instance); + vkok(vkCreateInstance(&ci, renderer->allocator, &renderer->instance)); + volkLoadInstance(renderer->instance); #if BB_DEBUG VkDebugUtilsMessengerEXT messenger; - vkok(vkCreateDebugUtilsMessengerEXT(result->instance, &msg_ci, result->allocator, &messenger)); + vkok(vkCreateDebugUtilsMessengerEXT(renderer->instance, &msg_ci, renderer->allocator, &messenger)); #endif } - { - u32 physical_device_count; VkPhysicalDevice physical_devices[256]; - vkok(vkEnumeratePhysicalDevices(result->instance, &physical_device_count, 0)); + vkok(vkEnumeratePhysicalDevices(renderer->instance, &physical_device_count, 0)); if (physical_device_count == 0) { @@ -603,21 +900,21 @@ Renderer* renderer_initialize() failed_execution(); } - vkok(vkEnumeratePhysicalDevices(result->instance, &physical_device_count, physical_devices)); + vkok(vkEnumeratePhysicalDevices(renderer->instance, &physical_device_count, physical_devices)); - result->physical_device = physical_devices[0]; + renderer->physical_device = physical_devices[0]; } - vkGetPhysicalDeviceMemoryProperties(result->physical_device, &result->memory_properties); + vkGetPhysicalDeviceMemoryProperties(renderer->physical_device, &renderer->memory_properties); u32 graphics_queue_family_index; { u32 present_queue_family_index; VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(result->physical_device, &properties); + vkGetPhysicalDeviceProperties(renderer->physical_device, &properties); u32 queue_count; - vkGetPhysicalDeviceQueueFamilyProperties(result->physical_device, &queue_count, 0); + vkGetPhysicalDeviceQueueFamilyProperties(renderer->physical_device, &queue_count, 0); VkQueueFamilyProperties queue_properties[64]; if (queue_count > array_length(queue_properties)) @@ -625,7 +922,7 @@ Renderer* renderer_initialize() failed_execution(); } - vkGetPhysicalDeviceQueueFamilyProperties(result->physical_device, &queue_count, queue_properties); + vkGetPhysicalDeviceQueueFamilyProperties(renderer->physical_device, &queue_count, queue_properties); for (graphics_queue_family_index = 0; graphics_queue_family_index < queue_count; graphics_queue_family_index += 1) { @@ -707,34 +1004,34 @@ Renderer* renderer_initialize() .pNext = &features, }; - vkok(vkCreateDevice(result->physical_device, &ci, result->allocator, &result->device)); + vkok(vkCreateDevice(renderer->physical_device, &ci, renderer->allocator, &renderer->device)); } - vkGetDeviceQueue(result->device, graphics_queue_family_index, 0, &result->graphics_queue); + vkGetDeviceQueue(renderer->device, graphics_queue_family_index, 0, &renderer->graphics_queue); - result->immediate.device = result->device; - result->immediate.queue = result->graphics_queue; + renderer->immediate.device = renderer->device; + renderer->immediate.queue = renderer->graphics_queue; VkCommandPoolCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = graphics_queue_family_index, }; - vkok(vkCreateCommandPool(result->device, &create_info, result->allocator, &result->immediate.command_pool)); + vkok(vkCreateCommandPool(renderer->device, &create_info, renderer->allocator, &renderer->immediate.command_pool)); VkCommandBufferAllocateInfo command_buffer_allocate_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = result->immediate.command_pool, + .commandPool = renderer->immediate.command_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = 1, }; - vkok(vkAllocateCommandBuffers(result->device, &command_buffer_allocate_info, &result->immediate.command_buffer)); + vkok(vkAllocateCommandBuffers(renderer->device, &command_buffer_allocate_info, &renderer->immediate.command_buffer)); VkFenceCreateInfo fence_create_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }; - vkok(vkCreateFence(result->device, &fence_create_info, result->allocator, &result->immediate.fence)); + vkok(vkCreateFence(renderer->device, &fence_create_info, renderer->allocator, &renderer->immediate.fence)); { VkFilter sampler_filter = VK_FILTER_LINEAR; @@ -759,313 +1056,47 @@ Renderer* renderer_initialize() .unnormalizedCoordinates = 0, }; - vkok(vkCreateSampler(result->device, &create_info, result->allocator, &result->sampler)); + vkok(vkCreateSampler(renderer->device, &create_info, renderer->allocator, &renderer->sampler)); } - return result; -} - -fn void destroy_image(Renderer* renderer, VulkanImage image) -{ - vkDestroyImageView(renderer->device, image.view, renderer->allocator); - vkDestroyImage(renderer->device, image.handle, renderer->allocator); - vkFreeMemory(renderer->device, image.memory, renderer->allocator); -} - -fn void swapchain_recreate(Renderer* renderer, RenderWindow* window, VkSurfaceCapabilitiesKHR surface_capabilities) -{ - VkSwapchainKHR old_swapchain = window->swapchain; - VkImageView old_swapchain_image_views[MAX_SWAPCHAIN_IMAGE_COUNT]; - - if (old_swapchain) - { - vkok(vkDeviceWaitIdle(renderer->device)); - for (u32 i = 0; i < window->swapchain_image_count; i += 1) - { - old_swapchain_image_views[i] = window->swapchain_image_views[i]; - } - } - - u32 queue_family_indices[] = { renderer->graphics_queue_family_index }; - VkImageUsageFlags swapchain_image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - window->swapchain_image_format = VK_FORMAT_B8G8R8A8_UNORM; - window->last_width = window->width; - window->last_height = window->height; - window->width = surface_capabilities.currentExtent.width; - window->height = surface_capabilities.currentExtent.height; - - VkSwapchainCreateInfoKHR swapchain_create_info = { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .surface = window->surface, - .minImageCount = surface_capabilities.minImageCount, - .imageFormat = window->swapchain_image_format, - .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - .imageExtent = surface_capabilities.currentExtent, - .imageArrayLayers = 1, - .imageUsage = swapchain_image_usage_flags, - .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = array_length(queue_family_indices), - .pQueueFamilyIndices = queue_family_indices, - .preTransform = surface_capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = VK_PRESENT_MODE_FIFO_KHR, - .clipped = 0, - .oldSwapchain = window->swapchain, + String shader_source_paths[] = { + strlit("bootstrap/shaders/font.vert"), + strlit("bootstrap/shaders/font.frag"), }; - - vkok(vkCreateSwapchainKHR(renderer->device, &swapchain_create_info, renderer->allocator, &window->swapchain)); - - assert(window->swapchain != old_swapchain); - - if (old_swapchain) - { - for (u32 i = 0; i < window->swapchain_image_count; i += 1) - { - vkDestroyImageView(renderer->device, old_swapchain_image_views[i], renderer->allocator); - } - - vkDestroySwapchainKHR(renderer->device, old_swapchain, renderer->allocator); - - destroy_image(renderer, window->render_image); - } - - { - vkok(vkGetSwapchainImagesKHR(renderer->device, window->swapchain, &window->swapchain_image_count, 0)); - - if (window->swapchain_image_count == 0) - { - failed_execution(); - } - - if (window->swapchain_image_count > array_length(window->swapchain_images)) - { - failed_execution(); - } - - vkok(vkGetSwapchainImagesKHR(renderer->device, window->swapchain, &window->swapchain_image_count, window->swapchain_images)); - - // VkImageViewUsageCreateInfo image_view_usage_create_info = { - // .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, - // .pNext = 0, - // .usage = swapchain_create_info.imageUsage, - // }; - - for (u32 i = 0; i < window->swapchain_image_count; i += 1) - { - VkImageViewCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - // .pNext = &image_view_usage_create_info, - .flags = 0, - .image = window->swapchain_images[i], - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = swapchain_create_info.imageFormat, - .components = { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY, + PipelineLayoutCreate pipeline_layouts[] = { + (PipelineLayoutCreate) { + .push_constant_ranges = array_to_slice(((PushConstantRange[]){ + (PushConstantRange) { + .offset = 0, + .size = sizeof(GPUDrawPushConstants), + .stage = SHADER_STAGE_VERTEX, }, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, + })), + .descriptor_set_layouts = array_to_slice(((DescriptorSetLayoutCreate[]){ + (DescriptorSetLayoutCreate) { + .bindings = array_to_slice(((DescriptorSetLayoutBinding[]) { + { + .binding = 0, + .type = DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER, + .stage = SHADER_STAGE_FRAGMENT, + .count = RECT_TEXTURE_SLOT_COUNT, + }, + })), }, - }; - - vkok(vkCreateImageView(renderer->device, &create_info, renderer->allocator, &window->swapchain_image_views[i])); - } - } - - window->render_image = vk_image_create(renderer->device, renderer->allocator, renderer->memory_properties, (VulkanImageCreate) { - .width = surface_capabilities.currentExtent.width, - .height = surface_capabilities.currentExtent.height, - .mip_levels = 1, - .format = window->swapchain_image_format, - .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - }); -} - -RenderWindow* renderer_window_initialize(Renderer* renderer, GraphicsWindow* window) -{ - RenderWindow* result = &renderer_window_memory; - result->graphics_window = window; - { -#ifdef VK_USE_PLATFORM_WIN32_KHR - VkWin32SurfaceCreateInfoKHR create_info = { - .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .hinstance = os_windows_get_module_handle(), - .hwnd = graphics_win32_window_get(window), - }; - vkok(vkCreateWin32SurfaceKHR(renderer->instance, &create_info, renderer->allocator, &result->surface)); -#endif -#ifdef VK_USE_PLATFORM_XLIB_KHR - VkXlibSurfaceCreateInfoKHR create_info = { - .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - .pNext = 0, - .flags = 0, - .dpy = graphics_x11_display_get(), - .window = graphics_x11_window_get(window), - }; - vkok(vkCreateXlibSurfaceKHR(renderer->instance, &create_info, renderer->allocator, &result->surface)); -#endif -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, -#endif -#ifdef VK_USE_PLATFORM_MACOS_MVK - VK_KHR_COCOA_SURFACE_EXTENSION_NAME, -#endif - } - - VkSurfaceCapabilitiesKHR surface_capabilities; - vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device, result->surface, &surface_capabilities)); - swapchain_recreate(renderer, result, surface_capabilities); - - VkCommandPoolCreateInfo command_pool_create_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = renderer->graphics_queue_family_index, + })), + }, }; - - VkFenceCreateInfo fence_create_info = { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .flags = VK_FENCE_CREATE_SIGNALED_BIT, + PipelineCreate pipeline_create[] = { + (PipelineCreate) { + .shader_source_indices = array_to_slice(((u16[]){0, 1})), + .layout_index = 0, + }, }; - - VkSemaphoreCreateInfo semaphore_create_info = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .flags = 0, + auto create_data = (GraphicsPipelinesCreate) { + .layouts = array_to_slice(pipeline_layouts), + .pipelines = array_to_slice(pipeline_create), + .shader_sources = array_to_slice(shader_source_paths), }; - - for (u32 i = 0; i < MAX_FRAMES; i += 1) - { - WindowFrame* frame = &result->frames[i]; - vkok(vkCreateCommandPool(renderer->device, &command_pool_create_info, renderer->allocator, &frame->command_pool)); - - VkCommandBufferAllocateInfo command_buffer_allocate_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = frame->command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - vkok(vkAllocateCommandBuffers(renderer->device, &command_buffer_allocate_info, &frame->command_buffer)); - vkok(vkCreateFence(renderer->device, &fence_create_info, renderer->allocator, &frame->render_fence)); - vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->render_semaphore)); - vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->swapchain_semaphore)); - } - - return result; -} - -#define MAX_DESCRIPTOR_SETS (16) -#define MAX_PUSH_CONSTANT_RANGES (16) - -STRUCT(PipelineLayout) -{ - VkPipelineLayout handle; - u32 descriptor_set_count; - VkDescriptorSet descriptor_sets[MAX_DESCRIPTOR_SETS]; - u32 push_constant_range_count; - VkPushConstantRange push_constant_ranges[MAX_DESCRIPTOR_SETS]; -}; - -STRUCT(Pipeline) -{ - VkPipeline handle; - PipelineLayoutIndex layout; -}; - -#define MAX_PIPELINES (16) -global_variable PipelineLayout pipeline_layouts[MAX_PIPELINES]; -global_variable Pipeline pipelines[MAX_PIPELINES]; - -STRUCT(GPUDrawPushConstants) -{ - VkDeviceAddress vertex_buffer; - f32 width; - f32 height; -}; - -#define MAX_SHADER_MODULE_COUNT_PER_PIPELINE (16) -fn VkShaderStageFlags vulkan_shader_stage_from_path(String shader_source_path) -{ - VkShaderStageFlags shader_stage; - if (string_ends_with(shader_source_path, strlit(".vert"))) - { - shader_stage = VK_SHADER_STAGE_VERTEX_BIT; - } - else if (string_ends_with(shader_source_path, strlit(".frag"))) - { - shader_stage = VK_SHADER_STAGE_FRAGMENT_BIT; - } - else - { - failed_execution(); - } - - return shader_stage; -} - -fn VkShaderStageFlags vulkan_shader_stage(ShaderStage shader_stage) -{ - VkShaderStageFlags result; - - switch (shader_stage) - { - case SHADER_STAGE_VERTEX: - result = VK_SHADER_STAGE_VERTEX_BIT; - break; - case SHADER_STAGE_FRAGMENT: - result = VK_SHADER_STAGE_FRAGMENT_BIT; - break; - } - - return result; -} - -fn ShaderStage shader_stage_from_path(String shader_source_path) -{ - ShaderStage shader_stage; - if (string_ends_with(shader_source_path, strlit(".vert"))) - { - shader_stage = SHADER_STAGE_VERTEX; - } - else if (string_ends_with(shader_source_path, strlit(".frag"))) - { - shader_stage = SHADER_STAGE_FRAGMENT; - } - else - { - failed_execution(); - } - - return shader_stage; -} - -fn VkDescriptorType vulkan_descriptor_type(DescriptorType type) -{ - VkDescriptorType result; - - switch (type) - { - case DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER: - result = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - break; - case DESCRIPTOR_TYPE_COUNT: - unreachable(); - } - - return result; -} - -PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* arena, GraphicsPipelinesCreate create_data) -{ auto graphics_pipeline_count = create_data.pipelines.length; assert(graphics_pipeline_count); auto pipeline_layout_count = create_data.layouts.length; @@ -1073,14 +1104,9 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren assert(pipeline_layout_count <= graphics_pipeline_count); auto shader_count = create_data.shader_sources.length; - if (graphics_pipeline_count > MAX_PIPELINES) - { - failed_execution(); - } - - VkPipeline pipeline_handles[MAX_PIPELINES]; + VkPipeline pipeline_handles[BB_PIPELINE_COUNT]; VkPipelineShaderStageCreateInfo shader_create_infos[MAX_SHADER_MODULE_COUNT_PER_PIPELINE]; - VkGraphicsPipelineCreateInfo graphics_pipeline_create_infos[MAX_PIPELINES]; + VkGraphicsPipelineCreateInfo graphics_pipeline_create_infos[BB_PIPELINE_COUNT]; VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, @@ -1219,45 +1245,38 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren vkok(vkCreateShaderModule(renderer->device, &create_info, renderer->allocator, &shader_modules[i])); } - // auto* pipeline_layouts = arena_allocate(arena, VkPipelineLayout, pipeline_layout_count); - - for (u64 i = 0; i < pipeline_layout_count; i += 1) + for (u64 pipeline_index = 0; pipeline_index < pipeline_layout_count; pipeline_index += 1) { - auto create = create_data.layouts.pointer[i]; + auto create = create_data.layouts.pointer[pipeline_index]; auto descriptor_set_layout_count = create.descriptor_set_layouts.length; auto push_constant_range_count = create.push_constant_ranges.length; - pipeline_layouts[i].descriptor_set_count = descriptor_set_layout_count; - pipeline_layouts[i].push_constant_range_count = push_constant_range_count; + auto* pipeline = &renderer->pipelines[pipeline_index]; + pipeline->descriptor_set_count = descriptor_set_layout_count; + pipeline->push_constant_range_count = push_constant_range_count; -#define MAX_DESCRIPTOR_SET_LAYOUT_COUNT (16) - VkDescriptorSetLayout descriptor_set_layouts[MAX_DESCRIPTOR_SET_LAYOUT_COUNT]; if (descriptor_set_layout_count > MAX_DESCRIPTOR_SET_LAYOUT_COUNT) { failed_execution(); } - u16 descriptor_type_counter[DESCRIPTOR_TYPE_COUNT] = {}; + // u16 descriptor_type_counter[DESCRIPTOR_TYPE_COUNT] = {}; - for (u64 i = 0; i < descriptor_set_layout_count; i += 1) + for (u64 descriptor_set_layout_index = 0; descriptor_set_layout_index < descriptor_set_layout_count; descriptor_set_layout_index += 1) { - auto set_layout_create = create.descriptor_set_layouts.pointer[i]; + auto set_layout_create = create.descriptor_set_layouts.pointer[descriptor_set_layout_index]; auto binding_count = set_layout_create.bindings.length; + auto* descriptor_set_layout_bindings = &pipeline->descriptor_set_layout_bindings[descriptor_set_layout_index]; + descriptor_set_layout_bindings->count = binding_count; -#define MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT (16) - VkDescriptorSetLayoutBinding bindings[MAX_DESCRIPTOR_SET_LAYOUT_BINDING_COUNT]; - - for (u64 i = 0; i < binding_count; i += 1) + for (u64 binding_index = 0; binding_index < binding_count; binding_index += 1) { - auto binding_descriptor = set_layout_create.bindings.pointer[i]; - auto* counter_ptr = &descriptor_type_counter[binding_descriptor.type]; - auto old_counter = *counter_ptr; - *counter_ptr = old_counter + binding_descriptor.count; + auto binding_descriptor = set_layout_create.bindings.pointer[binding_index]; VkDescriptorType descriptor_type = vulkan_descriptor_type(binding_descriptor.type); VkShaderStageFlags shader_stage = vulkan_shader_stage(binding_descriptor.stage); - bindings[i] = (VkDescriptorSetLayoutBinding) { + descriptor_set_layout_bindings->buffer[binding_index] = (VkDescriptorSetLayoutBinding) { .binding = binding_descriptor.binding, .descriptorType = descriptor_type, .descriptorCount = binding_descriptor.count, @@ -1271,63 +1290,21 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren .pNext = 0, .flags = 0, .bindingCount = binding_count, - .pBindings = bindings, + .pBindings = descriptor_set_layout_bindings->buffer, }; - vkok(vkCreateDescriptorSetLayout(renderer->device, &create_info, renderer->allocator, &descriptor_set_layouts[i])); + vkok(vkCreateDescriptorSetLayout(renderer->device, &create_info, renderer->allocator, &pipeline->descriptor_set_layouts[descriptor_set_layout_index])); } - { - VkDescriptorPoolSize pool_sizes[DESCRIPTOR_TYPE_COUNT]; - u32 pool_size_count = 0; - - for (DescriptorType i = 0; i < DESCRIPTOR_TYPE_COUNT; i += 1) - { - auto count = descriptor_type_counter[i]; - if (count) - { - auto* pool_size = &pool_sizes[pool_size_count]; - pool_size_count += 1; - - *pool_size = (VkDescriptorPoolSize) { - .type = vulkan_descriptor_type(i), - .descriptorCount = count, - }; - } - } - - VkDescriptorPoolCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .pNext = 0, - .flags = 0, - .maxSets = descriptor_set_layout_count, - .poolSizeCount = pool_size_count, - .pPoolSizes = pool_sizes, - }; - - VkDescriptorPool descriptor_pool; - vkok(vkCreateDescriptorPool(renderer->device, &create_info, renderer->allocator, &descriptor_pool)); - - VkDescriptorSetAllocateInfo allocate_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .pNext = 0, - .descriptorPool = descriptor_pool, - .descriptorSetCount = descriptor_set_layout_count, - .pSetLayouts = descriptor_set_layouts, - }; - - vkok(vkAllocateDescriptorSets(renderer->device, &allocate_info, pipeline_layouts[i].descriptor_sets)); - } - - if (push_constant_range_count > MAX_PUSH_CONSTANT_RANGES) + if (push_constant_range_count > MAX_PUSH_CONSTANT_RANGE_COUNT) { failed_execution(); } - for (u64 i = 0; i < push_constant_range_count; i += 1) + for (u64 push_constant_index = 0; push_constant_index < push_constant_range_count; push_constant_index += 1) { - auto push_constant_descriptor = create.push_constant_ranges.pointer[i]; - pipeline_layouts[i].push_constant_ranges[i] = (VkPushConstantRange) { + auto push_constant_descriptor = create.push_constant_ranges.pointer[push_constant_index]; + pipeline->push_constant_ranges[push_constant_index] = (VkPushConstantRange) { .stageFlags = vulkan_shader_stage(push_constant_descriptor.stage), .offset = push_constant_descriptor.offset, .size = push_constant_descriptor.size, @@ -1339,12 +1316,12 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren .pNext = 0, .flags = 0, .setLayoutCount = descriptor_set_layout_count, - .pSetLayouts = descriptor_set_layouts, + .pSetLayouts = pipeline->descriptor_set_layouts, .pushConstantRangeCount = push_constant_range_count, - .pPushConstantRanges = pipeline_layouts[i].push_constant_ranges, + .pPushConstantRanges = pipeline->push_constant_ranges, }; - vkok(vkCreatePipelineLayout(renderer->device, &create_info, renderer->allocator, &pipeline_layouts[i].handle)); + vkok(vkCreatePipelineLayout(renderer->device, &create_info, renderer->allocator, &pipeline->layout)); } for (u64 i = 0; i < graphics_pipeline_count; i += 1) @@ -1388,7 +1365,7 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren .pDepthStencilState = &depth_stencil_state_create_info, .pColorBlendState = &color_blend_state_create_info, .pDynamicState = &dynamic_state_create_info, - .layout = pipeline_layouts[create.layout_index].handle, + .layout = renderer->pipelines[i].layout, .renderPass = 0, .subpass = 0, .basePipelineHandle = 0, @@ -1401,108 +1378,278 @@ PipelineIndex renderer_graphics_pipelines_create(Renderer* renderer, Arena* aren for (u32 i = 0; i < graphics_pipeline_count; i += 1) { - pipelines[i] = (Pipeline) { - .handle = pipeline_handles[i], - .layout = { .value = create_data.pipelines.pointer[i].layout_index }, - }; + renderer->pipelines[i].handle = pipeline_handles[i]; } - return (PipelineIndex){ .value = 0 }; + return renderer; +} + +fn void destroy_image(Renderer* renderer, VulkanImage image) +{ + vkDestroyImageView(renderer->device, image.view, renderer->allocator); + vkDestroyImage(renderer->device, image.handle, renderer->allocator); + vkFreeMemory(renderer->device, image.memory, renderer->allocator); +} + +fn void swapchain_recreate(Renderer* renderer, RenderWindow* window, VkSurfaceCapabilitiesKHR surface_capabilities) +{ + VkSwapchainKHR old_swapchain = window->swapchain; + VkImageView old_swapchain_image_views[MAX_SWAPCHAIN_IMAGE_COUNT]; + + if (old_swapchain) + { + vkok(vkDeviceWaitIdle(renderer->device)); + for (u32 i = 0; i < window->swapchain_image_count; i += 1) + { + old_swapchain_image_views[i] = window->swapchain_image_views[i]; + } + } + + u32 queue_family_indices[] = { renderer->graphics_queue_family_index }; + VkImageUsageFlags swapchain_image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + window->swapchain_image_format = VK_FORMAT_B8G8R8A8_UNORM; + window->last_width = window->width; + window->last_height = window->height; + window->width = surface_capabilities.currentExtent.width; + window->height = surface_capabilities.currentExtent.height; + + VkSwapchainCreateInfoKHR swapchain_create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .surface = window->surface, + .minImageCount = surface_capabilities.minImageCount, + .imageFormat = window->swapchain_image_format, + .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + .imageExtent = surface_capabilities.currentExtent, + .imageArrayLayers = 1, + .imageUsage = swapchain_image_usage_flags, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = array_length(queue_family_indices), + .pQueueFamilyIndices = queue_family_indices, + .preTransform = surface_capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = VK_PRESENT_MODE_FIFO_KHR, + .clipped = 0, + .oldSwapchain = window->swapchain, + }; + + vkok(vkCreateSwapchainKHR(renderer->device, &swapchain_create_info, renderer->allocator, &window->swapchain)); + + assert(window->swapchain != old_swapchain); + + if (old_swapchain) + { + for (u32 i = 0; i < window->swapchain_image_count; i += 1) + { + vkDestroyImageView(renderer->device, old_swapchain_image_views[i], renderer->allocator); + } + + vkDestroySwapchainKHR(renderer->device, old_swapchain, renderer->allocator); + + destroy_image(renderer, window->render_image); + } + + { + vkok(vkGetSwapchainImagesKHR(renderer->device, window->swapchain, &window->swapchain_image_count, 0)); + + if (window->swapchain_image_count == 0) + { + failed_execution(); + } + + if (window->swapchain_image_count > array_length(window->swapchain_images)) + { + failed_execution(); + } + + vkok(vkGetSwapchainImagesKHR(renderer->device, window->swapchain, &window->swapchain_image_count, window->swapchain_images)); + + // VkImageViewUsageCreateInfo image_view_usage_create_info = { + // .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + // .pNext = 0, + // .usage = swapchain_create_info.imageUsage, + // }; + + for (u32 i = 0; i < window->swapchain_image_count; i += 1) + { + VkImageViewCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + // .pNext = &image_view_usage_create_info, + .flags = 0, + .image = window->swapchain_images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = swapchain_create_info.imageFormat, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + vkok(vkCreateImageView(renderer->device, &create_info, renderer->allocator, &window->swapchain_image_views[i])); + } + } + + window->render_image = vk_image_create(renderer->device, renderer->allocator, renderer->memory_properties, (VulkanImageCreate) { + .width = surface_capabilities.currentExtent.width, + .height = surface_capabilities.currentExtent.height, + .mip_levels = 1, + .format = window->swapchain_image_format, + .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + }); +} + +RenderWindow* renderer_window_initialize(Renderer* renderer, OSWindow window) +{ + RenderWindow* result = &renderer_window_memory; + { +#ifdef VK_USE_PLATFORM_WIN32_KHR + VkWin32SurfaceCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .hinstance = os_windows_get_module_handle(), + .hwnd = graphics_win32_window_get(window), + }; + vkok(vkCreateWin32SurfaceKHR(renderer->instance, &create_info, renderer->allocator, &result->surface)); +#endif +#ifdef VK_USE_PLATFORM_XLIB_KHR + VkXlibSurfaceCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = 0, + .flags = 0, + .dpy = x11_display_get(), + .window = x11_window_get(window), + }; + vkok(vkCreateXlibSurfaceKHR(renderer->instance, &create_info, renderer->allocator, &result->surface)); +#endif +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, +#endif +#ifdef VK_USE_PLATFORM_MACOS_MVK + VK_KHR_COCOA_SURFACE_EXTENSION_NAME, +#endif + } + + VkSurfaceCapabilitiesKHR surface_capabilities; + vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device, result->surface, &surface_capabilities)); + swapchain_recreate(renderer, result, surface_capabilities); + + for (u64 pipeline_index = 0; pipeline_index < BB_PIPELINE_COUNT; pipeline_index += 1) + { + auto* pipeline_descriptor = &renderer->pipelines[pipeline_index]; + auto* pipeline_instantiation = &result->pipeline_instantiations[pipeline_index]; + + u16 descriptor_type_counter[DESCRIPTOR_TYPE_COUNT] = {}; + + for (u64 descriptor_index = 0; descriptor_index < pipeline_descriptor->descriptor_set_count; descriptor_index += 1) + { + auto* descriptor_set_layout_bindings = &pipeline_descriptor->descriptor_set_layout_bindings[descriptor_index]; + + for (u64 binding_index = 0; binding_index < descriptor_set_layout_bindings->count; binding_index += 1) + { + auto* binding_descriptor = &descriptor_set_layout_bindings->buffer[binding_index]; + auto descriptor_type = descriptor_type_from_vulkan(binding_descriptor->descriptorType); + auto* counter_ptr = &descriptor_type_counter[descriptor_type]; + auto old_counter = *counter_ptr; + *counter_ptr = old_counter + binding_descriptor->descriptorCount; + } + } + + VkDescriptorPoolSize pool_sizes[DESCRIPTOR_TYPE_COUNT]; + u32 pool_size_count = 0; + + for (DescriptorType i = 0; i < DESCRIPTOR_TYPE_COUNT; i += 1) + { + auto count = descriptor_type_counter[i]; + if (count) + { + auto* pool_size = &pool_sizes[pool_size_count]; + pool_size_count += 1; + + *pool_size = (VkDescriptorPoolSize) { + .type = vulkan_descriptor_type(i), + .descriptorCount = count, + }; + } + } + + VkDescriptorPoolCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = 0, + .flags = 0, + .maxSets = pipeline_descriptor->descriptor_set_count, + .poolSizeCount = pool_size_count, + .pPoolSizes = pool_sizes, + }; + + VkDescriptorPool descriptor_pool; + vkok(vkCreateDescriptorPool(renderer->device, &create_info, renderer->allocator, &descriptor_pool)); + + VkDescriptorSetAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = 0, + .descriptorPool = descriptor_pool, + .descriptorSetCount = pipeline_descriptor->descriptor_set_count, + .pSetLayouts = pipeline_descriptor->descriptor_set_layouts, + }; + + vkok(vkAllocateDescriptorSets(renderer->device, &allocate_info, pipeline_instantiation->descriptor_sets)); + } + + for (u32 i = 0; i < MAX_FRAME_COUNT; i += 1) + { + VkCommandPoolCreateInfo command_pool_create_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = renderer->graphics_queue_family_index, + }; + + VkFenceCreateInfo fence_create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + + VkSemaphoreCreateInfo semaphore_create_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .flags = 0, + }; + + WindowFrame* frame = &result->frames[i]; + vkok(vkCreateCommandPool(renderer->device, &command_pool_create_info, renderer->allocator, &frame->command_pool)); + + VkCommandBufferAllocateInfo command_buffer_allocate_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = frame->command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + vkok(vkAllocateCommandBuffers(renderer->device, &command_buffer_allocate_info, &frame->command_buffer)); + vkok(vkCreateFence(renderer->device, &fence_create_info, renderer->allocator, &frame->render_fence)); + vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->render_semaphore)); + vkok(vkCreateSemaphore(renderer->device, &semaphore_create_info, renderer->allocator, &frame->swapchain_semaphore)); + frame->bound_pipeline = BB_PIPELINE_COUNT; + } + + return result; } fn WindowFrame* window_frame(RenderWindow* window) { - return &window->frames[window->frame_index % MAX_FRAMES]; + return &window->frames[window->frame_index % MAX_FRAME_COUNT]; } -// TODO: this might be the wrong abstraction layer -fn void queue_submit(Renderer* renderer, RenderWindow* window) -{ - auto* frame = window_frame(window); - - VkCommandBufferSubmitInfo command_buffer_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = frame->command_buffer, - .deviceMask = 0, - }, - }; - - VkSemaphoreSubmitInfo wait_semaphore_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = frame->swapchain_semaphore, - .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, - .deviceIndex = 0, - .value = 1, - }, - }; - - VkSemaphoreSubmitInfo signal_semaphore_submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = frame->render_semaphore, - .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, - .deviceIndex = 0, - .value = 1, - }, - }; - - VkSubmitInfo2 submit_info[] = { - { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .flags = 0, - .waitSemaphoreInfoCount = array_length(wait_semaphore_submit_info), - .pWaitSemaphoreInfos = wait_semaphore_submit_info, - .signalSemaphoreInfoCount = array_length(signal_semaphore_submit_info), - .pSignalSemaphoreInfos = signal_semaphore_submit_info, - .commandBufferInfoCount = array_length(command_buffer_submit_info), - .pCommandBufferInfos = command_buffer_submit_info, - }, - }; - - vkok(vkQueueSubmit2(renderer->graphics_queue, array_length(submit_info), submit_info, frame->render_fence)); -} - -fn void queue_present(Renderer* renderer, RenderWindow* window) -{ - auto* frame = window_frame(window); - const VkSwapchainKHR swapchains[] = { window->swapchain }; - const u32 swapchain_image_indices[] = { window->swapchain_image_index }; - const VkSemaphore wait_semaphores[] = { frame->render_semaphore }; - VkResult results[array_length(swapchains)]; - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = array_length(wait_semaphores), - .pWaitSemaphores = wait_semaphores, - .swapchainCount = array_length(swapchains), - .pSwapchains = swapchains, - .pImageIndices = swapchain_image_indices, - .pResults = results, - }; - - VkResult present_result = vkQueuePresentKHR(renderer->graphics_queue, &present_info); - if (present_result == VK_SUCCESS) - { - for (u32 i = 0; i < array_length(results); i += 1) - { - vkok_swapchain(results[i]); - } - } - else if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) - { - VkSurfaceCapabilitiesKHR surface_capabilities; - vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device, window->surface, &surface_capabilities)); - swapchain_recreate(renderer, window, surface_capabilities); - } - else - { - vkok(present_result); - } -} - -GraphicsWindowSize renderer_window_frame_begin(Renderer* renderer, RenderWindow* window) +void renderer_window_frame_begin(Renderer* renderer, RenderWindow* window) { auto* frame = window_frame(window); auto timeout = ~(u64)0; @@ -1528,39 +1675,119 @@ GraphicsWindowSize renderer_window_frame_begin(Renderer* renderer, RenderWindow* VkCommandBufferResetFlags reset_flags = 0; vkok(vkResetCommandBuffer(frame->command_buffer, reset_flags)); - auto window_size = graphics_window_size_get(window->graphics_window); + // Reset frame data + for (u32 i = 0; i < array_length(window->pipeline_instantiations); i += 1) + { + auto* pipeline_instantiation = &window->pipeline_instantiations[i]; + pipeline_instantiation->vertex_buffer.cpu.length = 0; + pipeline_instantiation->index_buffer.cpu.length = 0; + } +} - return window_size; +void buffer_destroy(Renderer* renderer, VulkanBuffer buffer) +{ + if (buffer.handle) + { + vkDestroyBuffer(renderer->device, buffer.handle, renderer->allocator); + } + + if (buffer.gpu_data) + { + if (buffer.type == BUFFER_TYPE_STAGING) + { + vkUnmapMemory(renderer->device, buffer.gpu_data); + } + + vkFreeMemory(renderer->device, buffer.gpu_data, renderer->allocator); + } } void renderer_window_frame_end(Renderer* renderer, RenderWindow* window) -{ - queue_submit(renderer, window); - - queue_present(renderer, window); - - window->frame_index += 1; -} - -void window_command_begin(RenderWindow* window) { auto* frame = window_frame(window); + // print("Frame index: {u32}\n", window->frame_index); + VkCommandBufferBeginInfo command_buffer_begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; vkok(vkBeginCommandBuffer(frame->command_buffer, &command_buffer_begin_info)); -} -void window_command_end(RenderWindow* window) -{ - auto* frame = window_frame(window); - vkok(vkEndCommandBuffer(frame->command_buffer)); -} + for (u32 i = 0; i < BB_PIPELINE_COUNT; i += 1) + { + auto* pipeline_instantiation = &window->pipeline_instantiations[i]; + + if (likely(pipeline_instantiation->vertex_buffer.cpu.length)) + { + auto old_vertex_buffer = pipeline_instantiation->vertex_buffer.gpu; + auto old_index_buffer = pipeline_instantiation->index_buffer.gpu; + + auto new_vertex_buffer_size = pipeline_instantiation->vertex_buffer.cpu.length * sizeof(pipeline_instantiation->vertex_buffer.cpu.pointer); + auto new_index_buffer_size = pipeline_instantiation->index_buffer.cpu.length * sizeof(pipeline_instantiation->index_buffer.cpu.pointer); + auto new_transient_buffer_size = new_vertex_buffer_size + new_index_buffer_size; + + if (unlikely(new_transient_buffer_size)) + { + buffer_destroy(renderer, pipeline_instantiation->transient_buffer); + pipeline_instantiation->transient_buffer = buffer_create(renderer, new_transient_buffer_size, BUFFER_TYPE_STAGING); + } + + if (unlikely(new_vertex_buffer_size > old_vertex_buffer.size)) + { + buffer_destroy(renderer, pipeline_instantiation->vertex_buffer.gpu); + pipeline_instantiation->vertex_buffer.gpu = buffer_create(renderer, new_vertex_buffer_size, BUFFER_TYPE_VERTEX); + } + + if (unlikely(new_index_buffer_size > old_index_buffer.size)) + { + buffer_destroy(renderer, pipeline_instantiation->index_buffer.gpu); + pipeline_instantiation->index_buffer.gpu = buffer_create(renderer, new_index_buffer_size, BUFFER_TYPE_INDEX); + } + + buffer_copy_to_host(pipeline_instantiation->transient_buffer, (Slice(HostBufferCopy)) array_to_slice(((HostBufferCopy[]) { + (HostBufferCopy) { + .source = (String) { + .pointer = (u8*)pipeline_instantiation->vertex_buffer.cpu.pointer, + .length = new_vertex_buffer_size, + }, + .destination_offset = 0, + }, + (HostBufferCopy) { + .source = (String) { + .pointer = (u8*)pipeline_instantiation->index_buffer.cpu.pointer, + .length = new_index_buffer_size, + }, + .destination_offset = new_vertex_buffer_size, + }, + }))); + + buffer_copy_to_local_command(frame->command_buffer, (Slice(LocalBufferCopy)) array_to_slice(((LocalBufferCopy[]) { + { + .destination = pipeline_instantiation->vertex_buffer.gpu, + .source = pipeline_instantiation->transient_buffer, + .regions = array_to_slice(((LocalBufferCopyRegion[]) { + { + .source_offset = 0, + .destination_offset = 0, + .size = new_vertex_buffer_size, + }, + })), + }, + { + .destination = pipeline_instantiation->index_buffer.gpu, + .source = pipeline_instantiation->transient_buffer, + .regions = array_to_slice(((LocalBufferCopyRegion[]) { + { + .source_offset = new_vertex_buffer_size, + .destination_offset = 0, + .size = new_index_buffer_size, + }, + })), + }, + }))); + } + } -void window_render_begin(RenderWindow* window) -{ - auto* frame = window_frame(window); vk_image_transition(frame->command_buffer, window->render_image.handle, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VkViewport viewports[] = { @@ -1618,11 +1845,55 @@ void window_render_begin(RenderWindow* window) }; vkCmdBeginRendering(frame->command_buffer, &rendering_info); -} -void window_render_end(RenderWindow* window) -{ - auto* frame = window_frame(window); + for (u32 i = 0; i < BB_PIPELINE_COUNT; i += 1) + { + auto* pipeline = &renderer->pipelines[i]; + auto* pipeline_instantiation = &window->pipeline_instantiations[i]; + + if (likely(pipeline_instantiation->vertex_buffer.cpu.length)) + { + auto bind_pipeline = frame->bound_pipeline != i; + // if (unlikely(bind_pipeline)) + { + vkCmdBindPipeline(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); + // print("Binding pipeline: 0x{u64}\n", pipeline->handle); + u32 dynamic_offset_count = 0; + u32* dynamic_offsets = 0; + u32 first_set = 0; + vkCmdBindDescriptorSets(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, first_set, pipeline->descriptor_set_count, pipeline_instantiation->descriptor_sets, dynamic_offset_count, dynamic_offsets); + // print("Binding descriptor sets: 0x{u64}\n", pipeline_instantiation->descriptor_sets); + frame->bound_pipeline = i; + } + + auto bind_index_buffer = frame->index_buffer != pipeline_instantiation->index_buffer.gpu.handle; + // if (unlikely(bind_index_buffer)) + { + vkCmdBindIndexBuffer(frame->command_buffer, pipeline_instantiation->index_buffer.gpu.handle, 0, VK_INDEX_TYPE_UINT32); + frame->index_buffer = pipeline_instantiation->index_buffer.gpu.handle; + // print("Binding descriptor sets: 0x{u64}\n", frame->index_buffer); + } + + auto push_constants = (GPUDrawPushConstants) + { + .vertex_buffer = pipeline_instantiation->vertex_buffer.gpu.address, + .width = window->width, + .height = window->height, + }; + + static_assert(sizeof(push_constants) == sizeof(frame->push_constants)); + + // if (unlikely(memcmp(&push_constants, &frame->push_constants, sizeof(push_constants)) != 0)) + { + auto push_constant_range = pipeline->push_constant_ranges[0]; + vkCmdPushConstants(frame->command_buffer, pipeline->layout, push_constant_range.stageFlags, push_constant_range.offset, push_constant_range.size, &push_constants); + frame->push_constants = push_constants; + } + + vkCmdDrawIndexed(frame->command_buffer, pipeline_instantiation->index_buffer.cpu.length, 1, 0, 0, 0); + } + } + vkCmdEndRendering(frame->command_buffer); vk_image_transition(frame->command_buffer, window->render_image.handle, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); @@ -1648,85 +1919,99 @@ void window_render_end(RenderWindow* window) }); vk_image_transition(frame->command_buffer, swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); -} -STRUCT(VulkanBuffer) -{ - VkBuffer handle; - VkDeviceMemory gpu_data; - u64 address; - VkDeviceSize size; -}; + vkok(vkEndCommandBuffer(frame->command_buffer)); -fn VulkanBuffer vk_buffer_create(VkDevice device, const VkAllocationCallbacks* allocation_callbacks, VkPhysicalDeviceMemoryProperties physical_device_memory_properties, VkDeviceSize buffer_size, VkBufferUsageFlags usage_flags, VkMemoryPropertyFlags memory_flags) -{ - VulkanBuffer result = { - .size = buffer_size, + VkCommandBufferSubmitInfo command_buffer_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .commandBuffer = frame->command_buffer, + .deviceMask = 0, + }, }; - VkBufferCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = 0, - .flags = 0, - .size = buffer_size, - .usage = usage_flags, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = 0, + VkSemaphoreSubmitInfo wait_semaphore_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = frame->swapchain_semaphore, + .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + .deviceIndex = 0, + .value = 1, + }, }; - vkok(vkCreateBuffer(device, &create_info, allocation_callbacks, &result.handle)); - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(device, result.handle, &memory_requirements); + VkSemaphoreSubmitInfo signal_semaphore_submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = frame->render_semaphore, + .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, + .deviceIndex = 0, + .value = 1, + }, + }; - u8 use_device_address_bit = !!(create_info.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - result.gpu_data = vk_allocate_memory(device, allocation_callbacks, physical_device_memory_properties, memory_requirements, memory_flags, use_device_address_bit); + VkSubmitInfo2 submit_info[] = { + { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .flags = 0, + .waitSemaphoreInfoCount = array_length(wait_semaphore_submit_info), + .pWaitSemaphoreInfos = wait_semaphore_submit_info, + .signalSemaphoreInfoCount = array_length(signal_semaphore_submit_info), + .pSignalSemaphoreInfos = signal_semaphore_submit_info, + .commandBufferInfoCount = array_length(command_buffer_submit_info), + .pCommandBufferInfos = command_buffer_submit_info, + }, + }; - VkDeviceSize memory_offset = 0; - vkok(vkBindBufferMemory(device, result.handle, result.gpu_data, memory_offset)); + vkok(vkQueueSubmit2(renderer->graphics_queue, array_length(submit_info), submit_info, frame->render_fence)); - u8 map_memory = !!(memory_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - assert(((map_memory | use_device_address_bit) == 0) | (map_memory == !use_device_address_bit)); - if (map_memory) + const VkSwapchainKHR swapchains[] = { window->swapchain }; + const u32 swapchain_image_indices[] = { window->swapchain_image_index }; + const VkSemaphore wait_semaphores[] = { frame->render_semaphore }; + VkResult results[array_length(swapchains)]; + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = array_length(wait_semaphores), + .pWaitSemaphores = wait_semaphores, + .swapchainCount = array_length(swapchains), + .pSwapchains = swapchains, + .pImageIndices = swapchain_image_indices, + .pResults = results, + }; + + VkResult present_result = vkQueuePresentKHR(renderer->graphics_queue, &present_info); + + if (present_result == VK_SUCCESS) { - void* data = 0; - VkDeviceSize offset = 0; - VkMemoryMapFlags map_flags = 0; - vkok(vkMapMemory(device, result.gpu_data, offset, memory_requirements.size, map_flags, &data)); - result.address = (u64)data; + for (u32 i = 0; i < array_length(results); i += 1) + { + vkok_swapchain(results[i]); + } + } + else if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) + { + VkSurfaceCapabilitiesKHR surface_capabilities; + vkok(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device, window->surface, &surface_capabilities)); + swapchain_recreate(renderer, window, surface_capabilities); + } + else + { + vkok(present_result); } - if (use_device_address_bit) - { - VkBufferDeviceAddressInfo device_address_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - .pNext = 0, - .buffer = result.handle, - }; - result.address = vkGetBufferDeviceAddress(device, &device_address_info); - } - - return result; + window->frame_index += 1; } -#define MAX_TEXTURES (16) -STRUCT(VulkanTexture) -{ - VulkanImage image; - VkSampler sampler; -}; -global_variable VulkanTexture textures[MAX_TEXTURES]; -global_variable u32 texture_count; - fn VkFormat vk_texture_format(TextureFormat format) { VkFormat result; switch (format) { - case R8_UNORM: + case TEXTURE_FORMAT_R8_UNORM: result = VK_FORMAT_R8_UNORM; break; - case R8G8B8A8_SRGB: + case TEXTURE_FORMAT_R8G8B8A8_SRGB: result = VK_FORMAT_R8G8B8A8_SRGB; break; } @@ -1738,9 +2023,9 @@ fn u32 format_channel_count(TextureFormat format) { switch (format) { - case R8_UNORM: + case TEXTURE_FORMAT_R8_UNORM: return 1; - case R8G8B8A8_SRGB: + case TEXTURE_FORMAT_R8G8B8A8_SRGB: return 4; } } @@ -1804,212 +2089,124 @@ TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_m return (TextureIndex) { .value = texture_index }; } -PipelineLayoutIndex renderer_pipeline_get_layout(PipelineIndex pipeline) -{ - return pipelines[pipeline.value].layout; -} -void renderer_update_pipeline_resources(Renderer* renderer, PipelineIndex pipeline_index, Slice(DescriptorSetUpdate) descriptor_updates) -{ - if (descriptor_updates.length > MAX_DESCRIPTOR_SET_UPDATE_COUNT) - { - failed_execution(); - } - - Pipeline* pipeline = &pipelines[pipeline_index.value]; - PipelineLayout* layout = &pipeline_layouts[pipeline->layout.value]; +// void window_bind_index_buffer(RenderWindow* window, BufferIndex index_buffer, u64 offset, IndexType index_type) +// { +// auto* frame = window_frame(window); +// auto* buffer = &buffers[index_buffer.value]; +// VkIndexType vk_index_type; +// switch (index_type) +// { +// case INDEX_TYPE_U16: +// vk_index_type = VK_INDEX_TYPE_UINT16; +// break; +// case INDEX_TYPE_U32: +// vk_index_type = VK_INDEX_TYPE_UINT32; +// break; +// } +// vkCmdBindIndexBuffer(frame->command_buffer, buffer->handle, offset, vk_index_type); +// } - VkWriteDescriptorSet write_descriptor_sets[MAX_DESCRIPTOR_SET_UPDATE_COUNT]; - VkDescriptorImageInfo images[MAX_DESCRIPTOR_SET_UPDATE_COUNT][MAX_TEXTURE_UPDATE_COUNT]; +// void window_push_constants(RenderWindow* window, PipelineIndex pipeline_index, SliceP(void) memories) +// { +// auto* pipeline = &pipelines[pipeline_index.value]; +// auto* pipeline_layout = &pipeline_layouts[pipeline->layout.value]; +// auto* frame = window_frame(window); +// +// if (memories.length != pipeline_layout->push_constant_range_count) +// { +// failed_execution(); +// } +// +// for (u64 i = 0; i < memories.length; i += 1) +// { +// auto* memory = memories.pointer[i]; +// auto push_constant_range = pipeline_layout->push_constant_ranges[i]; +// vkCmdPushConstants(frame->command_buffer, pipeline_layout->handle, push_constant_range.stageFlags, push_constant_range.offset, push_constant_range.size, memory); +// } +// } - for (u64 i = 0; i < descriptor_updates.length; i += 1) - { - DescriptorSetUpdate* in_update = &descriptor_updates.pointer[i]; - VkWriteDescriptorSet* out_update = &write_descriptor_sets[i]; - *out_update = (VkWriteDescriptorSet) - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = 0, - .dstSet = layout->descriptor_sets[in_update->set.value], - .dstBinding = in_update->binding, - .dstArrayElement = 0, - .descriptorCount = in_update->descriptor_count, - .descriptorType = vulkan_descriptor_type(in_update->type), - .pImageInfo = 0, - .pBufferInfo = 0, - .pTexelBufferView = 0, - }; - - switch (in_update->type) - { - case DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER: - { - auto* image_pointer = images[i]; - out_update->pImageInfo = image_pointer; - for (u32 i = 0; i < in_update->descriptor_count; i += 1) - { - VkDescriptorImageInfo* descriptor_image = &image_pointer[i]; - VulkanTexture* texture = &textures[in_update->textures[i].value]; - *descriptor_image = (VkDescriptorImageInfo) { - .sampler = texture->sampler, - .imageView = texture->image.view, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // TODO: specify - }; - } - } break; - case DESCRIPTOR_TYPE_COUNT: - unreachable(); - } - } - - u32 descriptor_copy_count = 0; - VkCopyDescriptorSet* descriptor_copies = 0; - vkUpdateDescriptorSets(renderer->device, descriptor_updates.length, write_descriptor_sets, descriptor_copy_count, descriptor_copies); -} - -#define MAX_BUFFER_COUNT (32) -global_variable VulkanBuffer buffers[MAX_BUFFER_COUNT]; -global_variable u32 buffer_count; - -BufferIndex renderer_buffer_create(Renderer* renderer, u64 size, BufferType type) -{ - auto buffer_index = buffer_count; - if (unlikely(buffer_index == MAX_BUFFER_COUNT)) - { - failed_execution(); - } - - u8 is_dst = (type == BUFFER_TYPE_VERTEX) | (type == BUFFER_TYPE_INDEX); - u8 is_src = type == BUFFER_TYPE_STAGING; - - VkBufferUsageFlags usage = - (VK_BUFFER_USAGE_TRANSFER_DST_BIT * is_dst) | - (VK_BUFFER_USAGE_TRANSFER_SRC_BIT * is_src) | - ((VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) * (type == BUFFER_TYPE_VERTEX)) | - (VK_BUFFER_USAGE_INDEX_BUFFER_BIT * (type == BUFFER_TYPE_INDEX)); - VkMemoryPropertyFlags memory_flags = - (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT * is_dst) | - ((VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) * is_src); - buffers[buffer_index] = vk_buffer_create(renderer->device, renderer->allocator, renderer->memory_properties, size, usage, memory_flags); - buffer_count = buffer_index + 1; - - return (BufferIndex){ .value = buffer_index }; -} - -void renderer_copy_to_host(BufferIndex buffer_index, Slice(HostBufferCopy) regions) -{ - VulkanBuffer* buffer = &buffers[buffer_index.value]; - auto* buffer_pointer = (u8*)buffer->address; - - for (u64 i = 0; i < regions.length; i += 1) - { - auto region = regions.pointer[i]; - memcpy(buffer_pointer + region.destination_offset, region.source.pointer, region.source.length); - } -} - -void renderer_copy_to_local(Renderer* renderer, Slice(LocalBufferCopy) copies) -{ - immediate_start(renderer->immediate); - - for (u64 i = 0; i < copies.length; i += 1) - { - auto copy = copies.pointer[i]; - auto* source_buffer = &buffers[copy.source.value]; - auto* destination_buffer = &buffers[copy.destination.value]; - - VkBufferCopy2 buffer_copies[MAX_LOCAL_BUFFER_COPY_COUNT]; - - for (u64 i = 0; i < copy.regions.length; i += 1) - { - auto copy_region = copy.regions.pointer[i]; - buffer_copies[i] = (VkBufferCopy2) { - .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2, - .pNext = 0, - .srcOffset = copy_region.source_offset, - .dstOffset = copy_region.destination_offset, - .size = copy_region.size, - }; - } - - VkCopyBufferInfo2 info = { - .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, - .pNext = 0, - .srcBuffer = source_buffer->handle, - .dstBuffer = destination_buffer->handle, - .regionCount = copy.regions.length, - .pRegions = buffer_copies, - }; - - vkCmdCopyBuffer2(renderer->immediate.command_buffer, &info); - } - - immediate_end(renderer->immediate); -} - -void window_bind_pipeline(RenderWindow* window, PipelineIndex pipeline_index) -{ - auto* frame = window_frame(window); - auto* pipeline = &pipelines[pipeline_index.value]; - vkCmdBindPipeline(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); -} - -void window_bind_index_buffer(RenderWindow* window, BufferIndex index_buffer, u64 offset, IndexType index_type) -{ - auto* frame = window_frame(window); - auto* buffer = &buffers[index_buffer.value]; - VkIndexType vk_index_type; - switch (index_type) - { - case INDEX_TYPE_U16: - vk_index_type = VK_INDEX_TYPE_UINT16; - break; - case INDEX_TYPE_U32: - vk_index_type = VK_INDEX_TYPE_UINT32; - break; - } - vkCmdBindIndexBuffer(frame->command_buffer, buffer->handle, offset, vk_index_type); -} - -void window_bind_pipeline_descriptor_sets(RenderWindow* window, PipelineIndex pipeline_index) -{ - auto* pipeline = &pipelines[pipeline_index.value]; - auto* pipeline_layout = &pipeline_layouts[pipeline->layout.value]; - auto* frame = window_frame(window); - - u32 dynamic_offset_count = 0; - u32* dynamic_offsets = 0; - u32 first_set = 0; - vkCmdBindDescriptorSets(frame->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout->handle, first_set, pipeline_layout->descriptor_set_count, pipeline_layout->descriptor_sets, dynamic_offset_count, dynamic_offsets); -} - -void window_push_constants(RenderWindow* window, PipelineIndex pipeline_index, SliceP(void) memories) -{ - auto* pipeline = &pipelines[pipeline_index.value]; - auto* pipeline_layout = &pipeline_layouts[pipeline->layout.value]; - auto* frame = window_frame(window); - - if (memories.length != pipeline_layout->push_constant_range_count) - { - failed_execution(); - } - - for (u64 i = 0; i < memories.length; i += 1) - { - auto* memory = memories.pointer[i]; - auto push_constant_range = pipeline_layout->push_constant_ranges[i]; - vkCmdPushConstants(frame->command_buffer, pipeline_layout->handle, push_constant_range.stageFlags, push_constant_range.offset, push_constant_range.size, memory); - } -} - -u64 buffer_address(BufferIndex buffer_index) -{ - auto* buffer = &buffers[buffer_index.value]; - return buffer->address; -} +// u64 buffer_address(BufferIndex buffer_index) +// { +// auto* buffer = &buffers[buffer_index.value]; +// return buffer->address; +// } void window_draw_indexed(RenderWindow* window, u32 index_count, u32 instance_count, u32 first_index, s32 vertex_offset, u32 first_instance) { auto* frame = window_frame(window); vkCmdDrawIndexed(frame->command_buffer, index_count, instance_count, first_index, vertex_offset, first_instance); } + +fn void window_texture_update_begin(RenderWindow* window, BBPipeline pipeline_index, u32 descriptor_count) +{ + auto* pipeline_instantiation = &window->pipeline_instantiations[pipeline_index]; + assert(descriptor_count <= array_length(pipeline_instantiation->texture_descriptors)); + + pipeline_instantiation->descriptor_set_update = (VkWriteDescriptorSet) { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = 0, + .dstSet = pipeline_instantiation->descriptor_sets[0], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = descriptor_count, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = pipeline_instantiation->texture_descriptors, + .pBufferInfo = 0, + .pTexelBufferView = 0, + }; +} + +void window_rect_texture_update_begin(RenderWindow* window) +{ + window_texture_update_begin(window, BB_PIPELINE_RECT, RECT_TEXTURE_SLOT_COUNT); +} + +fn void window_queue_pipeline_texture_update(RenderWindow* window, BBPipeline pipeline_index, u32 resource_slot, TextureIndex texture_index) +{ + auto* pipeline_instantiation = &window->pipeline_instantiations[pipeline_index]; + VkDescriptorImageInfo* descriptor_image = &pipeline_instantiation->texture_descriptors[resource_slot]; + VulkanTexture* texture = &textures[texture_index.value]; + *descriptor_image = (VkDescriptorImageInfo) { + .sampler = texture->sampler, + .imageView = texture->image.view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // TODO: specify + }; +} + +void window_queue_rect_texture_update(RenderWindow* window, RectTextureSlot slot, TextureIndex texture_index) +{ + window_queue_pipeline_texture_update(window, BB_PIPELINE_RECT, slot, texture_index); +} + +void renderer_queue_font_update(Renderer* renderer, RenderWindow* window, RenderFontType type, TextureAtlas atlas) +{ + static_assert(RECT_TEXTURE_SLOT_MONOSPACE_FONT < RECT_TEXTURE_SLOT_PROPORTIONAL_FONT); + auto slot = RECT_TEXTURE_SLOT_MONOSPACE_FONT + type; + window_queue_rect_texture_update(window, slot, atlas.texture); + renderer->fonts[type] = atlas; +} + +fn void window_texture_update_end(Renderer* renderer, RenderWindow* window, BBPipeline pipeline_index) +{ + auto* pipeline_instantiation = &window->pipeline_instantiations[pipeline_index]; + u32 descriptor_copy_count = 0; + VkCopyDescriptorSet* descriptor_copies = 0; + vkUpdateDescriptorSets(renderer->device, 1, &pipeline_instantiation->descriptor_set_update, descriptor_copy_count, descriptor_copies); +} + +void window_rect_texture_update_end(Renderer* renderer, RenderWindow* window) +{ + window_texture_update_end(renderer, window, BB_PIPELINE_RECT); +} + +void window_pipeline_add_vertices(RenderWindow* window, BBPipeline pipeline_index, String vertex_memory) +{ + vb_copy_string(&window->pipeline_instantiations[pipeline_index].vertex_buffer.cpu, vertex_memory); +} + +void window_pipeline_add_indices(RenderWindow* window, BBPipeline pipeline_index, Slice(u32) indices) +{ + auto* index_pointer = vb_add(&window->pipeline_instantiations[pipeline_index].index_buffer.cpu, indices.length); + memcpy(index_pointer, indices.pointer, indices.length * sizeof(*indices.pointer)); +} diff --git a/bootstrap/std/shader_compilation.c b/bootstrap/std/shader_compilation.c index a0938e2..215de9e 100644 --- a/bootstrap/std/shader_compilation.c +++ b/bootstrap/std/shader_compilation.c @@ -116,7 +116,11 @@ String compile_shader(Arena* arena, String path, ShaderStage shader_stage) strlit(".spv"), }))); char* arguments[] = { +#if _WIN32 + "C:/VulkanSDK/1.3.296.0/Bin/glslangValidator.exe", +#else "/usr/bin/glslangValidator", +#endif "-V", string_to_c(path), "-o", diff --git a/bootstrap/std/ui_core.c b/bootstrap/std/ui_core.c new file mode 100644 index 0000000..b38168d --- /dev/null +++ b/bootstrap/std/ui_core.c @@ -0,0 +1,3 @@ +#include + +