Correct framebuffer's attachments clearing when multiple views are rendered.

This commit is contained in:
Artem Kharytoniuk 2017-04-12 18:25:20 +03:00
parent 73e4db35d7
commit 11791b47a3
6 changed files with 107 additions and 64 deletions

View File

@ -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 <windows.h>
#include <gl/gl.h>
#endif

View File

@ -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();

View File

@ -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;

View File

@ -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 <algorithm>
@ -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;
}

View File

@ -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

View File

@ -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;
}