diff --git a/src/engine/renderer/qgl.h b/src/engine/renderer/qgl.h index 1319394..ec63110 100644 --- a/src/engine/renderer/qgl.h +++ b/src/engine/renderer/qgl.h @@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #pragma warning (disable: 4032) #pragma warning (disable: 4201) #pragma warning (disable: 4214) +#define NOMINMAX #include #include #endif diff --git a/src/engine/renderer/tr_backend.c b/src/engine/renderer/tr_backend.c index 3f6ae0a..66431df 100644 --- a/src/engine/renderer/tr_backend.c +++ b/src/engine/renderer/tr_backend.c @@ -422,21 +422,52 @@ void RB_BeginDrawingView (void) { // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; - if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) + bool clear_stencil = r_measureOverdraw->integer || r_shadows->integer == 2; + if ( clear_stencil ) { clearBits |= GL_STENCIL_BUFFER_BIT; } - if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) + +#ifdef _DEBUG + float 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 +#endif + + bool clear_color = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ); + if ( clear_color ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used -#ifdef _DEBUG - qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky -#else - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky -#endif + qglClearColor(color[0], color[1], color[2], color[3]); } qglClear( clearBits ); + // VULKAN + if (glState.vk_dirty_attachments) { + VkClearAttachment attachments[2]; + uint32_t attachment_count = clear_color ? 2 : 1; + + attachments[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + attachments[0].clearValue.depthStencil.depth = 1.0f; + + if (clear_stencil) { + attachments[0].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + attachments[0].clearValue.depthStencil.stencil = 0; + } + if (clear_color) { + attachments[1].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attachments[1].colorAttachment = 0; + attachments[1].clearValue.color = { color[0], color[1], color[2], color[3] }; + } + + VkClearRect clear_rect; + clear_rect.rect = vk_get_viewport_rect(); + clear_rect.baseArrayLayer = 0; + clear_rect.layerCount = 1; + + vkCmdClearAttachments(vk_instance.command_buffer, attachment_count, attachments, 1, &clear_rect); + } + if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 993f28e..62992ed 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/qfiles.h" #include "../qcommon/qcommon.h" #include "tr_public.h" + #include "qgl.h" // VULKAN @@ -808,7 +809,12 @@ typedef struct { unsigned long glStateBits; // VULKAN - image_t* vk_current_images[2]; + + // This flag is used to decide whether framebuffer's attachments should be cleared with vmCmdClearAttachment (vk_dirty_attachments == true), + // or they have just been cleared by render pass instance clear op (vk_dirty_attachments == false). + bool vk_dirty_attachments; + + image_t* vk_current_images[2]; } glstate_t; diff --git a/src/engine/renderer/vk.cpp b/src/engine/renderer/vk.cpp index 5512017..3d0a923 100644 --- a/src/engine/renderer/vk.cpp +++ b/src/engine/renderer/vk.cpp @@ -1,8 +1,9 @@ -#include "vk.h" +#include "tr_local.h" + #include "vk_utils.h" #include "vk_allocator.h" #include "vk_resource_manager.h" -#include "tr_local.h" + #include "vk_demo.h" #include @@ -860,3 +861,31 @@ void vk_destroy_resources() { vkDeviceWaitIdle(vk_instance.device); vk_destroy_pipelines(); } + +VkRect2D vk_get_viewport_rect() { + VkRect2D r; + + if (backEnd.projection2D) { + r.offset.x = 0.0f; + r.offset.y = 0.0f; + r.extent.width = glConfig.vidWidth; + r.extent.height = glConfig.vidHeight; + } else { + r.offset.x = backEnd.viewParms.viewportX; + if (r.offset.x < 0) + r.offset.x = 0; + + r.offset.y = glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight); + if (r.offset.y < 0) + r.offset.y = 0; + + r.extent.width = backEnd.viewParms.viewportWidth; + if (r.offset.x + r.extent.width > glConfig.vidWidth) + r.extent.width = glConfig.vidWidth - r.offset.x; + + r.extent.height = backEnd.viewParms.viewportHeight; + if (r.offset.y + r.extent.height > glConfig.vidHeight) + r.extent.height = glConfig.vidHeight - r.offset.y; + } + return r; +} diff --git a/src/engine/renderer/vk.h b/src/engine/renderer/vk.h index d318d1e..8c3b5e7 100644 --- a/src/engine/renderer/vk.h +++ b/src/engine/renderer/vk.h @@ -15,6 +15,8 @@ bool vk_initialize(HWND hwnd); void vk_deinitialize(); void vk_destroy_resources(); +VkRect2D vk_get_viewport_rect(); + struct Vk_Staging_Buffer { VkBuffer handle = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; // memory associated with a buffer diff --git a/src/engine/renderer/vk_demo.cpp b/src/engine/renderer/vk_demo.cpp index ea1f32d..d503bee 100644 --- a/src/engine/renderer/vk_demo.cpp +++ b/src/engine/renderer/vk_demo.cpp @@ -421,6 +421,8 @@ void Vulkan_Demo::begin_frame() { tess_vertex_buffer_offset = 0; tess_index_buffer_offset = 0; tess_ubo_offset = 0; + + glState.vk_dirty_attachments = false; } void Vulkan_Demo::end_frame() { @@ -469,36 +471,20 @@ void Vulkan_Demo::render_tess(const shaderStage_t* stage) { vkCmdBindDescriptorSets(vk_instance.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &set, 1, &tess_ubo_offset); tess_ubo_offset += tess_ubo_offset_step; - VkViewport viewport; - VkRect2D scissor; - - if (backEnd.projection2D) { - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float) glConfig.vidWidth; - viewport.height = (float)glConfig.vidHeight; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - scissor.offset = {0, 0}; - scissor.extent = {(uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight}; - } else { - viewport.x = backEnd.viewParms.viewportX; - viewport.y = (float)(glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight)); - viewport.width = (float) backEnd.viewParms.viewportWidth; - viewport.height = (float)backEnd.viewParms.viewportHeight; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - scissor.offset = {backEnd.viewParms.viewportX, (glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight))}; - if (scissor.offset.y < 0) scissor.offset.y = 0; // receive such data from backEnd, so just adjust to valid value to prevent vulkan warnings - scissor.extent = {(uint32_t)backEnd.viewParms.viewportWidth, (uint32_t)backEnd.viewParms.viewportHeight}; - } - vkCmdBindPipeline(vk_instance.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stage->vk_pipeline); + VkRect2D r = vk_get_viewport_rect(); + vkCmdSetScissor(vk_instance.command_buffer, 0, 1, &r); + + VkViewport viewport; + viewport.x = (float)r.offset.x; + viewport.y = (float)r.offset.y; + viewport.width = (float)r.extent.width; + viewport.height = (float)r.extent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; vkCmdSetViewport(vk_instance.command_buffer, 0, 1, &viewport); - vkCmdSetScissor(vk_instance.command_buffer, 0, 1, &scissor); + if (tess.shader->polygonOffset) { vkCmdSetDepthBias(vk_instance.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value); } @@ -506,6 +492,8 @@ void Vulkan_Demo::render_tess(const shaderStage_t* stage) { vkCmdDrawIndexed(vk_instance.command_buffer, tess.numIndexes, 1, 0, 0, 0); tess_vertex_buffer_offset += tess.numVertexes * sizeof(Vk_Vertex); tess_index_buffer_offset += tess.numIndexes * sizeof(uint32_t); + + glState.vk_dirty_attachments = true; } void Vulkan_Demo::render_tess_multi(const shaderStage_t* stage) { @@ -557,36 +545,20 @@ void Vulkan_Demo::render_tess_multi(const shaderStage_t* stage) { vkCmdBindDescriptorSets(vk_instance.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &set, 1, &tess_ubo_offset); tess_ubo_offset += tess_ubo_offset_step; - VkViewport viewport; - VkRect2D scissor; - - if (backEnd.projection2D) { - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float) glConfig.vidWidth; - viewport.height = (float)glConfig.vidHeight; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - scissor.offset = {0, 0}; - scissor.extent = {(uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight}; - } else { - viewport.x = backEnd.viewParms.viewportX; - viewport.y = (float)(glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight)); - viewport.width = (float) backEnd.viewParms.viewportWidth; - viewport.height = (float)backEnd.viewParms.viewportHeight; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - scissor.offset = {backEnd.viewParms.viewportX, (glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight))}; - if (scissor.offset.y < 0) scissor.offset.y = 0; // receive such data from backEnd, so just adjust to valid value to prevent vulkan warnings - scissor.extent = {(uint32_t)backEnd.viewParms.viewportWidth, (uint32_t)backEnd.viewParms.viewportHeight}; - } - vkCmdBindPipeline(vk_instance.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stage->vk_pipeline); + VkRect2D r = vk_get_viewport_rect(); + vkCmdSetScissor(vk_instance.command_buffer, 0, 1, &r); + + VkViewport viewport; + viewport.x = (float)r.offset.x; + viewport.y = (float)r.offset.y; + viewport.width = (float)r.extent.width; + viewport.height = (float)r.extent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; vkCmdSetViewport(vk_instance.command_buffer, 0, 1, &viewport); - vkCmdSetScissor(vk_instance.command_buffer, 0, 1, &scissor); + if (tess.shader->polygonOffset) { vkCmdSetDepthBias(vk_instance.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value); } @@ -594,4 +566,6 @@ void Vulkan_Demo::render_tess_multi(const shaderStage_t* stage) { vkCmdDrawIndexed(vk_instance.command_buffer, tess.numIndexes, 1, 0, 0, 0); tess_vertex_buffer_offset += tess.numVertexes * sizeof(Vk_Vertex2); tess_index_buffer_offset += tess.numIndexes * sizeof(uint32_t); + + glState.vk_dirty_attachments = true; }