1312 lines
57 KiB
C++
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, ®ion);
|
|
|
|
// 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);
|
|
}
|
|
} |