From f984f245aa355802afbbc49d7b8aab7aef38e458 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Wed, 6 Nov 2024 17:50:42 -0700 Subject: [PATCH] Double buffered GPUHexContext --- client/include/hex.h | 20 ++-- client/src/draw.c | 18 ++-- client/src/gpu.c | 12 +-- client/src/hex.c | 61 ++++++++++-- client/src/main.c | 216 +++++++++++++++++++++++-------------------- 5 files changed, 191 insertions(+), 136 deletions(-) diff --git a/client/include/hex.h b/client/include/hex.h index 4ba3065..b0c557a 100644 --- a/client/include/hex.h +++ b/client/include/hex.h @@ -13,6 +13,11 @@ #define REGION_WIDTH (HEX_X*REGION_DIAMETER) #define REGION_HEIGHT (HEX_Z*REGION_DIAMETER) +extern vec3 hex_vertices[]; +extern vec3 hex_starts[]; +extern vec3 hex_directions[]; +extern int hex_indices[]; + typedef struct GPUHexStruct { float height[6]; uint32_t color[7]; @@ -44,23 +49,24 @@ typedef struct GPUHexContextStruct { vec4 hover_end; uint32_t current_map; uint32_t clicked_region; - int32_t clicked_hex; + uint32_t clicked_hex; uint32_t hovered_region; - int32_t hovered_hex; + uint32_t hovered_hex; VkDeviceAddress regions[MAX_LOADED_REGIONS]; } GPUHexContext; typedef struct HexContextStruct { - VkDeviceAddress address; - VkBuffer context; - VmaAllocation context_memory; + VkDeviceAddress address[MAX_FRAMES_IN_FLIGHT]; + VkBuffer context[MAX_FRAMES_IN_FLIGHT]; + VmaAllocation context_memory[MAX_FRAMES_IN_FLIGHT]; GraphicsPipeline graphics; - GraphicsPipeline ray_pipeline; GraphicsPipeline highlight_pipeline; +#ifdef DRAW_HEX_RAYS + GraphicsPipeline ray_pipeline; +#endif HexRegion* regions[MAX_LOADED_REGIONS]; - GPUHexContext data; } HexContext; diff --git a/client/src/draw.c b/client/src/draw.c index 9f41c3f..e82f18d 100644 --- a/client/src/draw.c +++ b/client/src/draw.c @@ -5,8 +5,6 @@ void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context, double time, uint32_t frame) { UIPushConstant push = { .time = (float)time, - .layer = 0, - .pad = frame, }; vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.pipeline); @@ -25,20 +23,22 @@ void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context, doubl void record_hex_draw(VkCommandBuffer command_buffer, HexContext* hex, double time, uint32_t frame) { HexPushConstant push = { - .context = hex->address, + .context = hex->address[frame], .time = (float)time, }; + vkCmdPushConstants(command_buffer, hex->graphics.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(HexPushConstant), &push); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->graphics.pipeline); vkCmdDraw(command_buffer, 18, REGION_HEX_COUNT*MAX_LOADED_REGIONS, 0, 0); - // Draw rays - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->ray_pipeline.pipeline); - vkCmdDraw(command_buffer, 2, 2, 0, 0); - - // Draw Highlights vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->highlight_pipeline.pipeline); vkCmdDraw(command_buffer, 18, 2, 0, 0); + +#ifdef DRAW_HEX_RAYS + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->ray_pipeline.pipeline); + vkCmdDraw(command_buffer, 2, 2, 0, 0); +#endif } void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui, uint32_t frame) { @@ -144,7 +144,7 @@ VkResult draw_frame( VK_RESULT(vkEndCommandBuffer(compute_commands)); frame->compute_index += 1; - VkPipelineStageFlags compute_wait_stages[] = {VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; + VkPipelineStageFlags compute_wait_stages[] = {VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT}; VkTimelineSemaphoreSubmitInfo compute_timeline = { .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, .waitSemaphoreValueCount = 1, diff --git a/client/src/gpu.c b/client/src/gpu.c index 8de7ed1..589cff0 100644 --- a/client/src/gpu.c +++ b/client/src/gpu.c @@ -952,6 +952,7 @@ VkResult create_depth_image( VmaAllocationCreateInfo allocation_info = { .usage = VMA_MEMORY_USAGE_AUTO, + .preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, }; VkResult result; @@ -1294,17 +1295,6 @@ VkResult add_transfer( VkDeviceSize src_offset = 0; for(uint32_t i = 0; i < transfer->count; i++) { -/* - -Adding size 32 write to 0x4b000000004b at offset 0 -size = 32, offset = 0, info->offset = 0 -Adding size 8 write to 0x4b000000004b at offset 44 -size = 8, offset = 44, info->offset = 0 -Transferring 32 bytes: 90605F3D228D5A448B925AC4C8FA45429E195A42E0EE36C4E0CA214400B07F3F to 0x4b000000004b - -*/ - - VkDeviceSize diff = offset - transfer->infos[i].offset; if(transfer->infos[i].buffer == buffer && transfer->infos[i].offset <= offset diff --git a/client/src/hex.c b/client/src/hex.c index 72b9392..98c2236 100644 --- a/client/src/hex.c +++ b/client/src/hex.c @@ -4,6 +4,43 @@ #include #include +// cos(I*PI/3)/2, sin(I*PI/3)/2 +vec3 hex_vertices[] = { + { 1.0/2, 0, 0}, + { 1.0/4, 0, SQRT3/4}, + {-1.0/4, 0, SQRT3/4}, + {-1.0/2, 0, 0}, + {-1.0/4, 0, -SQRT3/4}, + { 1.0/4, 0, -SQRT3/4}, +}; + +vec3 hex_starts[] = { + { 0, 0, HEX_Z}, + {-HEX_X, 0, HEX_Z/2}, + {-HEX_X, 0, -HEX_Z/2}, + { 0, 0, -HEX_Z}, + { HEX_X, 0, -HEX_Z/2}, + { HEX_X, 0, HEX_Z/2}, +}; + +vec3 hex_directions[] = { + {-HEX_X, 0, -HEX_Z/2}, + { 0, 0, -HEX_Z}, + { HEX_X, 0, -HEX_Z/2}, + { HEX_X, 0, HEX_Z/2}, + { 0, 0, HEX_Z}, + {-HEX_X, 0, HEX_Z/2}, +}; + +int hex_indices[] = { + 0, 2, 1, + 0, 3, 2, + 0, 4, 3, + 0, 5, 4, + 0, 6, 5, + 0, 1, 6, +}; + VkResult create_ray_pipeline( RenderContext* gpu, GraphicsPipeline* pipeline) { @@ -475,20 +512,24 @@ VkResult create_hex_context( VkResult result; VK_RESULT(create_hex_pipeline(gpu, &context->graphics)); +#ifdef DRAW_HEX_RAYS VK_RESULT(create_ray_pipeline(gpu, &context->ray_pipeline)); +#endif VK_RESULT(create_hex_highlight_pipeline(gpu, &context->highlight_pipeline)); memset(&context->data, 0, sizeof(GPUHexContext)); glm_perspective(PERSPECTIVE_FOVY, (float)gpu->swapchain_extent.width/(float)gpu->swapchain_extent.height, PERSPECTIVE_NEARZ, PERSPECTIVE_FARZ, context->data.proj); glm_mat4_identity(context->data.view); - VK_RESULT(create_storage_buffer( - gpu->allocator, - 0, - sizeof(GPUHexContext), - &context->context, - &context->context_memory)); - context->address = buffer_address(gpu->device, context->context); - VK_RESULT(add_transfer(&context->data, context->context, 0, sizeof(GPUHexContext), gpu->current_frame, gpu)); + for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VK_RESULT(create_storage_buffer( + gpu->allocator, + 0, + sizeof(GPUHexContext), + &context->context[i], + &context->context_memory[i])); + context->address[i] = buffer_address(gpu->device, context->context[i]); + } + VK_RESULT(add_transfers(&context->data, context->context, 0, sizeof(GPUHexContext), gpu)); return VK_SUCCESS; } @@ -522,8 +563,8 @@ VkResult set_hex_region(int32_t q, int32_t r, int32_t y, uint32_t map, HexRegion VK_RESULT(add_transfer(&(*region)->data.q, (*region)->region, offsetof(GPUHexRegion, q), sizeof(int32_t)*3 + sizeof(uint32_t), gpu->current_frame, gpu)); (*region)->address = buffer_address(gpu->device, (*region)->region); - - VK_RESULT(add_transfer(&(*region)->address, hex->context, offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*i, sizeof(VkDeviceAddress), gpu->current_frame, gpu)); + // TODO: load hex data before setting address so that data is synchronized + VK_RESULT(add_transfers(&(*region)->address, hex->context, offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*i, sizeof(VkDeviceAddress), gpu)); return VK_SUCCESS; } diff --git a/client/src/main.c b/client/src/main.c index 2e51267..ae32ea5 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -56,76 +56,14 @@ void* network_thread(void* data) { return NULL; } -// cos(I*PI/3)/2, sin(I*PI/3)/2 -vec3 hex_vertices[] = { - { 1.0/2, 0, 0}, - { 1.0/4, 0, SQRT3/4}, - {-1.0/4, 0, SQRT3/4}, - {-1.0/2, 0, 0}, - {-1.0/4, 0, -SQRT3/4}, - { 1.0/4, 0, -SQRT3/4}, -}; - -vec3 hex_starts[] = { - { 0, 0, HEX_Z}, - {-HEX_X, 0, HEX_Z/2}, - {-HEX_X, 0, -HEX_Z/2}, - { 0, 0, -HEX_Z}, - { HEX_X, 0, -HEX_Z/2}, - { HEX_X, 0, HEX_Z/2}, -}; - -vec3 hex_directions[] = { - {-HEX_X, 0, -HEX_Z/2}, - { 0, 0, -HEX_Z}, - { HEX_X, 0, -HEX_Z/2}, - { HEX_X, 0, HEX_Z/2}, - { 0, 0, HEX_Z}, - {-HEX_X, 0, HEX_Z/2}, -}; - -int hex_indices[] = { - 0, 2, 1, - 0, 3, 2, - 0, 4, 3, - 0, 5, 4, - 0, 6, 5, - 0, 1, 6, -}; - -bool ray_hex_intersect(float* distance, vec4 ray_start, vec4 ray_end, uint32_t region_index, uint32_t hex_index, HexContext* context) { +bool ray_hex_intersect(float* distance, vec3 start, vec3 dir, vec3 region_offset, uint32_t hex_index, HexRegion* region) { /* Ray-hexagon intersection 1. For each triangle in the hexagon, check for intersection 2. If intersections, return the closest along the ray */ - GPUHexRegion* region = &context->regions[region_index]->data; - GPUHex* hex = ®ion->hexes[hex_index]; - vec3 start; - start[0] = ray_start[0]/ray_start[3]; - start[1] = ray_start[1]/ray_start[3]; - start[2] = ray_start[2]/ray_start[3]; - - vec3 end; - end[0] = ray_end[0]/ray_end[3]; - end[1] = ray_end[1]/ray_end[3]; - end[2] = ray_end[2]/ray_end[3]; - - vec3 dir; - dir[0] = end[0] - start[0]; - dir[1] = end[1] - start[1]; - dir[2] = end[2] - start[2]; - - - float dir_len = glm_vec3_norm(dir); - glm_vec3_divs(dir, dir_len, dir); - - vec3 region_offset = { - ((float)region->q + (float)region->r/2)*REGION_WIDTH - region->r*HEX_X/2, - 0, - 0.75*region->r*REGION_HEIGHT + 0.25*region->r*HEX_Z + 0.5*region->q*HEX_Z, - }; + GPUHex* hex = ®ion->data.hexes[hex_index]; float center_height = (hex->height[0] + hex->height[1] @@ -207,6 +145,74 @@ bool ray_hex_intersect(float* distance, vec4 ray_start, vec4 ray_end, uint32_t r return intersect; } +bool ray_region_intersect(float* distance, uint32_t* hid, vec3 start, vec3 dir, HexRegion* region) { + bool intersect = false; + float temp_distance; + *distance = INFINITY; + + vec3 region_offset = { + ((float)region->data.q + (float)region->data.r/2)*REGION_WIDTH - region->data.r*HEX_X/2, + 0, + 0.75*region->data.r*REGION_HEIGHT + 0.25*region->data.r*HEX_Z + 0.5*region->data.q*HEX_Z, + }; + + for(uint32_t temp_hid = 0; temp_hid < REGION_HEX_COUNT; temp_hid++) { + if(ray_hex_intersect(&temp_distance, start, dir, region_offset, temp_hid, region)) { + if(temp_distance < *distance) { + intersect = true; + *hid = temp_hid; + *distance = temp_distance; + } + } + } + + return intersect; +} + +bool ray_world_intersect(float* distance, uint32_t* rid, uint32_t* hid, vec4 ray_start, vec4 ray_end, HexContext* context) { + vec3 start; + start[0] = ray_start[0]/ray_start[3]; + start[1] = ray_start[1]/ray_start[3]; + start[2] = ray_start[2]/ray_start[3]; + + vec3 end; + end[0] = ray_end[0]/ray_end[3]; + end[1] = ray_end[1]/ray_end[3]; + end[2] = ray_end[2]/ray_end[3]; + + vec3 dir; + dir[0] = end[0] - start[0]; + dir[1] = end[1] - start[1]; + dir[2] = end[2] - start[2]; + float mdir = glm_vec3_norm(dir); + glm_vec3_divs(dir, mdir, dir); + + bool intersect = false; + float temp_distance; + uint32_t temp_hid; + *distance = INFINITY; + + for(uint32_t temp_rid = 0; temp_rid < MAX_LOADED_REGIONS; temp_rid++) { + HexRegion* region = context->regions[temp_rid]; + if(region == NULL) { + continue; + } else if(region->data.map != context->data.current_map) { + continue; + } + + if(ray_region_intersect(&temp_distance, &temp_hid, start, dir, region)) { + if(temp_distance < *distance) { + intersect = true; + *hid = temp_hid; + *rid = temp_rid; + *distance = temp_distance; + } + } + } + + return intersect; +} + vec3 up = {0, 1, 0}; VkResult main_thread(ClientContext* context) { @@ -251,7 +257,7 @@ VkResult main_thread(ClientContext* context) { }; context->hex->data.current_map = 0x01; - add_transfer(&context->hex->data.current_map, context->hex->context, offsetof(GPUHexContext, current_map), sizeof(uint32_t), context->render->current_frame, context->render); + add_transfers(&context->hex->data.current_map, context->hex->context, offsetof(GPUHexContext, current_map), sizeof(uint32_t), context->render); uint32_t region = 0; for(int32_t q = -5; q < 5; q++) { @@ -264,7 +270,7 @@ VkResult main_thread(ClientContext* context) { } regions[region]->data.hexes[i].color[6] = colors[(q+r+50) % (sizeof(colors)/sizeof(uint32_t))]; } - VK_RESULT(add_transfer(®ions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, 0, context->render)); + VK_RESULT(add_transfer(®ions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, context->render->current_frame, context->render)); region++; } } @@ -302,12 +308,11 @@ VkResult main_thread(ClientContext* context) { PERSPECTIVE_NEARZ, PERSPECTIVE_FARZ, context->hex->data.proj); - VK_RESULT(add_transfer( + VK_RESULT(add_transfers( &context->hex->data.proj, context->hex->context, offsetof(GPUHexContext, proj), sizeof(mat4), - context->render->current_frame, context->render)); } @@ -343,7 +348,7 @@ VkResult main_thread(ClientContext* context) { glm_mat4_mul(context->hex->data.proj, context->hex->data.view, regular); glm_mat4_inv(regular, context->inverse); - add_transfer(&context->hex->data, context->hex->context, 0, 2*sizeof(mat4), context->render->current_frame, context->render); + add_transfers(&context->hex->data, context->hex->context, 0, 2*sizeof(mat4), context->render); } if(context->clicked_hex[0] != 0 || context->clicked_hex[1] != 0) { @@ -471,25 +476,33 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) break; case GLFW_MOUSE_BUTTON_LEFT: if(action == GLFW_PRESS) { - cursor_to_world_ray(context, cursor, context->hex->data.click_start, context->hex->data.click_end); - add_transfer(&context->hex->data.click_start, context->hex->context, offsetof(GPUHexContext, click_start), sizeof(vec4)*2, context->render->current_frame, context->render); + cursor_to_world_ray( + context, + cursor, + context->hex->data.click_start, context->hex->data.click_end); + add_transfers( + &context->hex->data.click_start, + context->hex->context, + offsetof(GPUHexContext, click_start), + sizeof(vec4)*2, + context->render); // Hex intersections float distance; - for(uint32_t r = 0; r < MAX_LOADED_REGIONS; r++) { - if(context->hex->regions[r] == NULL) { - continue; - } else if(context->hex->regions[r]->data.map != context->hex->data.current_map) { - continue; - } - for(uint32_t h = 0; h < REGION_HEX_COUNT; h++) { - if(ray_hex_intersect(&distance, context->hex->data.click_start, context->hex->data.click_end, r, h, context->hex)) { - context->hex->data.clicked_region = r; - context->hex->data.clicked_hex = h; - add_transfer(&context->hex->data.clicked_region, context->hex->context, offsetof(GPUHexContext, clicked_region), sizeof(uint32_t)*2, context->render->current_frame, context->render); - } - } - } + if(ray_world_intersect( + &distance, + &context->hex->data.clicked_region, + &context->hex->data.clicked_hex, + context->hex->data.click_start, + context->hex->data.click_end, + context->hex)) { + add_transfers( + &context->hex->data.clicked_region, + context->hex->context, + offsetof(GPUHexContext, clicked_region), + sizeof(uint32_t)*2, + context->render); + } // UI intersections for(uint32_t c = 0; c < context->ui->max_containers; c++) { @@ -533,23 +546,28 @@ void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) { context->cursor[0] = xpos; context->cursor[1] = ypos; cursor_to_world_ray(context, context->cursor, context->hex->data.hover_start, context->hex->data.hover_end); - add_transfer(&context->hex->data.hover_start, context->hex->context, offsetof(GPUHexContext, hover_start), sizeof(vec4)*2, context->render->current_frame, context->render); + add_transfers( + &context->hex->data.hover_start, + context->hex->context, + offsetof(GPUHexContext, hover_start), + sizeof(vec4)*2, + context->render); // Hex intersections float distance; - for(uint32_t r = 0; r < MAX_LOADED_REGIONS; r++) { - if(context->hex->regions[r] == NULL) { - continue; - } else if(context->hex->regions[r]->data.map != context->hex->data.current_map) { - continue; - } - for(uint32_t h = 0; h < REGION_HEX_COUNT; h++) { - if(ray_hex_intersect(&distance, context->hex->data.hover_start, context->hex->data.hover_end, r, h, context->hex)) { - context->hex->data.hovered_region = r; - context->hex->data.hovered_hex = h; - add_transfer(&context->hex->data.hovered_region, context->hex->context, offsetof(GPUHexContext, hovered_region), sizeof(uint32_t)*2, context->render->current_frame, context->render); - } - } + if(ray_world_intersect( + &distance, + &context->hex->data.hovered_region, + &context->hex->data.hovered_hex, + context->hex->data.hover_start, + context->hex->data.hover_end, + context->hex)) { + add_transfers( + &context->hex->data.hovered_region, + context->hex->context, + offsetof(GPUHexContext, hovered_region), + sizeof(uint32_t)*2, + context->render); } }