diff --git a/src/engine/renderer/tr_backend.c b/src/engine/renderer/tr_backend.c index 73e22d6..6656876 100644 --- a/src/engine/renderer/tr_backend.c +++ b/src/engine/renderer/tr_backend.c @@ -429,23 +429,24 @@ void RB_BeginDrawingView (void) { } #ifdef _DEBUG - float color[4] = { 0.8f, 0.7f, 0.4f, 1.0f }; // FIXME: get color of sky + float sky_color[4] = { 0.8f, 0.7f, 0.4f, 1.0f }; // FIXME: get color of sky #else - float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // FIXME: get color of sky + float sky_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // FIXME: get color of sky #endif - bool clear_color = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ); - if ( clear_color ) + bool fast_sky = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ); + if ( fast_sky ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used - qglClearColor(color[0], color[1], color[2], color[3]); + qglClearColor(sky_color[0], sky_color[1], sky_color[2], sky_color[3]); } + qglClear( clearBits ); // VULKAN - if (glState.vk_dirty_attachments) { + if (glState.vk_dirty_attachments || fast_sky) { VkClearAttachment attachments[2]; - uint32_t attachment_count = clear_color ? 2 : 1; + uint32_t attachment_count = fast_sky ? 2 : 1; attachments[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; attachments[0].clearValue.depthStencil.depth = 1.0f; @@ -454,18 +455,33 @@ void RB_BeginDrawingView (void) { attachments[0].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; attachments[0].clearValue.depthStencil.stencil = 0; } - if (clear_color) { + if (fast_sky) { attachments[1].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; attachments[1].colorAttachment = 0; - attachments[1].clearValue.color = { color[0], color[1], color[2], color[3] }; + attachments[1].clearValue.color = { sky_color[0], sky_color[1], sky_color[2], sky_color[3] }; } - VkClearRect clear_rect; - clear_rect.rect = vk_get_viewport_rect(); - clear_rect.baseArrayLayer = 0; - clear_rect.layerCount = 1; + VkClearRect clear_rect[2]; + clear_rect[0].rect = vk_get_viewport_rect(); + clear_rect[0].baseArrayLayer = 0; + clear_rect[0].layerCount = 1; + int rect_count = 1; - vkCmdClearAttachments(vk.command_buffer, attachment_count, attachments, 1, &clear_rect); + // Split viewport rectangle into two non-overlapping rectangles. + // It's a HACK to prevent Vulkan validation layer's performance warning: + // "vkCmdClearAttachments() issued on command buffer object XXX prior to any Draw Cmds. + // It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw." + // + if (fast_sky) { + uint32_t h = clear_rect[0].rect.extent.height / 2; + clear_rect[0].rect.extent.height = h; + + clear_rect[1] = clear_rect[0]; + clear_rect[1].rect.offset.y = h; + rect_count = 2; + } + + vkCmdClearAttachments(vk.command_buffer, attachment_count, attachments, rect_count, clear_rect); } if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) @@ -922,34 +938,8 @@ const void *RB_DrawBuffer( const void *data ) { qglDrawBuffer( cmd->buffer ); - // clear screen for debugging - if ( r_clear->integer ) { - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - } - // VULKAN - VkResult result = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vulkan_demo->image_acquired, VK_NULL_HANDLE, &vulkan_demo->swapchain_image_index); - check_vk_result(result, "vkAcquireNextImageKHR"); - - result = vkWaitForFences(vk.device, 1, &vulkan_demo->rendering_finished_fence, VK_FALSE, 1e9); - check_vk_result(result, "vkWaitForFences"); - result = vkResetFences(vk.device, 1, &vulkan_demo->rendering_finished_fence); - check_vk_result(result, "vkResetFences"); - - VkCommandBufferBeginInfo begin_info; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.pNext = nullptr; - begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - begin_info.pInheritanceInfo = nullptr; - - extern FILE* vk_log_file; - if (r_logFile->integer) - fprintf(vk_log_file, "begin\n"); - - result = vkBeginCommandBuffer(vk.command_buffer, &begin_info); - check_vk_result(result, "vkBeginCommandBuffer"); - vulkan_demo->begin_frame(); + vk_begin_frame(); return (const void *)(cmd + 1); } diff --git a/src/engine/renderer/tr_init.c b/src/engine/renderer/tr_init.c index 165f24c..39e43d0 100644 --- a/src/engine/renderer/tr_init.c +++ b/src/engine/renderer/tr_init.c @@ -105,7 +105,6 @@ cvar_t *r_picmip; cvar_t *r_showtris; cvar_t *r_showsky; cvar_t *r_shownormals; -cvar_t *r_clear; cvar_t *r_swapInterval; cvar_t *r_textureMode; cvar_t *r_offsetFactor; @@ -899,7 +898,6 @@ void R_Register( void ) r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); - r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 331318d..8f06d4d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1045,7 +1045,6 @@ extern cvar_t *r_logFile; // number of frames to emit GL logs extern cvar_t *r_showtris; // enables wireframe rendering of the world extern cvar_t *r_showsky; // forces sky in front of all surfaces extern cvar_t *r_shownormals; // draws wireframe normals -extern cvar_t *r_clear; // force screen clear every frame extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection extern cvar_t *r_flares; // light flares diff --git a/src/engine/renderer/tr_shade.c b/src/engine/renderer/tr_shade.c index 19b7bee..1f63005 100644 --- a/src/engine/renderer/tr_shade.c +++ b/src/engine/renderer/tr_shade.c @@ -841,7 +841,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) } // VULKAN - vk_bind_stage_specific_resources(pStage->vk_pipeline, multitexture); + vk_bind_stage_specific_resources(pStage->vk_pipeline, multitexture, input->shader->isSky == qtrue); vkCmdDrawIndexed(vk.command_buffer, tess.numIndexes, 1, 0, 0, 0); glState.vk_dirty_attachments = true; diff --git a/src/engine/renderer/tr_sky.c b/src/engine/renderer/tr_sky.c index 560dee2..2e2cde3 100644 --- a/src/engine/renderer/tr_sky.c +++ b/src/engine/renderer/tr_sky.c @@ -504,43 +504,14 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad } } -static void FillCloudBox( const shader_t *shader, int stage ) +static void FillCloudBox( int stage ) { - int i; - - for ( i =0; i < 6; i++ ) + for ( int i = 0; i < 5; i++ ) { int sky_mins_subd[2], sky_maxs_subd[2]; int s, t; - float MIN_T; - if ( 1 ) // FIXME? shader->sky.fullClouds ) - { - MIN_T = -HALF_SKY_SUBDIVISIONS; - - // still don't want to draw the bottom, even if fullClouds - if ( i == 5 ) - continue; - } - else - { - switch( i ) - { - case 0: - case 1: - case 2: - case 3: - MIN_T = -1; - break; - case 5: - // don't draw clouds beneath you - continue; - case 4: // top - default: - MIN_T = -HALF_SKY_SUBDIVISIONS; - break; - } - } + float MIN_T = -HALF_SKY_SUBDIVISIONS; sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; @@ -625,7 +596,7 @@ void R_BuildCloudData( shaderCommands_t *input ) if ( !tess.xstages[i] ) { break; } - FillCloudBox( input->shader, i ); + FillCloudBox( i ); } } } diff --git a/src/engine/renderer/vk.cpp b/src/engine/renderer/vk.cpp index bcf7c2e..0436df3 100644 --- a/src/engine/renderer/vk.cpp +++ b/src/engine/renderer/vk.cpp @@ -265,29 +265,27 @@ static VkSwapchainKHR create_swapchain(VkPhysicalDevice physical_device, VkDevic return swapchain; } -// TODO: pass device, color format, depth format. Physical device is not needed. -static VkRenderPass create_render_pass(VkPhysicalDevice physical_device, VkDevice device) { - VkAttachmentDescription color_attachment; - color_attachment.flags = 0; - color_attachment.format = vk.surface_format.format; - color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; +static VkRenderPass create_render_pass(VkDevice device, VkFormat color_format, VkFormat depth_format) { + VkAttachmentDescription attachments[2]; + attachments[0].flags = 0; + attachments[0].format = color_format; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - VkAttachmentDescription depth_attachment; - depth_attachment.flags = 0; - depth_attachment.format = find_depth_format(physical_device); - depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].flags = 0; + attachments[1].format = depth_format; + attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkAttachmentReference color_attachment_ref; color_attachment_ref.attachment = 0; @@ -309,13 +307,12 @@ static VkRenderPass create_render_pass(VkPhysicalDevice physical_device, VkDevic subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; - std::array attachments{color_attachment, depth_attachment}; VkRenderPassCreateInfo desc; desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; desc.pNext = nullptr; desc.flags = 0; - desc.attachmentCount = static_cast(attachments.size()); - desc.pAttachments = attachments.data(); + desc.attachmentCount = sizeof(attachments) / sizeof(attachments[0]); + desc.pAttachments = attachments; desc.subpassCount = 1; desc.pSubpasses = &subpass; desc.dependencyCount = 0; @@ -408,7 +405,9 @@ bool vk_initialize(HWND hwnd) { }); } - g.render_pass = create_render_pass(g.physical_device, g.device); + VkFormat depth_format = find_depth_format(vk.physical_device); + + vk.render_pass = create_render_pass(vk.device, vk.surface_format.format, depth_format); { std::array attachments = {VK_NULL_HANDLE, vk.depth_image_view}; @@ -1173,7 +1172,7 @@ void vk_bind_resources_shared_between_stages(int num_passes) { vkCmdPushConstants(vk.command_buffer, vk.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 64, mvp); } -void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture) { +void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture, bool sky) { // // Specify color/st for each draw call since they are regenerated for each Q3 shader's stage. // xyz are specified only once for all stages. @@ -1243,9 +1242,65 @@ void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture) { viewport.maxDepth = 0.3f; } + if (sky) { + if (r_showsky->integer) { + viewport.minDepth = 0.0f; + viewport.maxDepth = 0.0f; + } else { + viewport.minDepth = 1.0f; + viewport.maxDepth = 1.0f; + } + } + vkCmdSetViewport(vk.command_buffer, 0, 1, &viewport); if (tess.shader->polygonOffset) { vkCmdSetDepthBias(vk.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value); } } + +void vk_begin_frame() { + extern FILE* vk_log_file; + if (r_logFile->integer) + fprintf(vk_log_file, "vk_begin_frame\n"); + + VkResult result = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vulkan_demo->image_acquired, VK_NULL_HANDLE, &vulkan_demo->swapchain_image_index); + check_vk_result(result, "vkAcquireNextImageKHR"); + + result = vkWaitForFences(vk.device, 1, &vulkan_demo->rendering_finished_fence, VK_FALSE, 1e9); + check_vk_result(result, "vkWaitForFences"); + result = vkResetFences(vk.device, 1, &vulkan_demo->rendering_finished_fence); + check_vk_result(result, "vkResetFences"); + + VkCommandBufferBeginInfo begin_info; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.pNext = nullptr; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + begin_info.pInheritanceInfo = nullptr; + + result = vkBeginCommandBuffer(vk.command_buffer, &begin_info); + check_vk_result(result, "vkBeginCommandBuffer"); + + VkClearValue clear_values[2]; + /// ignore clear_values[0] which corresponds to color attachment + clear_values[1].depthStencil.depth = 1.0; + clear_values[1].depthStencil.stencil = 0; + + VkRenderPassBeginInfo render_pass_begin_info; + render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin_info.pNext = nullptr; + render_pass_begin_info.renderPass = vk.render_pass; + render_pass_begin_info.framebuffer = vk.framebuffers[vulkan_demo->swapchain_image_index]; + render_pass_begin_info.renderArea.offset = { 0, 0 }; + render_pass_begin_info.renderArea.extent = { (uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight }; + render_pass_begin_info.clearValueCount = 2; + render_pass_begin_info.pClearValues = clear_values; + + vkCmdBeginRenderPass(vk.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + vk.xyz_elements = 0; + vk.color_st_elements = 0; + vk.index_buffer_offset = 0; + + glState.vk_dirty_attachments = false; +} diff --git a/src/engine/renderer/vk.h b/src/engine/renderer/vk.h index b377280..73d80c4 100644 --- a/src/engine/renderer/vk.h +++ b/src/engine/renderer/vk.h @@ -19,7 +19,9 @@ VkRect2D vk_get_viewport_rect(); void vk_get_mvp_transform(float mvp[16]); void vk_bind_resources_shared_between_stages(int num_passes); -void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture); +void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture, bool sky); + +void vk_begin_frame(); struct Vk_Staging_Buffer { VkBuffer handle = VK_NULL_HANDLE; diff --git a/src/engine/renderer/vk_demo.cpp b/src/engine/renderer/vk_demo.cpp index 50d3c8c..2028573 100644 --- a/src/engine/renderer/vk_demo.cpp +++ b/src/engine/renderer/vk_demo.cpp @@ -107,30 +107,3 @@ void Vulkan_Demo::create_texture_sampler() { texture_image_sampler = get_resource_manager()->create_sampler(desc); } - -void Vulkan_Demo::begin_frame() { - if (r_logFile->integer) - fprintf(vk_log_file, "begin_frame\n"); - - std::array clear_values; - clear_values[0].color = {1.0f, 0.3f, 0.3f, 0.0f}; - clear_values[1].depthStencil = {1.0, 0}; - - VkRenderPassBeginInfo render_pass_begin_info; - render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin_info.pNext = nullptr; - render_pass_begin_info.renderPass = vk.render_pass; - render_pass_begin_info.framebuffer = vk.framebuffers[swapchain_image_index]; - render_pass_begin_info.renderArea.offset = {0, 0}; - render_pass_begin_info.renderArea.extent = {(uint32_t)window_width, (uint32_t)window_height}; - render_pass_begin_info.clearValueCount = static_cast(clear_values.size()); - render_pass_begin_info.pClearValues = clear_values.data(); - - vkCmdBeginRenderPass(vk.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - vk.xyz_elements = 0; - vk.color_st_elements = 0; - vk.index_buffer_offset = 0; - - glState.vk_dirty_attachments = false; -} diff --git a/src/engine/renderer/vk_demo.h b/src/engine/renderer/vk_demo.h index d1d3659..87064eb 100644 --- a/src/engine/renderer/vk_demo.h +++ b/src/engine/renderer/vk_demo.h @@ -12,8 +12,6 @@ class Vulkan_Demo { public: Vulkan_Demo(int window_width, int window_height); - void begin_frame(); - public: VkImage create_texture(const uint8_t* pixels, int bytes_per_pixel, int width, int height, VkImageView& image_view); void create_texture_sampler();