rtx: add runtime toggle between ray tracing and traditional renderer
new command is `vk_rtx_toggle`
This commit is contained in:
parent
20d38fead5
commit
3ed4d84653
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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, ®ion,
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue