Double buffered GPUHexContext

main
noah metz 2024-11-06 17:50:42 -07:00
parent 32963fce07
commit f984f245aa
5 changed files with 191 additions and 136 deletions

@ -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;

@ -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,

@ -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

@ -4,6 +4,43 @@
#include <stdio.h>
#include <string.h>
// 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;
}

@ -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 = &region->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 = &region->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(&regions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, 0, context->render));
VK_RESULT(add_transfer(&regions[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);
}
}