FidelityFX-FSR2/src/VK/Renderer.cpp
2022-06-22 12:54:32 +01:00

1312 lines
57 KiB
C++

// This file is part of the FidelityFX SDK.
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Renderer.h"
#include "UI.h"
//--------------------------------------------------------------------------------------
//
// OnCreate
//
//--------------------------------------------------------------------------------------
void Renderer::OnCreate(Device *pDevice, SwapChain *pSwapChain, float FontSize, bool bInvertedDepth)
{
m_pDevice = pDevice;
m_bInvertedDepth = bInvertedDepth;
// Create all the heaps for the resources views
const uint32_t cbvDescriptorCount = 2000;
const uint32_t srvDescriptorCount = 8000;
const uint32_t uavDescriptorCount = 10;
const uint32_t samplerDescriptorCount = 20;
m_ResourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, samplerDescriptorCount);
// Create a commandlist ring for the Direct queue
uint32_t commandListsPerBackBuffer = 8;
m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer);
// Create a 'dynamic' constant buffer
const uint32_t constantBuffersMemSize = 32 * 1024 * 1024;
m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, "Uniforms");
// Create a 'static' pool for vertices and indices
const uint32_t staticGeometryMemSize = (1024) * 1024 * 1024;
m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom");
// Create a 'static' pool for vertices and indices in system memory
const uint32_t systemGeometryMemSize = 32 * 1024;
m_SysMemBufferPool.OnCreate(pDevice, systemGeometryMemSize, false, "PostProcGeom");
// initialize the GPU time stamps module
m_GPUTimer.OnCreate(pDevice, backBufferCount);
// Quick helper to upload resources, it has it's own commandList and uses suballocation.
const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024;
m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results)
// Create GBuffer and render passes
//
{
m_GBuffer.OnCreate(
pDevice,
&m_ResourceViewHeaps,
{
{ GBUFFER_DEPTH, VK_FORMAT_D32_SFLOAT},
{ GBUFFER_FORWARD, VK_FORMAT_R16G16B16A16_SFLOAT},
{ GBUFFER_MOTION_VECTORS, VK_FORMAT_R16G16_SFLOAT},
{ GBUFFER_UPSCALEREACTIVE, VK_FORMAT_R8_UNORM},
{ GBUFFER_UPSCALE_TRANSPARENCY_AND_COMPOSITION, VK_FORMAT_R8_UNORM},
},
1
);
GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD | GBUFFER_MOTION_VECTORS | GBUFFER_UPSCALEREACTIVE | GBUFFER_UPSCALE_TRANSPARENCY_AND_COMPOSITION;
if (bInvertedDepth) fullGBuffer |= GBUFFER_INVERTED_DEPTH;
bool bClear = true;
m_RenderPassFullGBufferWithClear.OnCreate(&m_GBuffer, fullGBuffer, bClear,"m_RenderPassFullGBufferWithClear");
m_RenderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer, !bClear, "m_RenderPassFullGBuffer");
m_RenderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD, !bClear, "m_RenderPassJustDepthAndHdr");
}
// Create render pass shadow, will clear contents
{
VkAttachmentDescription depthAttachments;
AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments);
m_Render_pass_shadow = CreateRenderPassOptimal(m_pDevice->GetDevice(), 0, NULL, &depthAttachments);
}
m_SkyDome.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_UploadHeap, VK_FORMAT_R16G16B16A16_SFLOAT, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, "..\\media\\cauldron-media\\envmaps\\papermill\\diffuse.dds", "..\\media\\cauldron-media\\envmaps\\papermill\\specular.dds", VK_SAMPLE_COUNT_1_BIT, m_bInvertedDepth);
m_SkyDomeProc.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_UploadHeap, VK_FORMAT_R16G16B16A16_SFLOAT, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_1_BIT, m_bInvertedDepth);
m_Wireframe.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_1_BIT, m_bInvertedDepth);
m_WireframeBox.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool);
m_DownSample.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT);
m_Bloom.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT);
m_MagnifierPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT);
// Create tonemapping pass
m_ToneMappingCS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing);
m_ToneMappingPS.OnCreate(m_pDevice, pSwapChain->GetRenderPass(), &m_ResourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing);
m_ColorConversionPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_ResourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing);
// Initialize UI rendering resources
m_ImGUI.OnCreate(m_pDevice, pSwapChain->GetRenderPass(), &m_UploadHeap, &m_ConstantBufferRing, FontSize);
// Make sure upload heap has finished uploading before continuing
m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList());
m_UploadHeap.FlushAndFinish();
m_GpuFrameRateLimiter.OnCreate(pDevice, &m_ConstantBufferRing, &m_ResourceViewHeaps);
}
//--------------------------------------------------------------------------------------
//
// OnDestroy
//
//--------------------------------------------------------------------------------------
void Renderer::OnDestroy()
{
m_GpuFrameRateLimiter.OnDestroy();
m_AsyncPool.Flush();
m_ImGUI.OnDestroy();
m_ColorConversionPS.OnDestroy();
m_ToneMappingPS.OnDestroy();
m_ToneMappingCS.OnDestroy();
m_Bloom.OnDestroy();
m_DownSample.OnDestroy();
m_MagnifierPS.OnDestroy();
m_WireframeBox.OnDestroy();
m_Wireframe.OnDestroy();
m_SkyDomeProc.OnDestroy();
m_SkyDome.OnDestroy();
m_RenderPassFullGBufferWithClear.OnDestroy();
m_RenderPassJustDepthAndHdr.OnDestroy();
m_RenderPassFullGBuffer.OnDestroy();
m_GBuffer.OnDestroy();
m_pUpscaleContext->OnDestroy();
delete m_pUpscaleContext;
m_pUpscaleContext = NULL;
vkDestroyRenderPass(m_pDevice->GetDevice(), m_Render_pass_shadow, nullptr);
m_UploadHeap.OnDestroy();
m_GPUTimer.OnDestroy();
m_VidMemBufferPool.OnDestroy();
m_SysMemBufferPool.OnDestroy();
m_ConstantBufferRing.OnDestroy();
m_ResourceViewHeaps.OnDestroy();
m_CommandListRing.OnDestroy();
}
//--------------------------------------------------------------------------------------
//
// OnCreateWindowSizeDependentResources
//
//--------------------------------------------------------------------------------------
void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, UIState* pState)
{
m_Width = pState->renderWidth;
m_Height = pState->renderHeight;
// Create GBuffer
//
m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, m_Width, m_Height);
// Create frame buffers for the GBuffer render passes
//
m_RenderPassFullGBufferWithClear.OnCreateWindowSizeDependentResources(m_Width, m_Height);
m_RenderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(m_Width, m_Height);
m_RenderPassFullGBuffer.OnCreateWindowSizeDependentResources(m_Width, m_Height);
bool renderNative = (pState->m_nUpscaleType == UPSCALE_TYPE_NATIVE);
bool hdr = (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR);
VkFormat uiFormat = (hdr ? m_GBuffer.m_HDR.GetFormat() : pSwapChain->GetFormat());
VkFormat dFormat = (hdr ? uiFormat : VK_FORMAT_R8G8B8A8_UNORM);
m_displayOutput.InitRenderTarget(m_pDevice, pState->displayWidth, pState->displayHeight, dFormat, VK_SAMPLE_COUNT_1_BIT, (VkImageUsageFlags)(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), false, "DisplayOutput");
m_displayOutput.CreateSRV(&m_displayOutputSRV);
{
m_OpaqueTexture.InitRenderTarget(m_pDevice, pState->renderWidth, pState->renderHeight, m_GBuffer.m_HDR.GetFormat(), VK_SAMPLE_COUNT_1_BIT, (VkImageUsageFlags)(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), false, "OpaqueBuffer");
m_OpaqueTexture.CreateSRV(&m_OpaqueTextureSRV);
}
// Update PostProcessing passes
//
m_DownSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_GBuffer.m_HDR, 6); //downsample the HDR texture 6 times
m_Bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_DownSample.GetTexture(), 6, &m_GBuffer.m_HDR);
m_MagnifierPS.OnCreateWindowSizeDependentResources(pState->displayWidth, pState->displayHeight);
m_bMagResourceReInit = true;
m_RenderPassDisplayOutput = SimpleColorBlendRenderPass(m_pDevice->GetDevice(), m_displayOutput.GetFormat(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
std::vector<VkImageView> attachments = { m_displayOutputSRV };
m_FramebufferDisplayOutput = CreateFrameBuffer(m_pDevice->GetDevice(), m_RenderPassDisplayOutput, &attachments, pState->displayWidth, pState->displayHeight);
m_ImGUI.UpdatePipeline((pSwapChain->GetDisplayMode() == DISPLAYMODE_SDR) ? pSwapChain->GetRenderPass() : m_RenderPassDisplayOutput);
// Lazy Upscale context generation:
if ((m_pUpscaleContext == NULL) || (pState->m_nUpscaleType != m_pUpscaleContext->Type()))
{
// just a safeguard, usually OnDestroyWindowSizeDependentResources should have been called before it enters here
if (m_pUpscaleContext)
{
m_pUpscaleContext->OnDestroyWindowSizeDependentResources();
m_pUpscaleContext->OnDestroy();
delete m_pUpscaleContext;
m_pUpscaleContext = NULL;
}
// create upscale context
UpscaleContext::FfxUpscaleInitParams upscaleParams = { pState->m_nUpscaleType, m_bInvertedDepth, m_pDevice, pSwapChain->GetFormat(), &m_UploadHeap, backBufferCount };
m_pUpscaleContext = UpscaleContext::CreateUpscaleContext(upscaleParams);
}
m_pUpscaleContext->OnCreateWindowSizeDependentResources(nullptr, m_displayOutputSRV, pState->renderWidth, pState->renderHeight, pState->displayWidth, pState->displayHeight, hdr);
}
//--------------------------------------------------------------------------------------
//
// OnDestroyWindowSizeDependentResources
//
//--------------------------------------------------------------------------------------
void Renderer::OnDestroyWindowSizeDependentResources()
{
vkDestroyImageView(m_pDevice->GetDevice(), m_OpaqueTextureSRV, 0);
vkDestroyFramebuffer(m_pDevice->GetDevice(), m_FramebufferDisplayOutput, 0);
vkDestroyImageView(m_pDevice->GetDevice(), m_displayOutputSRV, 0);
vkDestroyRenderPass(m_pDevice->GetDevice(), m_RenderPassDisplayOutput, 0);
m_OpaqueTextureSRV = nullptr;
m_FramebufferDisplayOutput = nullptr;
m_displayOutputSRV = nullptr;
m_RenderPassDisplayOutput = nullptr;
m_displayOutput.OnDestroy();
m_Bloom.OnDestroyWindowSizeDependentResources();
m_DownSample.OnDestroyWindowSizeDependentResources();
m_MagnifierPS.OnDestroyWindowSizeDependentResources();
m_OpaqueTexture.OnDestroy();
m_RenderPassFullGBufferWithClear.OnDestroyWindowSizeDependentResources();
m_RenderPassJustDepthAndHdr.OnDestroyWindowSizeDependentResources();
m_RenderPassFullGBuffer.OnDestroyWindowSizeDependentResources();
m_GBuffer.OnDestroyWindowSizeDependentResources();
// destroy upscale context
if (m_pUpscaleContext)
{
m_pUpscaleContext->OnDestroyWindowSizeDependentResources();
}
}
void Renderer::OnUpdateDisplayDependentResources(SwapChain *pSwapChain)
{
// Update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes)
//
m_ColorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode());
m_ToneMappingPS.UpdatePipelines(pSwapChain->GetRenderPass());
}
//--------------------------------------------------------------------------------------
//
// OnUpdateLocalDimmingChangedResources
//
//--------------------------------------------------------------------------------------
void Renderer::OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain)
{
m_ColorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode());
}
//--------------------------------------------------------------------------------------
//
// LoadScene
//
//--------------------------------------------------------------------------------------
int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int Stage)
{
// show loading progress
//
ImGui::OpenPopup("Loading");
if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
float progress = (float)Stage / 12.0f;
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL);
ImGui::EndPopup();
}
// use multi threading
AsyncPool *pAsyncPool = &m_AsyncPool;
// Loading stages
//
if (Stage == 0)
{
}
else if (Stage == 5)
{
Profile p("m_pGltfLoader->Load");
m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers();
m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing);
}
else if (Stage == 6)
{
Profile p("LoadTextures");
// here we are loading onto the GPU all the textures and the inverse matrices
// this data will be used to create the PBR and Depth passes
m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool);
}
else if (Stage == 7)
{
Profile p("m_GLTFDepth->OnCreate");
//create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass
m_GLTFDepth = new GltfDepthPass();
m_GLTFDepth->OnCreate(
m_pDevice,
m_Render_pass_shadow,
&m_UploadHeap,
&m_ResourceViewHeaps,
&m_ConstantBufferRing,
&m_VidMemBufferPool,
m_pGLTFTexturesAndBuffers,
pAsyncPool,
m_bInvertedDepth
);
m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList());
m_UploadHeap.FlushAndFinish();
}
else if (Stage == 8)
{
Profile p("m_GLTFPBR->OnCreate");
// same thing as above but for the PBR pass
m_GLTFPBR = new GltfPbrPass();
m_GLTFPBR->OnCreate(
m_pDevice,
&m_UploadHeap,
&m_ResourceViewHeaps,
&m_ConstantBufferRing,
&m_VidMemBufferPool,
m_pGLTFTexturesAndBuffers,
&m_SkyDome,
false, // use SSAO mask
m_ShadowSRVPool,
&m_RenderPassFullGBufferWithClear,
pAsyncPool,
m_bInvertedDepth
);
m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList());
m_UploadHeap.FlushAndFinish();
}
else if (Stage == 9)
{
Profile p("m_GLTFBBox->OnCreate");
// just a bounding box pass that will draw boundingboxes instead of the geometry itself
m_GLTFBBox = new GltfBBoxPass();
m_GLTFBBox->OnCreate(
m_pDevice,
m_RenderPassJustDepthAndHdr.GetRenderPass(),
&m_ResourceViewHeaps,
&m_ConstantBufferRing,
&m_VidMemBufferPool,
m_pGLTFTexturesAndBuffers,
&m_Wireframe
);
// we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs
m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList());
}
else if (Stage == 10)
{
Profile p("Flush");
m_UploadHeap.FlushAndFinish();
//once everything is uploaded we dont need the upload heaps anymore
m_VidMemBufferPool.FreeUploadHeap();
// tell caller that we are done loading the map
return 0;
}
Stage++;
return Stage;
}
//--------------------------------------------------------------------------------------
//
// UnloadScene
//
//--------------------------------------------------------------------------------------
void Renderer::UnloadScene()
{
// wait for all the async loading operations to finish
m_AsyncPool.Flush();
m_pDevice->GPUFlush();
if (m_GLTFPBR)
{
m_GLTFPBR->OnDestroy();
delete m_GLTFPBR;
m_GLTFPBR = NULL;
}
if (m_GLTFDepth)
{
m_GLTFDepth->OnDestroy();
delete m_GLTFDepth;
m_GLTFDepth = NULL;
}
if (m_GLTFBBox)
{
m_GLTFBBox->OnDestroy();
delete m_GLTFBBox;
m_GLTFBBox = NULL;
}
if (m_pGLTFTexturesAndBuffers)
{
m_pGLTFTexturesAndBuffers->OnDestroy();
delete m_pGLTFTexturesAndBuffers;
m_pGLTFTexturesAndBuffers = NULL;
}
assert(m_shadowMapPool.size() == m_ShadowSRVPool.size());
while (!m_shadowMapPool.empty())
{
m_shadowMapPool.back().ShadowMap.OnDestroy();
vkDestroyFramebuffer(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowFrameBuffer, nullptr);
vkDestroyImageView(m_pDevice->GetDevice(), m_ShadowSRVPool.back(), nullptr);
vkDestroyImageView(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowDSV, nullptr);
m_ShadowSRVPool.pop_back();
m_shadowMapPool.pop_back();
}
}
void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon)
{
// Go through the lights and allocate shadow information
uint32_t NumShadows = 0;
for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i)
{
const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId];
if (lightData.m_shadowResolution)
{
SceneShadowInfo ShadowInfo;
ShadowInfo.ShadowResolution = lightData.m_shadowResolution;
ShadowInfo.ShadowIndex = NumShadows++;
ShadowInfo.LightIndex = i;
m_shadowMapPool.push_back(ShadowInfo);
}
}
if (NumShadows > MaxShadowInstances)
{
Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h");
throw;
}
// If we had shadow information, allocate all required maps and bindings
if (!m_shadowMapPool.empty())
{
std::vector<SceneShadowInfo>::iterator CurrentShadow = m_shadowMapPool.begin();
for (uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow)
{
CurrentShadow->ShadowMap.InitDepthStencil(m_pDevice, CurrentShadow->ShadowResolution, CurrentShadow->ShadowResolution, VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, "ShadowMap");
CurrentShadow->ShadowMap.CreateDSV(&CurrentShadow->ShadowDSV);
// Create render pass shadow, will clear contents
{
VkAttachmentDescription depthAttachments;
AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments);
// Create frame buffer
VkImageView attachmentViews[1] = { CurrentShadow->ShadowDSV };
VkFramebufferCreateInfo fb_info = {};
fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fb_info.pNext = NULL;
fb_info.renderPass = m_Render_pass_shadow;
fb_info.attachmentCount = 1;
fb_info.pAttachments = attachmentViews;
fb_info.width = CurrentShadow->ShadowResolution;
fb_info.height = CurrentShadow->ShadowResolution;
fb_info.layers = 1;
VkResult res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &CurrentShadow->ShadowFrameBuffer);
assert(res == VK_SUCCESS);
}
VkImageView ShadowSRV;
CurrentShadow->ShadowMap.CreateSRV(&ShadowSRV);
m_ShadowSRVPool.push_back(ShadowSRV);
}
}
}
//--------------------------------------------------------------------------------------
//
// OnRender
//
//--------------------------------------------------------------------------------------
void Renderer::OnRender(UIState* pState, const Camera& Cam, SwapChain* pSwapChain)
{
const bool bHDR = pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR;
bool bUseUpscale = pState->m_nUpscaleType != UPSCALE_TYPE_NATIVE;
bool bUseTaaRcas = pState->bUseTAA || pState->bUseRcas;
// Wait for swapchain (we are going to render to it) -----------------------------------
int imageIndex = pSwapChain->WaitForSwapChain();
// Let our resource managers do some house keeping
m_ConstantBufferRing.OnBeginFrame();
m_CommandListRing.OnBeginFrame();
// command buffer calls
VkCommandBuffer cmdBuf1 = m_CommandListRing.GetNewCommandList();
{
VkCommandBufferBeginInfo cmd_buf_info;
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmd_buf_info.pNext = NULL;
cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmd_buf_info.pInheritanceInfo = NULL;
VkResult res = vkBeginCommandBuffer(cmdBuf1, &cmd_buf_info);
assert(res == VK_SUCCESS);
}
m_GPUTimer.OnBeginFrame(cmdBuf1, &m_TimeStamps);
// Render size viewport
VkViewport vpr = { 0.0f, static_cast<float>(pState->renderHeight), static_cast<float>(pState->renderWidth), -static_cast<float>(pState->renderHeight), 0.0f, 1.0f };
VkRect2D srr = { 0, 0, pState->renderWidth, pState->renderHeight };
// Display size viewport
VkViewport vpd = { 0.0f, static_cast<float>(pState->displayHeight), static_cast<float>(pState->displayWidth), -static_cast<float>(pState->displayHeight), 0.0f, 1.0f };
VkRect2D srd = { 0, 0, pState->displayWidth, pState->displayHeight };
m_pUpscaleContext->PreDraw(pState);
// Sets the perFrame data
per_frame *pPerFrame = NULL;
if (m_pGLTFTexturesAndBuffers)
{
// fill as much as possible using the GLTF (camera, lights, ...)
pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(Cam);
// Set some lighting factors
pPerFrame->iblFactor = pState->IBLFactor;
pPerFrame->emmisiveFactor = pState->EmissiveFactor;
pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width);
pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height);
pPerFrame->wireframeOptions.setX(pState->WireframeColor[0]);
pPerFrame->wireframeOptions.setY(pState->WireframeColor[1]);
pPerFrame->wireframeOptions.setZ(pState->WireframeColor[2]);
pPerFrame->wireframeOptions.setW(pState->WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR ? 1.0f : 0.0f);
pPerFrame->lodBias = pState->mipBias;
m_pGLTFTexturesAndBuffers->SetPerFrameConstants();
m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons();
}
// Render all shadow maps
if (m_GLTFDepth && pPerFrame != NULL)
{
SetPerfMarkerBegin(cmdBuf1, "ShadowPass");
VkClearValue depth_clear_values[1];
depth_clear_values[0].depthStencil.depth = 1.0f;
depth_clear_values[0].depthStencil.stencil = 0;
VkRenderPassBeginInfo rp_begin;
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.pNext = NULL;
rp_begin.renderPass = m_Render_pass_shadow;
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.clearValueCount = 1;
rp_begin.pClearValues = depth_clear_values;
std::vector<SceneShadowInfo>::iterator ShadowMap = m_shadowMapPool.begin();
while (ShadowMap < m_shadowMapPool.end())
{
// Clear shadow map
rp_begin.framebuffer = ShadowMap->ShadowFrameBuffer;
rp_begin.renderArea.extent.width = ShadowMap->ShadowResolution;
rp_begin.renderArea.extent.height = ShadowMap->ShadowResolution;
vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
// Render to shadow map
SetViewportAndScissor(cmdBuf1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution);
// Set per frame constant buffer values
per_frame* cbDepthPerFrame = m_GLTFDepth->SetPerFrameConstants();
cbDepthPerFrame->mCameraCurrViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj;
cbDepthPerFrame->lodBias = pState->mipBias;
m_GLTFDepth->Draw(cmdBuf1);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Shadow Map Render");
vkCmdEndRenderPass(cmdBuf1);
++ShadowMap;
}
SetPerfMarkerEnd(cmdBuf1);
}
// Render Scene to the GBuffer ------------------------------------------------
SetPerfMarkerBegin(cmdBuf1, "Color pass");
VkRect2D currentRect = pState->bDynamicRes ? srd : srr;
if (pPerFrame != NULL && m_GLTFPBR)
{
const bool bWireframe = pState->WireframeMode != UIState::WireframeMode::WIREFRAME_MODE_OFF;
std::vector<GltfPbrPass::BatchList> opaque, transparent;
m_GLTFPBR->BuildBatchLists(&opaque, &transparent, bWireframe);
// Render opaque
{
// Start the render pass with the display resolution so the entire render target is cleared when DRS is active
m_RenderPassFullGBufferWithClear.BeginPass(cmdBuf1, currentRect);
// After clearing set the correct render viewport/scissor rect
vkCmdSetScissor(cmdBuf1, 0, 1, &srr);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpr);
m_GLTFPBR->DrawBatchList(cmdBuf1, &opaque, bWireframe);
m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Opaque");
m_RenderPassFullGBufferWithClear.EndPass(cmdBuf1);
}
// Render skydome
{
m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, currentRect);
vkCmdSetScissor(cmdBuf1, 0, 1, &srr);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpr);
if (pState->SelectedSkydomeTypeIndex == 1)
{
math::Matrix4 clipToView = math::inverse(pPerFrame->mCameraCurrViewProj);
m_SkyDome.Draw(cmdBuf1, clipToView);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Skydome cube");
}
else if (pState->SelectedSkydomeTypeIndex == 0)
{
SkyDomeProc::Constants skyDomeConstants;
skyDomeConstants.invViewProj = math::inverse(pPerFrame->mCameraCurrViewProj);
skyDomeConstants.vSunDirection = math::Vector4(1.0f, 0.05f, 0.0f, 0.0f);
skyDomeConstants.turbidity = 10.0f;
skyDomeConstants.rayleigh = 2.0f;
skyDomeConstants.mieCoefficient = 0.005f;
skyDomeConstants.mieDirectionalG = 0.8f;
skyDomeConstants.luminance = 1.0f;
m_SkyDomeProc.Draw(cmdBuf1, skyDomeConstants);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Skydome Proc");
}
m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1);
}
if (pState->bUseFsr2AutoReactive|true)
{
// Copy resource before we render transparent stuff
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
VkImageMemoryBarrier barriers[2];
barriers[0] = barrier;
barriers[0].srcAccessMask = VK_IMAGE_LAYOUT_UNDEFINED;
barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barriers[0].image = m_OpaqueTexture.Resource();
barriers[1] = barrier;
barriers[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[1].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[1].image = m_GBuffer.m_HDR.Resource();
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers);
}
VkImageSubresourceLayers srLayers = {};
srLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
srLayers.baseArrayLayer = 0;
srLayers.layerCount = 1;
srLayers.mipLevel = 0;
VkImageCopy region = {};
region.extent.width = m_GBuffer.m_HDR.GetWidth();
region.extent.height = m_GBuffer.m_HDR.GetHeight();
region.extent.depth = 1;
region.dstSubresource = srLayers;
region.srcSubresource = srLayers;
vkCmdCopyImage(cmdBuf1, m_GBuffer.m_HDR.Resource(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_OpaqueTexture.Resource(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
// Copy resource before we render transparent stuff
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
VkImageMemoryBarrier barriers[2];
barriers[0] = barrier;
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barriers[0].image = m_OpaqueTexture.Resource();
barriers[1] = barrier;
barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[1].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barriers[1].image = m_GBuffer.m_HDR.Resource();
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 2, barriers);
}
}
// draw transparent geometry
{
m_RenderPassFullGBuffer.BeginPass(cmdBuf1, currentRect);
vkCmdSetScissor(cmdBuf1, 0, 1, &srr);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpr);
std::sort(transparent.begin(), transparent.end());
m_GLTFPBR->DrawBatchList(cmdBuf1, &transparent, bWireframe);
m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Transparent");
m_RenderPassFullGBuffer.EndPass(cmdBuf1);
}
// draw object's bounding boxes
{
m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, currentRect);
vkCmdSetScissor(cmdBuf1, 0, 1, &srr);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpr);
if (m_GLTFBBox)
{
if (pState->bDrawBoundingBoxes)
{
m_GLTFBBox->Draw(cmdBuf1, pPerFrame->mCameraCurrViewProj);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Bounding Box");
}
}
// draw light's frustums
if (pState->bDrawLightFrustum && pPerFrame != NULL)
{
SetPerfMarkerBegin(cmdBuf1, "light frustums");
math::Vector4 vCenter = math::Vector4(0.0f, 0.0f, 0.5f, 0.0f);
math::Vector4 vRadius = math::Vector4(1.0f, 1.0f, 0.5f, 0.0f);
math::Vector4 vColor = math::Vector4(1.0f, 1.0f, 1.0f, 1.0f);
for (uint32_t i = 0; i < pPerFrame->lightCount; i++)
{
math::Matrix4 spotlightMatrix = math::inverse(pPerFrame->lights[i].mLightViewProj);
math::Matrix4 worldMatrix = pPerFrame->mCameraCurrViewProj * spotlightMatrix;
m_WireframeBox.Draw(cmdBuf1, &m_Wireframe, worldMatrix, vCenter, vRadius, vColor);
}
m_GPUTimer.GetTimeStamp(cmdBuf1, "Light's frustum");
SetPerfMarkerEnd(cmdBuf1);
}
m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1);
}
}
else
{
m_RenderPassFullGBufferWithClear.BeginPass(cmdBuf1, currentRect);
m_RenderPassFullGBufferWithClear.EndPass(cmdBuf1);
m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, currentRect);
m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1);
}
VkImageMemoryBarrier barrier[1] = {};
barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier[0].pNext = NULL;
barrier[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier[0].subresourceRange.baseMipLevel = 0;
barrier[0].subresourceRange.levelCount = 1;
barrier[0].subresourceRange.baseArrayLayer = 0;
barrier[0].subresourceRange.layerCount = 1;
barrier[0].image = m_GBuffer.m_HDR.Resource();
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, barrier);
SetPerfMarkerEnd(cmdBuf1);
// if FSR2 and auto reactive mask is enabled: generate reactive mask
if (pState->bUseFsr2AutoReactive)
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.image = m_GBuffer.m_UpscaleReactive.Resource();
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
UpscaleContext::FfxUpscaleSetup upscaleSetup = {};
upscaleSetup.cameraSetup.vCameraPos = pState->camera.GetPosition();
upscaleSetup.cameraSetup.mCameraView = pState->camera.GetView();
upscaleSetup.cameraSetup.mCameraViewInv = math::inverse(pState->camera.GetView());
upscaleSetup.cameraSetup.mCameraProj = pState->camera.GetProjection();
upscaleSetup.opaqueOnlyColorResource = &m_OpaqueTexture;
upscaleSetup.unresolvedColorResource = &m_GBuffer.m_HDR;
upscaleSetup.reactiveMapResource = &m_GBuffer.m_UpscaleReactive;
upscaleSetup.opaqueOnlyColorResourceView = m_OpaqueTextureSRV;
upscaleSetup.unresolvedColorResourceView = m_GBuffer.m_HDRSRV;
upscaleSetup.reactiveMapResourceView = m_GBuffer.m_UpscaleReactiveSRV;
m_pUpscaleContext->GenerateReactiveMask(cmdBuf1, upscaleSetup, pState);
}
// Post proc---------------------------------------------------------------------------
// Bloom, takes HDR as input and applies bloom to it.
{
SetPerfMarkerBegin(cmdBuf1, "PostProcess");
// Downsample pass
m_DownSample.Draw(cmdBuf1);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Downsample");
// Bloom pass (needs the downsampled data)
m_Bloom.Draw(cmdBuf1);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Bloom");
SetPerfMarkerEnd(cmdBuf1);
}
// Start tracking input/output resources at this point to handle HDR and SDR render paths
VkImageView SRVCurrentInput = m_GBuffer.m_HDRSRV;
VkImage ImgCurrentInput = m_GBuffer.m_HDR.Resource();
VkFramebuffer CurrentFrambuffer = nullptr;
// Always use upscale context, if we don't want one, Spatial can skip upscale (but still do TAA and/or RCAS)
if (bUseUpscale || bUseTaaRcas)
{
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
VkImageMemoryBarrier barriers[6];
barriers[0] = barrier;
barriers[0].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
barriers[0].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
barriers[0].image = m_GBuffer.m_DepthBuffer.Resource();
barriers[1] = barrier;
barriers[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[1].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barriers[1].image = m_GBuffer.m_MotionVectors.Resource();
barriers[2] = barrier;
barriers[2].srcAccessMask = pState->bUseFsr2AutoReactive ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[2].oldLayout = pState->bUseFsr2AutoReactive ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barriers[2].image = m_GBuffer.m_UpscaleReactive.Resource();
barriers[3] = barrier;
barriers[3].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[3].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barriers[3].image = m_GBuffer.m_UpscaleTransparencyAndComposition.Resource();
// no layout transition but we still need to wait
barriers[4] = barrier;
barriers[4].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barriers[4].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barriers[4].image = m_GBuffer.m_HDR.Resource();
barriers[5] = barrier;
barriers[5].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[5].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barriers[5].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barriers[5].newLayout = VK_IMAGE_LAYOUT_GENERAL;
barriers[5].image = m_displayOutput.Resource();
VkPipelineStageFlags srcStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
if (pState->bUseFsr2AutoReactive)
srcStageFlags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
vkCmdPipelineBarrier(cmdBuf1, srcStageFlags, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 6, barriers);
}
UpscaleContext::FfxUpscaleSetup upscaleSetup;
upscaleSetup.cameraSetup.vCameraPos = pState->camera.GetPosition();
upscaleSetup.cameraSetup.mCameraView = pState->camera.GetView();
upscaleSetup.cameraSetup.mCameraViewInv = math::inverse(pState->camera.GetView());
upscaleSetup.cameraSetup.mCameraProj = pState->camera.GetProjection();
upscaleSetup.unresolvedColorResource = &m_GBuffer.m_HDR;
upscaleSetup.motionvectorResource = &m_GBuffer.m_MotionVectors;
upscaleSetup.depthbufferResource = &m_GBuffer.m_DepthBuffer;
upscaleSetup.reactiveMapResource = &m_GBuffer.m_UpscaleReactive;
upscaleSetup.transparencyAndCompositionResource = &m_GBuffer.m_UpscaleTransparencyAndComposition;
upscaleSetup.resolvedColorResource = &m_displayOutput;
upscaleSetup.unresolvedColorResourceView = m_GBuffer.m_HDRSRV;
upscaleSetup.motionvectorResourceView = m_GBuffer.m_MotionVectorsSRV;
upscaleSetup.depthbufferResourceView = m_GBuffer.m_DepthBufferSRV;
upscaleSetup.reactiveMapResourceView = m_GBuffer.m_UpscaleReactiveSRV;
upscaleSetup.transparencyAndCompositionResourceView = m_GBuffer.m_UpscaleTransparencyAndCompositionSRV;
upscaleSetup.resolvedColorResourceView = m_displayOutputSRV;
m_pUpscaleContext->Draw(cmdBuf1, upscaleSetup, pState);
if (bUseUpscale)
m_GPUTimer.GetTimeStamp(cmdBuf1, m_pUpscaleContext->Name().c_str());
else if (pState->bUseTAA && !pState->bUseRcas)
m_GPUTimer.GetTimeStamp(cmdBuf1, "TAA");
else if (!pState->bUseTAA && pState->bUseRcas)
m_GPUTimer.GetTimeStamp(cmdBuf1, "RCAS");
else if (pState->bUseTAA && pState->bUseRcas)
m_GPUTimer.GetTimeStamp(cmdBuf1, "TAA & RCAS");
SRVCurrentInput = m_displayOutputSRV;
ImgCurrentInput = m_displayOutput.Resource();
CurrentFrambuffer = m_FramebufferDisplayOutput;
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.image = ImgCurrentInput;
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
}
// Upscale done, display size is now the main target
vkCmdSetScissor(cmdBuf1, 0, 1, &srd);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpd);
// If using FreeSync HDR we need to do the tonemapping in-place and then apply the GUI, later we'll apply the color conversion into the swapchain
if (bHDR)
{
// Magnifier Pass: m_HDR as input, pass' own output
if (pState->bUseMagnifier)
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.image = m_MagnifierPS.GetPassOutputResource();
if (m_bMagResourceReInit)
{
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_bMagResourceReInit = false;
}
else
{
barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
// Note: assumes the input texture (specified in OnCreateWindowSizeDependentResources()) is in read state
m_MagnifierPS.Draw(cmdBuf1, pState->MagnifierParams, SRVCurrentInput);
m_GPUTimer.GetTimeStamp(cmdBuf1, "Magnifier");
SRVCurrentInput = m_MagnifierPS.GetPassOutputSRV();
ImgCurrentInput = m_MagnifierPS.GetPassOutputResource();
}
// Render HUD ------------------------------------------------------------------------
{
VkRenderPassBeginInfo rp_begin;
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.pNext = NULL;
rp_begin.renderPass = m_RenderPassDisplayOutput;
rp_begin.framebuffer = CurrentFrambuffer;
rp_begin.renderArea = srd;
rp_begin.pClearValues = nullptr;
rp_begin.clearValueCount = 0;
vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetScissor(cmdBuf1, 0, 1, &srd);
vkCmdSetViewport(cmdBuf1, 0, 1, &vpd);
m_ImGUI.Draw(cmdBuf1);
m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1);
m_GPUTimer.GetTimeStamp(cmdBuf1, "ImGUI Rendering");
}
// In place Tonemapping ------------------------------------------------------------------------
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.image = ImgCurrentInput;
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
m_ToneMappingCS.Draw(cmdBuf1, SRVCurrentInput, pState->ExposureHdr, pState->SelectedTonemapperIndex, srd.extent.width, srd.extent.height);
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.image = ImgCurrentInput;
vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
}
}
// submit command buffer
{
VkResult res = vkEndCommandBuffer(cmdBuf1);
assert(res == VK_SUCCESS);
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = NULL;
submit_info.pWaitDstStageMask = NULL;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmdBuf1;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = NULL;
res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE);
assert(res == VK_SUCCESS);
}
//m_CommandListRing.OnBeginFrame();
VkCommandBuffer cmdBuf2 = m_CommandListRing.GetNewCommandList();
{
VkCommandBufferBeginInfo cmd_buf_info;
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmd_buf_info.pNext = NULL;
cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmd_buf_info.pInheritanceInfo = NULL;
VkResult res = vkBeginCommandBuffer(cmdBuf2, &cmd_buf_info);
assert(res == VK_SUCCESS);
}
vkCmdSetScissor(cmdBuf2, 0, 1, &srd);
vkCmdSetViewport(cmdBuf2, 0, 1, &vpd);
// Magnifier Pass: m_HDR as input, pass' own output
if (pState->bUseMagnifier && !bHDR)
{
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.image = m_MagnifierPS.GetPassOutputResource();
if (m_bMagResourceReInit)
{
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_bMagResourceReInit = false;
}
else
{
barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
vkCmdPipelineBarrier(cmdBuf2, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
}
// Note: assumes the input texture (specified in OnCreateWindowSizeDependentResources()) is in read state
m_MagnifierPS.Draw(cmdBuf2, pState->MagnifierParams, SRVCurrentInput);
m_GPUTimer.GetTimeStamp(cmdBuf2, "Magnifier");
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.image = m_MagnifierPS.GetPassOutputResource();
vkCmdPipelineBarrier(cmdBuf2, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier);
}
SRVCurrentInput = m_MagnifierPS.GetPassOutputSRV();
ImgCurrentInput = m_MagnifierPS.GetPassOutputResource();
}
SetPerfMarkerBegin(cmdBuf2, "Swapchain RenderPass");
// prepare render pass
{
VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.pNext = NULL;
rp_begin.renderPass = pSwapChain->GetRenderPass();
rp_begin.framebuffer = pSwapChain->GetFramebuffer(imageIndex);
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent = srd.extent;
rp_begin.clearValueCount = 0;
rp_begin.pClearValues = NULL;
vkCmdBeginRenderPass(cmdBuf2, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
}
vkCmdSetScissor(cmdBuf2, 0, 1, &srd);
vkCmdSetViewport(cmdBuf2, 0, 1, &vpd);
if (bHDR)
{
m_ColorConversionPS.Draw(cmdBuf2, SRVCurrentInput);
m_GPUTimer.GetTimeStamp(cmdBuf2, "Color Conversion");
}
// For SDR pipeline, we apply the tonemapping and then draw the GUI and skip the color conversion
else
{
// Tonemapping ------------------------------------------------------------------------
{
m_ToneMappingPS.Draw(cmdBuf2, SRVCurrentInput, pState->Exposure, pState->SelectedTonemapperIndex);
m_GPUTimer.GetTimeStamp(cmdBuf2, "Tonemapping");
}
// Render HUD -------------------------------------------------------------------------
{
m_ImGUI.Draw(cmdBuf2);
m_GPUTimer.GetTimeStamp(cmdBuf2, "ImGUI Rendering");
}
}
SetPerfMarkerEnd(cmdBuf2);
vkCmdEndRenderPass(cmdBuf2);
if (pState->bEnableFrameRateLimiter &&
pState->bUseGPUFrameRateLimiter &&
!m_TimeStamps.empty())
{
m_GpuFrameRateLimiter.Draw(cmdBuf2, &m_ConstantBufferRing, uint64_t(m_TimeStamps.back().m_microseconds), uint64_t(pState->targetFrameTime * 1000));
m_GPUTimer.GetTimeStamp(cmdBuf2, "FrameRateLimiter");
}
m_GPUTimer.OnEndFrame();
// Close & Submit the command list ----------------------------------------------------
{
VkResult res = vkEndCommandBuffer(cmdBuf2);
assert(res == VK_SUCCESS);
VkSemaphore ImageAvailableSemaphore;
VkSemaphore RenderFinishedSemaphores;
VkFence CmdBufExecutedFences;
pSwapChain->GetSemaphores(&ImageAvailableSemaphore, &RenderFinishedSemaphores, &CmdBufExecutedFences);
VkPipelineStageFlags submitWaitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info2;
submit_info2.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info2.pNext = NULL;
submit_info2.waitSemaphoreCount = 1;
submit_info2.pWaitSemaphores = &ImageAvailableSemaphore;
submit_info2.pWaitDstStageMask = &submitWaitStage;
submit_info2.commandBufferCount = 1;
submit_info2.pCommandBuffers = &cmdBuf2;
submit_info2.signalSemaphoreCount = 1;
submit_info2.pSignalSemaphores = &RenderFinishedSemaphores;
res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info2, CmdBufExecutedFences);
assert(res == VK_SUCCESS);
}
}
void Renderer::BuildDevUI(UIState* pState)
{
if (m_pUpscaleContext)
{
m_pUpscaleContext->BuildDevUI(pState);
}
}