roleplay/client/src/draw.c

201 lines
8.8 KiB
C

#include "draw.h"
#include "gpu.h"
/*
* Must be updated if any of the following changes
* - ui_context->max_containers <- uint32
* - ui_context->containers[*].layer_count <- uint32
* - ui_context->containers[*].layers[*].address <- device address
* Basically, needs to be re-run whenever the number of layers/containers changes
*/
void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui_context) {
VkDeviceAddress push[2] = {ui_context->address, 0};
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->string_pipeline.pipeline);
for(uint32_t i = 0; i < ui_context->max_containers; i++) {
if(ui_context->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) {
push[1] = ui_context->containers[i].layers[j].address;
VkBufferMemoryBarrier draw_command_barrier_1 = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.buffer = ui_context->containers[i].layers[j].layer,
.offset = offsetof(GPULayer, draw),
.size = sizeof(DrawCommand),
.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &draw_command_barrier_1, 0, NULL);
command_copy_buffer(command_buffer, ui_context->containers[i].layers[j].layer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, num_drawables), offsetof(GPULayer, draw) + offsetof(DrawCommand, instance_count), sizeof(uint32_t));
VkBufferMemoryBarrier draw_command_barrier_2 = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.buffer = ui_context->containers[i].layers[j].layer,
.offset = offsetof(GPULayer, draw),
.size = sizeof(DrawCommand),
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 1, &draw_command_barrier_2, 0, NULL);
vkCmdPushConstants(command_buffer, ui_context->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, push);
vkCmdDispatchIndirect(command_buffer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, dispatch_strings));
VkBufferMemoryBarrier draw_command_barrier_3 = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.buffer = ui_context->containers[i].layers[j].layer,
.offset = offsetof(GPULayer, draw),
.size = sizeof(DrawCommand),
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0, 0, NULL, 1, &draw_command_barrier_3, 0, NULL);
VkBufferMemoryBarrier drawables_barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.buffer = ui_context->containers[i].layers[j].drawables,
.offset = 0,
.size = sizeof(GPUDrawable)*ui_context->containers[i].layers[j].data.max_drawables,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, NULL, 1, &drawables_barrier, 0, NULL);
}
}
}
}
/*
* Must be updated if any of the following changes
* - ui_context->max_containers <- uint32
* - ui_context->containers[*].layer_count <- uint32
* - ui_context->containers[*].layers[*].address <- device address
* Basically, needs to be re-run whenever the number of layers/containers changes
*/
void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context) {
VkDeviceAddress push[2] = {ui_context->address, 0};
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++) {
if(ui_context->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) {
push[1] = ui_context->containers[i].layers[j].address;
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, offsetof(GPULayer, draw), 1, 0);
}
}
}
}
VkResult record_draw_commands(
RenderContext* context,
UIContext* ui_context) {
VkResult result;
for(uint32_t image_index = 0; image_index < context->swapchain_image_count; image_index++) {
VkCommandBuffer command_buffer = context->swapchain_command_buffers[image_index];
VK_RESULT(vkResetCommandBuffer(command_buffer, 0));
VkCommandBufferBeginInfo begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
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,
};
record_ui_compute(command_buffer, ui_context);
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
// Render World
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
// Render UI
record_ui_draw(command_buffer, ui_context);
vkCmdEndRenderPass(command_buffer);
VK_RESULT(vkEndCommandBuffer(command_buffer));
}
return VK_SUCCESS;
}
VkResult draw_frame(
RenderContext* context,
double time) {
(void)time;
VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
if(result != VK_SUCCESS) {
return result;
}
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
return result;
}
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
if(result != VK_SUCCESS) {
return result;
}
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &context->image_available_semaphores[context->current_frame],
.pWaitDstStageMask = wait_stages,
.commandBufferCount = 1,
.pCommandBuffers = &context->swapchain_command_buffers[image_index],
.signalSemaphoreCount = 1,
.pSignalSemaphores = &context->render_finished_semaphores[context->current_frame],
};
result = vkQueueSubmit(context->graphics_queue.handle, 1, &submit_info, context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
return result;
}
VkPresentInfoKHR present_info = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &context->render_finished_semaphores[context->current_frame],
.swapchainCount = 1,
.pSwapchains = &context->swapchain,
.pImageIndices = &image_index,
.pResults = 0,
};
result = vkQueuePresentKHR(context->present_queue.handle, &present_info);
if(result != VK_SUCCESS) {
return result;
}
context->current_frame = (context->current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
return VK_SUCCESS;
}