roleplay/client/src/draw.c

246 lines
10 KiB
C

#include "draw.h"
#include "hex.h"
#include "vulkan/vulkan_core.h"
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);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 0, 1, &ui_context->font_samplers, 0, NULL);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 1, 1, &ui_context->font_textures, 0, NULL);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 2, 1, &ui_context->samplers, 0, NULL);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 3, 1, &ui_context->textures, 0, NULL);
for(uint32_t i = 0; i < ui_context->max_containers; i++) {
for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) {
push.layer = ui_context->containers[i].layers[j].address[frame];
vkCmdPushConstants(command_buffer, ui_context->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, &push);
vkCmdDrawIndirect(command_buffer, ui_context->containers[i].layers[j].layer[frame], offsetof(GPULayer, draw), 1, 0);
}
}
}
void record_hex_draw(VkCommandBuffer command_buffer, HexContext* hex, double time, uint32_t frame) {
HexPushConstant push = {
.context = hex->address,
.time = (float)time,
.region = 0,
};
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);
}
void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui, uint32_t frame) {
UIPushConstant push = {
.time = 0.0,
.layer = 0,
.pad = frame,
};
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui->string_pipeline.pipeline);
for(uint32_t i = 0; i < ui->max_containers; i++) {
if(ui->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui->containers[i].layer_count; j++) {
command_copy_buffer(command_buffer, ui->containers[i].layers[j].layer[frame], ui->containers[i].layers[j].layer[frame], offsetof(GPULayer, num_drawables), offsetof(GPULayer, draw) + offsetof(DrawCommand, instance_count), sizeof(uint32_t));
}
}
}
for(uint32_t i = 0; i < ui->max_containers; i++) {
if(ui->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui->containers[i].layer_count; j++) {
push.layer = ui->containers[i].layers[j].address[frame];
vkCmdPushConstants(command_buffer, ui->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, &push);
vkCmdDispatchIndirect(command_buffer, ui->containers[i].layers[j].layer[frame], offsetof(GPULayer, dispatch_strings));
}
}
}
}
VkResult draw_frame(
RenderContext* context,
UIContext* ui,
HexContext* hex,
double time) {
VkResult result;
FrameContext* frame = &context->frame[context->current_frame];
VkFence fences[] = {frame->ready};
VK_RESULT(vkWaitForFences(context->device, 1, fences, VK_TRUE, UINT64_MAX));
VK_RESULT(vkResetFences(context->device, 1, fences));
VkCommandBufferBeginInfo begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
TransferBuffer* transfer = &frame->transfers[frame->transfer_index % 2];
if(transfer->count > 0) {
VkCommandBuffer transfer_commands = frame->transfer_commands;
VK_RESULT(vkResetCommandBuffer(transfer_commands, 0));
VK_RESULT(vkBeginCommandBuffer(transfer_commands, &begin_info));
VkDeviceSize src_offset = 0;
for(uint32_t tid = 0; tid < transfer->count; tid++) {
command_copy_buffer(
transfer_commands,
transfer->buffer,
transfer->infos[tid].buffer,
src_offset,
transfer->infos[tid].offset,
transfer->infos[tid].size);
src_offset += transfer->infos[tid].size;
}
VK_RESULT(vkEndCommandBuffer(transfer_commands));
frame->transfer_index += 1;
transfer->count = 0;
transfer->written = 0;
VkTimelineSemaphoreSubmitInfo transfer_timeline = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.signalSemaphoreValueCount = 1,
.pSignalSemaphoreValues = &frame->transfer_index,
};
VkSubmitInfo transfer_submit = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &transfer_commands,
.pSignalSemaphores = &frame->transfer,
.signalSemaphoreCount = 1,
.pNext = &transfer_timeline,
};
VK_RESULT(vkQueueSubmit(context->transfer_queue.handle, 1, &transfer_submit, VK_NULL_HANDLE));
VkCommandBuffer compute_commands = frame->compute_commands;
VK_RESULT(vkResetCommandBuffer(compute_commands, 0));
VK_RESULT(vkBeginCommandBuffer(compute_commands, &begin_info));
VkMemoryBarrier compute_barrier = {
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
};
vkCmdPipelineBarrier(compute_commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &compute_barrier, 0, NULL, 0, NULL);
record_ui_compute(compute_commands, ui, context->current_frame);
VK_RESULT(vkEndCommandBuffer(compute_commands));
frame->compute_index += 1;
VkPipelineStageFlags compute_wait_stages[] = {VK_PIPELINE_STAGE_ALL_COMMANDS_BIT};
VkTimelineSemaphoreSubmitInfo compute_timeline = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.waitSemaphoreValueCount = 1,
.pWaitSemaphoreValues = &frame->transfer_index,
.signalSemaphoreValueCount = 1,
.pSignalSemaphoreValues = &frame->compute_index,
};
VkSubmitInfo compute_submit = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &compute_commands,
.pSignalSemaphores = &frame->compute,
.signalSemaphoreCount = 1,
.pWaitSemaphores = &frame->transfer,
.pWaitDstStageMask = compute_wait_stages,
.waitSemaphoreCount = 1,
.pNext = &compute_timeline,
};
VK_RESULT(vkQueueSubmit(context->transfer_queue.handle, 1, &compute_submit, VK_NULL_HANDLE));
}
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, frame->image, VK_NULL_HANDLE, &image_index);
if(result == VK_ERROR_OUT_OF_DATE_KHR) {
VK_RESULT(recreate_framebuffer(context));
} else if(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
return result;
}
VkCommandBuffer command_buffer = context->swapchain_command_buffers[image_index];
VK_RESULT(vkResetCommandBuffer(command_buffer, 0));
VK_RESULT(vkBeginCommandBuffer(command_buffer, &begin_info));
VkViewport viewport = {
.width = context->swapchain_extent.width,
.height = context->swapchain_extent.height,
.maxDepth = 1.0f,
.minDepth = 0.0f,
};
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
VkRect2D scissor = {
.extent = context->swapchain_extent,
};
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
VkClearValue clear_values[2] = {{.color={{0.0f, 0.0f, 0.0f, 0.0f}}}, {.depthStencil={1.0f, 0.0f}}};
VkRenderPassBeginInfo render_pass_begin = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = context->render_pass,
.framebuffer = context->swapchain_framebuffers[image_index],
.renderArea.offset = {0, 0},
.renderArea.extent = context->swapchain_extent,
.clearValueCount = 2,
.pClearValues = clear_values,
};
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
record_hex_draw(command_buffer, hex, time, context->current_frame);
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
record_ui_draw(command_buffer, ui, time, context->current_frame);
vkCmdEndRenderPass(command_buffer);
VK_RESULT(vkEndCommandBuffer(command_buffer));
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT};
VkSemaphore wait_semaphores[] = {frame->image, frame->compute};
VkSemaphore signal_semaphores[] = {frame->render};
uint64_t wait_values[] = {0, frame->compute_index};
uint64_t signal_values[] = {0};
VkTimelineSemaphoreSubmitInfo timeline_info = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.signalSemaphoreValueCount = sizeof(signal_values)/sizeof(uint64_t),
.pSignalSemaphoreValues = signal_values,
.waitSemaphoreValueCount = sizeof(wait_values)/sizeof(uint64_t),
.pWaitSemaphoreValues = wait_values,
};
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.waitSemaphoreCount = sizeof(wait_semaphores)/sizeof(VkSemaphore),
.pWaitSemaphores = wait_semaphores,
.pWaitDstStageMask = wait_stages,
.commandBufferCount = 1,
.pCommandBuffers = &context->swapchain_command_buffers[image_index],
.signalSemaphoreCount = sizeof(signal_semaphores)/sizeof(VkSemaphore),
.pSignalSemaphores = signal_semaphores,
.pNext = &timeline_info,
};
VK_RESULT(vkQueueSubmit(context->graphics_queue.handle, 1, &submit_info, frame->ready));
VkPresentInfoKHR present_info = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &frame->render,
.swapchainCount = 1,
.pSwapchains = &context->swapchain,
.pImageIndices = &image_index,
.pResults = 0,
};
result = vkQueuePresentKHR(context->present_queue.handle, &present_info);
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
VK_RESULT(recreate_framebuffer(context));
} else if(result != VK_SUCCESS) {
return result;
}
context->current_frame = (context->current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
return VK_SUCCESS;
}