rtx: add runtime toggle between ray tracing and traditional renderer

new command is `vk_rtx_toggle`
This commit is contained in:
Ivan Avdeev 2021-07-04 11:18:28 -07:00
parent 20d38fead5
commit 3ed4d84653
6 changed files with 77 additions and 35 deletions

View File

@ -16,6 +16,8 @@ static struct
VkFence fence;
uint32_t swapchain_image_index;
qboolean rtx_enabled;
} g_frame;
static VkFormat findSupportedImageFormat(const VkFormat *candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {
@ -99,20 +101,17 @@ static void destroyDepthImage( void ) {
freeDeviceMemory(&vk_frame.depth.device_memory);
}
static qboolean createRenderPass( void ) {
static VkRenderPass createRenderPass( qboolean ray_tracing ) {
VkRenderPass render_pass;
VkAttachmentDescription attachments[] = {{
.format = VK_FORMAT_B8G8R8A8_UNORM, //SRGB,// FIXME too early swapchain.create_info.imageFormat;
.samples = VK_SAMPLE_COUNT_1_BIT,
//.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
// TODO realtime switch between rtx and non-rtx requires either
// - re-creating render pass and all pipelines
// - having 2 sets of render passes and pipelines
.loadOp = vk_core.rtx ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR,
.loadOp = ray_tracing ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR /* TODO: prod renderer should not care VK_ATTACHMENT_LOAD_OP_DONT_CARE */,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.initialLayout = ray_tracing ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
}, {
// Depth
@ -151,9 +150,8 @@ static qboolean createRenderPass( void ) {
.pSubpasses = &subdesc,
};
XVK_CHECK(vkCreateRenderPass(vk_core.device, &rpci, NULL, &vk_frame.render_pass));
return true;
XVK_CHECK(vkCreateRenderPass(vk_core.device, &rpci, NULL, &render_pass));
return render_pass;
}
static void destroySwapchain( VkSwapchainKHR swapchain )
@ -184,7 +182,7 @@ static qboolean createSwapchain( void )
create_info->imageExtent.width = vk_frame.surface_caps.currentExtent.width;
create_info->imageExtent.height = vk_frame.surface_caps.currentExtent.height;
create_info->imageArrayLayers = 1;
create_info->imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | (vk_core.rtx ? VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0);
create_info->imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | (vk_core.rtx ? /*VK_IMAGE_USAGE_STORAGE_BIT |*/ VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0);
create_info->imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info->preTransform = vk_frame.surface_caps.currentTransform;
create_info->compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
@ -243,7 +241,7 @@ static qboolean createSwapchain( void )
};
VkFramebufferCreateInfo fbci = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = vk_frame.render_pass,
.renderPass = vk_frame.render_pass.raster,
.attachmentCount = ARRAYSIZE(attachments),
.pAttachments = attachments,
.width = vk_frame.create_info.imageExtent.width,
@ -318,7 +316,7 @@ void R_BeginFrame( qboolean clearScene )
}
vk2dBegin();
VK_RenderBegin();
VK_RenderBegin( g_frame.rtx_enabled );
{
VkCommandBufferBeginInfo beginfo = {
@ -342,13 +340,13 @@ void R_EndFrame( void )
};
VkPipelineStageFlags stageflags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
if (vk_core.rtx)
if (g_frame.rtx_enabled)
VK_RenderEndRTX( vk_core.cb, vk_frame.image_views[g_frame.swapchain_image_index], vk_frame.images[g_frame.swapchain_image_index], vk_frame.create_info.imageExtent.width, vk_frame.create_info.imageExtent.height );
{
VkRenderPassBeginInfo rpbi = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = vk_frame.render_pass,
.renderPass = g_frame.rtx_enabled ? vk_frame.render_pass.after_ray_tracing : vk_frame.render_pass.raster,
.renderArea.extent.width = vk_frame.create_info.imageExtent.width,
.renderArea.extent.height = vk_frame.create_info.imageExtent.height,
.clearValueCount = ARRAYSIZE(clear_value),
@ -371,7 +369,7 @@ void R_EndFrame( void )
vkCmdSetScissor(vk_core.cb, 0, ARRAYSIZE(scissor), scissor);
}
if (!vk_core.rtx)
if (!g_frame.rtx_enabled)
VK_RenderEnd( vk_core.cb );
vk2dEnd( vk_core.cb );
@ -432,10 +430,17 @@ void R_EndFrame( void )
g_frame.swapchain_image_index = -1;
}
static void toggleRaytracing( void ) {
ASSERT(vk_core.rtx);
g_frame.rtx_enabled = !g_frame.rtx_enabled;
gEngine.Con_Printf(S_WARN "Switching ray tracing to %d\n", g_frame.rtx_enabled);
}
qboolean VK_FrameCtlInit( void )
{
if (!createRenderPass())
return false;
vk_frame.render_pass.raster = createRenderPass(false);
if (vk_core.rtx)
vk_frame.render_pass.after_ray_tracing = createRenderPass(true);
if (!createSwapchain())
return false;
@ -445,6 +450,11 @@ qboolean VK_FrameCtlInit( void )
g_frame.fence = createFence();
g_frame.swapchain_image_index = -1;
g_frame.rtx_enabled = vk_core.rtx;
if (vk_core.rtx)
gEngine.Cmd_AddCommand("vk_rtx_toggle", toggleRaytracing, "Toggle between rasterization and ray tracing");
return true;
}
@ -456,5 +466,7 @@ void VK_FrameCtlShutdown( void )
destroySwapchain( vk_frame.swapchain );
vkDestroyRenderPass(vk_core.device, vk_frame.render_pass, NULL);
vkDestroyRenderPass(vk_core.device, vk_frame.render_pass.raster, NULL);
if (vk_core.rtx)
vkDestroyRenderPass(vk_core.device, vk_frame.render_pass.after_ray_tracing, NULL);
}

View File

@ -10,7 +10,16 @@ typedef struct vk_framectl_s {
VkImage image;
VkImageView image_view;
} depth;
VkRenderPass render_pass;
struct {
// Used when the entire rendering is traditional triangle rasterization
// Discards and clears color buffer
VkRenderPass raster;
// Used for 2D overlay rendering after ray tracing pass
// Preserves color buffer contents
VkRenderPass after_ray_tracing;
} render_pass;
VkSurfaceCapabilitiesKHR surface_caps;
VkSwapchainCreateInfoKHR create_info;

View File

@ -117,7 +117,7 @@ VkPipeline VK_PipelineGraphicsCreate(const vk_pipeline_graphics_create_info_t *c
.pColorBlendState = &color_blend,
.pDepthStencilState = &depth,
.layout = ci->layout,
.renderPass = vk_frame.render_pass,
.renderPass = vk_frame.render_pass.raster,
.pDynamicState = &dynamic_state_create_info,
.subpass = 0,
};

View File

@ -469,6 +469,8 @@ static struct {
int num_draw_commands;
matrix4x4 model, view, projection;
qboolean current_frame_is_ray_traced;
} g_render_state;
enum {
@ -481,7 +483,7 @@ enum {
UNIFORM_UPLOADED = 16,
};
void VK_RenderBegin( void ) {
void VK_RenderBegin( qboolean ray_tracing ) {
g_render_state.uniform_free_offset = 0;
g_render_state.uniform_data_set_mask = UNIFORM_UNSET;
g_render_state.current_ubo_offset = UINT32_MAX;
@ -490,8 +492,9 @@ void VK_RenderBegin( void ) {
memset(&g_render_state.dirty_uniform_data, 0, sizeof(g_render_state.dirty_uniform_data));
g_render_state.num_draw_commands = 0;
g_render_state.current_frame_is_ray_traced = ray_tracing;
if (vk_core.rtx)
if (ray_tracing)
VK_RayFrameBegin();
}
@ -691,7 +694,7 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf )
if (dlights_ubo_offset == UINT32_MAX)
return;
ASSERT(!vk_core.rtx);
ASSERT(!g_render_state.current_frame_is_ray_traced);
{
const VkDeviceSize offset = 0;
@ -815,7 +818,7 @@ void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage
}
qboolean VK_RenderModelInit( vk_render_model_t *model ) {
if (vk_core.rtx) {
if (vk_core.rtx && (g_render_state.current_frame_is_ray_traced || !model->dynamic)) {
// TODO runtime rtx switch: ???
const vk_ray_model_init_t args = {
.buffer = g_render.buffer.buffer,
@ -830,7 +833,7 @@ qboolean VK_RenderModelInit( vk_render_model_t *model ) {
}
void VK_RenderModelDestroy( vk_render_model_t* model ) {
if (vk_core.rtx) {
if (vk_core.rtx && (g_render_state.current_frame_is_ray_traced || !model->dynamic)) {
VK_RayModelDestroy(model->ray_model);
}
}
@ -842,7 +845,7 @@ void VK_RenderModelDraw( vk_render_model_t* model ) {
vk_buffer_handle_t vertex_buffer = InvalidHandle;
vk_buffer_handle_t index_buffer = InvalidHandle;
if (vk_core.rtx) {
if (g_render_state.current_frame_is_ray_traced) {
VK_RayFrameAddModel(model->ray_model, model, (const matrix3x4*)g_render_state.model);
return;
}

View File

@ -124,6 +124,6 @@ void VK_RenderFrameEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkI
void VK_RenderDebugLabelBegin( const char *label );
void VK_RenderDebugLabelEnd( void );
void VK_RenderBegin( void );
void VK_RenderBegin( qboolean ray_tracing );
void VK_RenderEnd( VkCommandBuffer cmdbuf );
void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage img_dst, uint32_t w, uint32_t h );

View File

@ -851,6 +851,30 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
args->dst.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region,
VK_FILTER_NEAREST);
}
{
VkImageMemoryBarrier image_barriers[] = {
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = args->dst.image,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}};
vkCmdPipelineBarrier(args->cmdbuf,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
}
}
static void createLayouts( void ) {
@ -1197,12 +1221,6 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
returnModelToCache(ray_model);
ray_model = NULL;
} else {
const VkSubmitInfo subinfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &vk_core.cb,
};
ray_model->kusochki_offset = kusochki_count_offset;
ray_model->dynamic = args.model->dynamic;