Files
WickedEngine/WickedEngine/RenderPath3D.cpp
T
2020-12-12 01:14:33 +01:00

1348 lines
41 KiB
C++

#include "RenderPath3D.h"
#include "wiRenderer.h"
#include "wiImage.h"
#include "wiHelper.h"
#include "wiTextureHelper.h"
#include "ResourceMapping.h"
#include "wiProfiler.h"
using namespace wiGraphics;
void RenderPath3D::ResizeBuffers()
{
GraphicsDevice* device = wiRenderer::GetDevice();
FORMAT defaultTextureFormat = device->GetBackBufferFormat();
XMUINT2 internalResolution = GetInternalResolution();
camera->CreatePerspective((float)internalResolution.x, (float)internalResolution.y, camera->zNearP, camera->zFarP);
// Render targets:
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
if (getMSAASampleCount() == 1)
{
desc.BindFlags |= BIND_UNORDERED_ACCESS;
}
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.SampleCount = getMSAASampleCount();
desc.Format = FORMAT_R16G16B16A16_FLOAT;
device->CreateTexture(&desc, nullptr, &rtGbuffer[GBUFFER_COLOR_ROUGHNESS]);
device->SetName(&rtGbuffer[GBUFFER_COLOR_ROUGHNESS], "rtGbuffer[GBUFFER_COLOR_ROUGHNESS]");
device->CreateTexture(&desc, nullptr, &rtGbuffer[GBUFFER_NORMAL_VELOCITY]);
device->SetName(&rtGbuffer[GBUFFER_NORMAL_VELOCITY], "rtGbuffer[GBUFFER_NORMAL_VELOCITY]");
if (getMSAASampleCount() > 1)
{
desc.SampleCount = 1;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
device->CreateTexture(&desc, nullptr, &rtGbuffer_resolved[GBUFFER_COLOR_ROUGHNESS]);
device->SetName(&rtGbuffer_resolved[GBUFFER_COLOR_ROUGHNESS], "rtGbuffer_resolved[GBUFFER_COLOR_ROUGHNESS]");
device->CreateTexture(&desc, nullptr, &rtGbuffer_resolved[GBUFFER_NORMAL_VELOCITY]);
device->SetName(&rtGbuffer_resolved[GBUFFER_NORMAL_VELOCITY], "rtGbuffer_resolved[GBUFFER_NORMAL_VELOCITY]");
}
}
{
TextureDesc desc;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R16G16B16A16_FLOAT;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtSSR);
device->SetName(&rtSSR, "rtSSR");
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
desc.Format = FORMAT_R16G16B16A16_FLOAT;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.SampleCount = getMSAASampleCount();
device->CreateTexture(&desc, nullptr, &rtParticleDistortion);
device->SetName(&rtParticleDistortion, "rtParticleDistortion");
if (getMSAASampleCount() > 1)
{
desc.SampleCount = 1;
device->CreateTexture(&desc, nullptr, &rtParticleDistortion_Resolved);
device->SetName(&rtParticleDistortion_Resolved, "rtParticleDistortion_Resolved");
}
}
{
TextureDesc desc;
desc.Format = FORMAT_R16G16B16A16_FLOAT;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Width = internalResolution.x / 4;
desc.Height = internalResolution.y / 4;
device->CreateTexture(&desc, nullptr, &rtVolumetricLights[0]);
device->SetName(&rtVolumetricLights[0], "rtVolumetricLights[0]");
device->CreateTexture(&desc, nullptr, &rtVolumetricLights[1]);
device->SetName(&rtVolumetricLights[1], "rtVolumetricLights[1]");
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
desc.Format = FORMAT_R8G8B8A8_SNORM;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtWaterRipple);
device->SetName(&rtWaterRipple, "rtWaterRipple");
}
{
TextureDesc desc;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS | BIND_RENDER_TARGET;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.Width = internalResolution.x / 2;
desc.Height = internalResolution.y / 2;
desc.MipLevels = std::min(8u, (uint32_t)std::log2(std::max(desc.Width, desc.Height)));
device->CreateTexture(&desc, nullptr, &rtSceneCopy);
device->SetName(&rtSceneCopy, "rtSceneCopy");
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
device->CreateTexture(&desc, nullptr, &rtSceneCopy_tmp);
device->SetName(&rtSceneCopy_tmp, "rtSceneCopy_tmp");
for (uint32_t i = 0; i < rtSceneCopy.GetDesc().MipLevels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&rtSceneCopy, SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtSceneCopy_tmp, SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtSceneCopy, UAV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtSceneCopy_tmp, UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.Width = internalResolution.x / 4;
desc.Height = internalResolution.y / 4;
desc.layout = IMAGE_LAYOUT_SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &rtReflection);
device->SetName(&rtReflection, "rtReflection");
}
{
TextureDesc desc;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R8_UNORM;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtAO);
device->SetName(&rtAO, "rtAO");
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
desc.Format = defaultTextureFormat;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.SampleCount = getMSAASampleCount();
device->CreateTexture(&desc, nullptr, &rtSun[0]);
device->SetName(&rtSun[0], "rtSun[0]");
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.SampleCount = 1;
desc.Width = internalResolution.x / 2;
desc.Height = internalResolution.y / 2;
device->CreateTexture(&desc, nullptr, &rtSun[1]);
device->SetName(&rtSun[1], "rtSun[1]");
if (getMSAASampleCount() > 1)
{
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.SampleCount = 1;
device->CreateTexture(&desc, nullptr, &rtSun_resolved);
device->SetName(&rtSun_resolved, "rtSun_resolved");
}
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.Width = internalResolution.x / 4;
desc.Height = internalResolution.y / 4;
desc.MipLevels = std::min(5u, (uint32_t)std::log2(std::max(desc.Width, desc.Height)));
device->CreateTexture(&desc, nullptr, &rtBloom);
device->SetName(&rtBloom, "rtBloom");
device->CreateTexture(&desc, nullptr, &rtBloom_tmp);
device->SetName(&rtBloom_tmp, "rtBloom_tmp");
for (uint32_t i = 0; i < rtBloom.GetDesc().MipLevels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&rtBloom, SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtBloom_tmp, SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtBloom, UAV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtBloom_tmp, UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
{
TextureDesc desc;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtTemporalAA[0]);
device->SetName(&rtTemporalAA[0], "rtTemporalAA[0]");
device->CreateTexture(&desc, nullptr, &rtTemporalAA[1]);
device->SetName(&rtTemporalAA[1], "rtTemporalAA[1]");
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtPostprocess_HDR);
device->SetName(&rtPostprocess_HDR, "rtPostprocess_HDR");
}
{
TextureDesc desc;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = defaultTextureFormat;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
device->CreateTexture(&desc, nullptr, &rtPostprocess_LDR[0]);
device->SetName(&rtPostprocess_LDR[0], "rtPostprocess_LDR[0]");
device->CreateTexture(&desc, nullptr, &rtPostprocess_LDR[1]);
device->SetName(&rtPostprocess_LDR[1], "rtPostprocess_LDR[1]");
desc.Width /= 4;
desc.Height /= 4;
desc.BindFlags = BIND_UNORDERED_ACCESS | BIND_SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[0]);
device->SetName(&rtGUIBlurredBackground[0], "rtGUIBlurredBackground[0]");
desc.Width /= 4;
desc.Height /= 4;
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[1]);
device->SetName(&rtGUIBlurredBackground[1], "rtGUIBlurredBackground[1]");
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[2]);
device->SetName(&rtGUIBlurredBackground[2], "rtGUIBlurredBackground[2]");
}
if(device->CheckCapability(GRAPHICSDEVICE_CAPABILITY_VARIABLE_RATE_SHADING_TIER2))
{
uint32_t tileSize = device->GetVariableRateShadingTileSize();
TextureDesc desc;
desc.BindFlags = BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R8_UINT;
desc.Width = (internalResolution.x + tileSize - 1) / tileSize;
desc.Height = (internalResolution.y + tileSize - 1) / tileSize;
device->CreateTexture(&desc, nullptr, &rtShadingRate);
device->SetName(&rtShadingRate, "rtShadingRate");
}
// Depth buffers:
{
TextureDesc desc;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.SampleCount = getMSAASampleCount();
desc.layout = IMAGE_LAYOUT_DEPTHSTENCIL_READONLY;
if (getMSAASampleCount() > 1)
{
desc.Format = FORMAT_R32G8X24_TYPELESS;
desc.BindFlags = BIND_DEPTH_STENCIL | BIND_SHADER_RESOURCE;
}
else
{
desc.Format = FORMAT_D32_FLOAT_S8X24_UINT;
desc.BindFlags = BIND_DEPTH_STENCIL;
}
device->CreateTexture(&desc, nullptr, &depthBuffer_Main);
device->SetName(&depthBuffer_Main, "depthBuffer_Main");
if (getMSAASampleCount() > 1)
{
desc.Format = FORMAT_R32_FLOAT;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
}
else
{
desc.Format = FORMAT_R32G8X24_TYPELESS;
desc.BindFlags = BIND_DEPTH_STENCIL | BIND_SHADER_RESOURCE;
}
desc.SampleCount = 1;
desc.layout = IMAGE_LAYOUT_SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &depthBuffer_Copy);
device->SetName(&depthBuffer_Copy, "depthBuffer_Copy");
device->CreateTexture(&desc, nullptr, &depthBuffer_Copy1);
device->SetName(&depthBuffer_Copy1, "depthBuffer_Copy1");
}
{
TextureDesc desc;
desc.BindFlags = BIND_DEPTH_STENCIL | BIND_SHADER_RESOURCE;
desc.Format = FORMAT_R32_TYPELESS;
desc.Width = internalResolution.x / 4;
desc.Height = internalResolution.y / 4;
desc.layout = IMAGE_LAYOUT_DEPTHSTENCIL_READONLY;
device->CreateTexture(&desc, nullptr, &depthBuffer_Reflection);
device->SetName(&depthBuffer_Reflection, "depthBuffer_Reflection");
}
{
TextureDesc desc;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.Format = FORMAT_R32_FLOAT;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.MipLevels = 6;
device->CreateTexture(&desc, nullptr, &rtLinearDepth);
device->SetName(&rtLinearDepth, "rtLinearDepth");
for (uint32_t i = 0; i < desc.MipLevels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&rtLinearDepth, SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&rtLinearDepth, UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
// Render passes:
{
RenderPassDesc desc;
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Main,
RenderPassAttachment::LOADOP_CLEAR,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
device->CreateRenderPass(&desc, &renderpass_depthprepass);
desc.attachments.clear();
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtGbuffer[GBUFFER_COLOR_ROUGHNESS], RenderPassAttachment::LOADOP_DONTCARE));
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtGbuffer[GBUFFER_NORMAL_VELOCITY], RenderPassAttachment::LOADOP_CLEAR));
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Main,
RenderPassAttachment::LOADOP_LOAD,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
if (getMSAASampleCount() > 1)
{
desc.attachments.push_back(RenderPassAttachment::Resolve(GetGbuffer_Read(GBUFFER_COLOR_ROUGHNESS)));
desc.attachments.push_back(RenderPassAttachment::Resolve(GetGbuffer_Read(GBUFFER_NORMAL_VELOCITY)));
}
device->CreateRenderPass(&desc, &renderpass_main);
}
{
RenderPassDesc desc;
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtGbuffer[GBUFFER_COLOR_ROUGHNESS], RenderPassAttachment::LOADOP_LOAD));
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Main,
RenderPassAttachment::LOADOP_LOAD,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
if (getMSAASampleCount() > 1)
{
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtGbuffer_resolved[GBUFFER_COLOR_ROUGHNESS]));
}
device->CreateRenderPass(&desc, &renderpass_transparent);
}
{
RenderPassDesc desc;
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Reflection,
RenderPassAttachment::LOADOP_CLEAR,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL,
IMAGE_LAYOUT_SHADER_RESOURCE
)
);
device->CreateRenderPass(&desc, &renderpass_reflection_depthprepass);
}
{
RenderPassDesc desc;
desc.attachments.push_back(
RenderPassAttachment::RenderTarget(
&rtReflection,
RenderPassAttachment::LOADOP_DONTCARE,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_SHADER_RESOURCE,
IMAGE_LAYOUT_RENDERTARGET,
IMAGE_LAYOUT_SHADER_RESOURCE
)
);
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Reflection,
RenderPassAttachment::LOADOP_LOAD,
RenderPassAttachment::STOREOP_DONTCARE,
IMAGE_LAYOUT_SHADER_RESOURCE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
device->CreateRenderPass(&desc, &renderpass_reflection);
}
{
RenderPassDesc desc;
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtSceneCopy, RenderPassAttachment::LOADOP_DONTCARE));
device->CreateRenderPass(&desc, &renderpass_downsamplescene);
}
{
RenderPassDesc desc;
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Main,
RenderPassAttachment::LOADOP_LOAD,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtSun[0], RenderPassAttachment::LOADOP_CLEAR));
if (getMSAASampleCount() > 1)
{
desc.attachments.back().storeop = RenderPassAttachment::STOREOP_DONTCARE;
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtSun_resolved));
}
device->CreateRenderPass(&desc, &renderpass_lightshafts);
}
{
RenderPassDesc desc;
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtVolumetricLights[0], RenderPassAttachment::LOADOP_CLEAR));
device->CreateRenderPass(&desc, &renderpass_volumetriclight);
}
{
RenderPassDesc desc;
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtParticleDistortion, RenderPassAttachment::LOADOP_CLEAR));
desc.attachments.push_back(
RenderPassAttachment::DepthStencil(
&depthBuffer_Main,
RenderPassAttachment::LOADOP_LOAD,
RenderPassAttachment::STOREOP_STORE,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY,
IMAGE_LAYOUT_DEPTHSTENCIL_READONLY
)
);
if (getMSAASampleCount() > 1)
{
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtParticleDistortion_Resolved));
}
device->CreateRenderPass(&desc, &renderpass_particledistortion);
}
{
RenderPassDesc desc;
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtWaterRipple, RenderPassAttachment::LOADOP_CLEAR));
device->CreateRenderPass(&desc, &renderpass_waterripples);
}
// Other resources:
const XMUINT3 tileCount = wiRenderer::GetEntityCullingTileCount(internalResolution);
{
GPUBufferDesc bd;
bd.StructureByteStride = sizeof(XMFLOAT4) * 4; // storing 4 planes for every tile
bd.ByteWidth = bd.StructureByteStride * tileCount.x * tileCount.y;
bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
bd.Usage = USAGE_DEFAULT;
bd.CPUAccessFlags = 0;
device->CreateBuffer(&bd, nullptr, &tileFrustums);
device->SetName(&tileFrustums, "tileFrustums");
}
{
GPUBufferDesc bd;
bd.StructureByteStride = sizeof(uint);
bd.ByteWidth = tileCount.x * tileCount.y * bd.StructureByteStride * SHADER_ENTITY_TILE_BUCKET_COUNT;
bd.Usage = USAGE_DEFAULT;
bd.BindFlags = BIND_UNORDERED_ACCESS | BIND_SHADER_RESOURCE;
bd.CPUAccessFlags = 0;
bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
device->CreateBuffer(&bd, nullptr, &entityTiles_Opaque);
device->CreateBuffer(&bd, nullptr, &entityTiles_Transparent);
device->SetName(&entityTiles_Opaque, "entityTiles_Opaque");
device->SetName(&entityTiles_Transparent, "entityTiles_Transparent");
}
{
TextureDesc desc;
desc.Width = internalResolution.x;
desc.Height = internalResolution.y;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = FORMAT_R8G8B8A8_UNORM;
desc.SampleCount = 1;
desc.Usage = USAGE_DEFAULT;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
device->CreateTexture(&desc, nullptr, &debugUAV);
device->SetName(&debugUAV, "debugUAV");
}
RenderPath2D::ResizeBuffers();
}
void RenderPath3D::PreUpdate()
{
camera_previous = *camera;
}
void RenderPath3D::Update(float dt)
{
RenderPath2D::Update(dt);
scene->Update(dt * wiRenderer::GetGameSpeed());
// Frustum culling for main camera:
visibility_main.layerMask = getLayerMask();
visibility_main.scene = scene;
visibility_main.camera = camera;
visibility_main.flags = wiRenderer::Visibility::ALLOW_EVERYTHING;
wiRenderer::UpdateVisibility(visibility_main);
if (visibility_main.planar_reflection_visible)
{
// Frustum culling for planar reflections:
camera_reflection = *camera;
camera_reflection.jitter = XMFLOAT2(0, 0);
camera_reflection.Reflect(visibility_main.reflectionPlane);
visibility_reflection.layerMask = getLayerMask();
visibility_reflection.scene = scene;
visibility_reflection.camera = &camera_reflection;
visibility_reflection.flags = wiRenderer::Visibility::ALLOW_OBJECTS;
wiRenderer::UpdateVisibility(visibility_reflection);
}
wiRenderer::OcclusionCulling_Read(*scene, visibility_main);
wiRenderer::UpdatePerFrameData(*scene, visibility_main, frameCB, GetInternalResolution(), dt);
if (wiRenderer::GetTemporalAAEnabled())
{
const XMFLOAT4& halton = wiMath::GetHaltonSequence(wiRenderer::GetDevice()->GetFrameCount() % 256);
camera->jitter.x = (halton.x * 2 - 1) / (float)GetInternalResolution().x;
camera->jitter.y = (halton.y * 2 - 1) / (float)GetInternalResolution().y;
}
else
{
camera->jitter = XMFLOAT2(0, 0);
}
camera->UpdateCamera();
std::swap(depthBuffer_Copy, depthBuffer_Copy1);
}
void RenderPath3D::Render() const
{
GraphicsDevice* device = wiRenderer::GetDevice();
wiJobSystem::context ctx;
CommandList cmd;
// Preparing the frame:
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [this, cmd](wiJobArgs args) {
RenderFrameSetUp(cmd);
});
static const uint32_t drawscene_flags =
wiRenderer::DRAWSCENE_OPAQUE |
wiRenderer::DRAWSCENE_HAIRPARTICLE |
wiRenderer::DRAWSCENE_TESSELLATION |
wiRenderer::DRAWSCENE_OCCLUSIONCULLING
;
static const uint32_t drawscene_flags_reflections =
wiRenderer::DRAWSCENE_OPAQUE
;
// Depth prepass + Occlusion culling + AO:
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [this, cmd](wiJobArgs args) {
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("Opaque Z-prepass", cmd);
wiRenderer::UpdateCameraCB(
*camera,
camera_previous,
camera_reflection,
cmd
);
device->RenderPassBegin(&renderpass_depthprepass, cmd);
auto range = wiProfiler::BeginRangeGPU("Z-Prepass", cmd);
Viewport vp;
vp.Width = (float)depthBuffer_Main.GetDesc().Width;
vp.Height = (float)depthBuffer_Main.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiRenderer::DrawScene(visibility_main, RENDERPASS_DEPTHONLY, cmd, drawscene_flags);
wiProfiler::EndRange(range);
wiRenderer::OcclusionCulling_Render(*camera, visibility_main, cmd);
device->RenderPassEnd(cmd);
// Make a readable copy for depth buffer:
if (getMSAASampleCount() > 1)
{
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&depthBuffer_Main, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY, IMAGE_LAYOUT_SHADER_RESOURCE),
GPUBarrier::Image(&depthBuffer_Copy, IMAGE_LAYOUT_SHADER_RESOURCE, IMAGE_LAYOUT_UNORDERED_ACCESS)
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
wiRenderer::ResolveMSAADepthBuffer(depthBuffer_Copy, depthBuffer_Main, cmd);
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&depthBuffer_Main, IMAGE_LAYOUT_SHADER_RESOURCE, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY),
GPUBarrier::Image(&depthBuffer_Copy, IMAGE_LAYOUT_UNORDERED_ACCESS, IMAGE_LAYOUT_SHADER_RESOURCE)
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
}
else
{
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&depthBuffer_Main, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY, IMAGE_LAYOUT_COPY_SRC),
GPUBarrier::Image(&depthBuffer_Copy, IMAGE_LAYOUT_SHADER_RESOURCE, IMAGE_LAYOUT_COPY_DST)
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
device->CopyResource(&depthBuffer_Copy, &depthBuffer_Main, cmd);
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&depthBuffer_Main, IMAGE_LAYOUT_COPY_SRC, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY),
GPUBarrier::Image(&depthBuffer_Copy, IMAGE_LAYOUT_COPY_DST, IMAGE_LAYOUT_SHADER_RESOURCE)
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
}
wiRenderer::Postprocess_Lineardepth(depthBuffer_Copy, rtLinearDepth, cmd);
RenderAO(cmd);
if (wiRenderer::GetVariableRateShadingClassification() && device->CheckCapability(GRAPHICSDEVICE_CAPABILITY_VARIABLE_RATE_SHADING_TIER2))
{
wiRenderer::ComputeShadingRateClassification(
GetGbuffer_Read(),
rtLinearDepth,
rtShadingRate,
debugUAV,
cmd
);
}
device->EventEnd(cmd);
});
// Planar reflections depth prepass + Light culling:
if (visibility_main.IsRequestedPlanarReflections())
{
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [cmd, this](wiJobArgs args) {
auto range = wiProfiler::BeginRangeGPU("Planar Reflections Z-Prepass", cmd);
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("Planar reflections Z-Prepass", cmd);
wiRenderer::UpdateCameraCB(
camera_reflection,
camera_reflection,
camera_reflection,
cmd
);
Viewport vp;
vp.Width = (float)depthBuffer_Reflection.GetDesc().Width;
vp.Height = (float)depthBuffer_Reflection.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
device->RenderPassBegin(&renderpass_reflection_depthprepass, cmd);
wiRenderer::DrawScene(visibility_reflection, RENDERPASS_DEPTHONLY, cmd, drawscene_flags_reflections);
device->RenderPassEnd(cmd);
wiRenderer::ComputeTiledLightCulling(
*camera,
depthBuffer_Reflection,
tileFrustums,
entityTiles_Opaque,
entityTiles_Transparent,
debugUAV,
cmd
);
device->EventEnd(cmd);
wiProfiler::EndRange(range); // Planar Reflections
});
}
// Shadow maps:
if (getShadowsEnabled() && !wiRenderer::GetRaytracedShadowsEnabled())
{
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [this, cmd](wiJobArgs args) {
wiRenderer::DrawShadowmaps(visibility_main, cmd);
});
}
// Updating textures:
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [cmd, this](wiJobArgs args) {
wiRenderer::BindCommonResources(cmd);
wiRenderer::RefreshDecalAtlas(*scene, cmd);
wiRenderer::RefreshLightmapAtlas(*scene, cmd);
wiRenderer::RefreshEnvProbes(visibility_main, cmd);
wiRenderer::RefreshImpostors(*scene, cmd);
});
// Voxel GI:
if (wiRenderer::GetVoxelRadianceEnabled())
{
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [cmd, this](wiJobArgs args) {
wiRenderer::VoxelRadiance(visibility_main, cmd);
});
}
// Planar reflections:
if (visibility_main.IsRequestedPlanarReflections())
{
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [cmd, this](wiJobArgs args) {
auto range = wiProfiler::BeginRangeGPU("Planar Reflections", cmd);
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("Planar reflections", cmd);
wiRenderer::UpdateCameraCB(
camera_reflection,
camera_reflection,
camera_reflection,
cmd
);
Viewport vp;
vp.Width = (float)depthBuffer_Reflection.GetDesc().Width;
vp.Height = (float)depthBuffer_Reflection.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
GPUBarrier barriers[] = {
GPUBarrier::Memory(&entityTiles_Opaque),
};
device->Barrier(barriers, arraysize(barriers), cmd);
device->UnbindResources(TEXSLOT_DEPTH, 1, cmd);
device->RenderPassBegin(&renderpass_reflection, cmd);
device->BindResource(PS, &entityTiles_Opaque, TEXSLOT_RENDERPATH_ENTITYTILES, cmd);
device->BindResource(PS, wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_REFLECTION, cmd);
device->BindResource(PS, wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd);
device->BindResource(PS, wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd);
wiRenderer::DrawScene(visibility_reflection, RENDERPASS_MAIN, cmd, drawscene_flags_reflections);
wiRenderer::DrawSky(*scene, cmd);
device->RenderPassEnd(cmd);
device->EventEnd(cmd);
wiProfiler::EndRange(range); // Planar Reflections
});
}
// Opaque scene + Light culling:
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [this, cmd](wiJobArgs args) {
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("Opaque Scene", cmd);
wiRenderer::UpdateCameraCB(
*camera,
camera_previous,
camera_reflection,
cmd
);
if (wiRenderer::GetVariableRateShadingClassification() && device->CheckCapability(GRAPHICSDEVICE_CAPABILITY_VARIABLE_RATE_SHADING_TIER2))
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(&rtShadingRate),
GPUBarrier::Image(&rtShadingRate,IMAGE_LAYOUT_UNORDERED_ACCESS, IMAGE_LAYOUT_SHADING_RATE_SOURCE),
};
device->Barrier(barriers, arraysize(barriers), cmd);
device->BindShadingRate(SHADING_RATE_1X1, cmd);
device->BindShadingRateImage(&rtShadingRate, cmd);
}
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
{
auto range = wiProfiler::BeginRangeGPU("Entity Culling", cmd);
wiRenderer::ComputeTiledLightCulling(
*camera,
depthBuffer_Copy,
tileFrustums,
entityTiles_Opaque,
entityTiles_Transparent,
debugUAV,
cmd
);
GPUBarrier barriers[] = {
GPUBarrier::Memory(&entityTiles_Opaque),
};
device->Barrier(barriers, arraysize(barriers), cmd);
wiProfiler::EndRange(range);
}
device->RenderPassBegin(&renderpass_main, cmd);
auto range = wiProfiler::BeginRangeGPU("Opaque Scene", cmd);
Viewport vp;
vp.Width = (float)depthBuffer_Main.GetDesc().Width;
vp.Height = (float)depthBuffer_Main.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
device->BindResource(PS, &entityTiles_Opaque, TEXSLOT_RENDERPATH_ENTITYTILES, cmd);
device->BindResource(PS, getReflectionsEnabled() ? &rtReflection : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_REFLECTION, cmd);
device->BindResource(PS, getAOEnabled() ? &rtAO : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd);
device->BindResource(PS, getSSREnabled() || getRaytracedReflectionEnabled() ? &rtSSR : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd);
wiRenderer::DrawScene(visibility_main, RENDERPASS_MAIN, cmd, drawscene_flags);
wiRenderer::DrawSky(*scene, cmd);
wiProfiler::EndRange(range); // Opaque Scene
RenderOutline(cmd);
device->RenderPassEnd(cmd);
device->BindShadingRateImage(nullptr, cmd);
device->EventEnd(cmd);
});
// Transparents, post processes, etc:
cmd = device->BeginCommandList();
wiJobSystem::Execute(ctx, [this, cmd](wiJobArgs args) {
GraphicsDevice* device = wiRenderer::GetDevice();
wiRenderer::UpdateCameraCB(
*camera,
camera_previous,
camera_reflection,
cmd
);
wiRenderer::BindCommonResources(cmd);
RenderLightShafts(cmd);
RenderVolumetrics(cmd);
RenderSceneMIPChain(cmd);
RenderSSR(cmd);
RenderTransparents(cmd);
RenderPostprocessChain(cmd);
});
RenderPath2D::Render();
wiJobSystem::Wait(ctx);
}
void RenderPath3D::Compose(CommandList cmd) const
{
GraphicsDevice* device = wiRenderer::GetDevice();
wiImageParams fx;
fx.blendFlag = BLENDMODE_OPAQUE;
fx.quality = QUALITY_LINEAR;
fx.enableFullScreen();
device->EventBegin("Composition", cmd);
wiImage::Draw(GetLastPostprocessRT(), fx, cmd);
device->EventEnd(cmd);
if (wiRenderer::GetDebugLightCulling() || wiRenderer::GetVariableRateShadingClassificationDebug())
{
wiImage::Draw(&debugUAV, wiImageParams((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight()), cmd);
}
RenderPath2D::Compose(cmd);
}
void RenderPath3D::RenderFrameSetUp(CommandList cmd) const
{
GraphicsDevice* device = wiRenderer::GetDevice();
device->BindResource(CS, &depthBuffer_Copy1, TEXSLOT_DEPTH, cmd);
wiRenderer::UpdateRenderData(visibility_main, frameCB, cmd);
if (getAO() == AO_RTAO || wiRenderer::GetRaytracedShadowsEnabled() || getRaytracedReflectionEnabled())
{
wiRenderer::UpdateRaytracingAccelerationStructures(*scene, cmd);
}
}
void RenderPath3D::RenderAO(CommandList cmd) const
{
wiRenderer::GetDevice()->UnbindResources(TEXSLOT_RENDERPATH_AO, 1, cmd);
if (getAOEnabled())
{
switch (getAO())
{
case AO_SSAO:
wiRenderer::Postprocess_SSAO(
depthBuffer_Copy,
rtLinearDepth,
rtAO,
cmd,
getAORange(),
getAOSampleCount(),
getAOPower()
);
break;
case AO_HBAO:
wiRenderer::Postprocess_HBAO(
*camera,
rtLinearDepth,
rtAO,
cmd,
getAOPower()
);
break;
case AO_MSAO:
wiRenderer::Postprocess_MSAO(
*camera,
rtLinearDepth,
rtAO,
cmd,
getAOPower()
);
break;
case AO_RTAO:
wiRenderer::Postprocess_RTAO(
*scene,
depthBuffer_Copy,
rtLinearDepth,
depthBuffer_Copy1,
rtAO,
cmd,
getAORange(),
getAOSampleCount(),
getAOPower()
);
break;
}
}
}
void RenderPath3D::RenderSSR(CommandList cmd) const
{
if (getRaytracedReflectionEnabled())
{
wiRenderer::Postprocess_RTReflection(
*scene,
depthBuffer_Copy,
GetGbuffer_Read(),
rtSSR,
cmd
);
}
else if (getSSREnabled())
{
wiRenderer::Postprocess_SSR(
rtSceneCopy,
depthBuffer_Copy,
rtLinearDepth,
GetGbuffer_Read(),
rtSSR,
cmd
);
}
}
void RenderPath3D::RenderOutline(CommandList cmd) const
{
if (getOutlineEnabled())
{
wiRenderer::Postprocess_Outline(rtLinearDepth, cmd, getOutlineThreshold(), getOutlineThickness(), getOutlineColor());
}
}
void RenderPath3D::RenderLightShafts(CommandList cmd) const
{
XMVECTOR sunDirection = XMLoadFloat3(&scene->weather.sunDirection);
if (getLightShaftsEnabled() && XMVectorGetX(XMVector3Dot(sunDirection, camera->GetAt())) > 0)
{
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("Light Shafts", cmd);
device->UnbindResources(TEXSLOT_ONDEMAND0, TEXSLOT_ONDEMAND_COUNT, cmd);
// Render sun stencil cutout:
{
device->RenderPassBegin(&renderpass_lightshafts, cmd);
Viewport vp;
vp.Width = (float)depthBuffer_Main.GetDesc().Width;
vp.Height = (float)depthBuffer_Main.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiRenderer::DrawSun(cmd);
device->RenderPassEnd(cmd);
}
// Radial blur on the sun:
{
XMVECTOR sunPos = XMVector3Project(sunDirection * 100000, 0, 0,
1.0f, 1.0f, 0.1f, 1.0f,
camera->GetProjection(), camera->GetView(), XMMatrixIdentity());
{
XMFLOAT2 sun;
XMStoreFloat2(&sun, sunPos);
wiRenderer::Postprocess_LightShafts(*renderpass_lightshafts.desc.attachments.back().texture, rtSun[1], cmd, sun);
}
}
device->EventEnd(cmd);
}
}
void RenderPath3D::RenderVolumetrics(CommandList cmd) const
{
if (getVolumeLightsEnabled() && visibility_main.IsRequestedVolumetricLights())
{
auto range = wiProfiler::BeginRangeGPU("Volumetric Lights", cmd);
GraphicsDevice* device = wiRenderer::GetDevice();
device->RenderPassBegin(&renderpass_volumetriclight, cmd);
Viewport vp;
vp.Width = (float)rtVolumetricLights[0].GetDesc().Width;
vp.Height = (float)rtVolumetricLights[0].GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiRenderer::DrawVolumeLights(visibility_main, depthBuffer_Copy, cmd);
device->RenderPassEnd(cmd);
wiRenderer::Postprocess_Blur_Bilateral(
rtVolumetricLights[0],
rtLinearDepth,
rtVolumetricLights[1],
rtVolumetricLights[0],
cmd
);
wiProfiler::EndRange(range);
}
}
void RenderPath3D::RenderSceneMIPChain(CommandList cmd) const
{
GraphicsDevice* device = wiRenderer::GetDevice();
auto range = wiProfiler::BeginRangeGPU("Scene MIP Chain", cmd);
device->EventBegin("RenderSceneMIPChain", cmd);
device->RenderPassBegin(&renderpass_downsamplescene, cmd);
Viewport vp;
vp.Width = (float)rtSceneCopy.GetDesc().Width;
vp.Height = (float)rtSceneCopy.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiImageParams fx;
fx.enableFullScreen();
fx.sampleFlag = SAMPLEMODE_CLAMP;
fx.quality = QUALITY_LINEAR;
fx.blendFlag = BLENDMODE_OPAQUE;
wiImage::Draw(GetGbuffer_Read(GBUFFER_COLOR_ROUGHNESS), fx, cmd);
device->RenderPassEnd(cmd);
wiRenderer::MIPGEN_OPTIONS mipopt;
mipopt.gaussian_temp = &rtSceneCopy_tmp;
wiRenderer::GenerateMipChain(rtSceneCopy, wiRenderer::MIPGENFILTER_GAUSSIAN, cmd, mipopt);
device->EventEnd(cmd);
wiProfiler::EndRange(range);
}
void RenderPath3D::RenderTransparents(CommandList cmd) const
{
GraphicsDevice* device = wiRenderer::GetDevice();
// Water ripple rendering:
if(wiRenderer::IsWaterrippleRendering())
{
device->RenderPassBegin(&renderpass_waterripples, cmd);
Viewport vp;
vp.Width = (float)rtWaterRipple.GetDesc().Width;
vp.Height = (float)rtWaterRipple.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiRenderer::DrawWaterRipples(visibility_main, cmd);
device->RenderPassEnd(cmd);
}
device->UnbindResources(TEXSLOT_GBUFFER0, 1, cmd);
device->UnbindResources(TEXSLOT_ONDEMAND0, TEXSLOT_ONDEMAND_COUNT, cmd);
GPUBarrier barriers[] = {
GPUBarrier::Memory(&entityTiles_Transparent),
};
device->Barrier(barriers, arraysize(barriers), cmd);
device->RenderPassBegin(&renderpass_transparent, cmd);
Viewport vp;
vp.Width = (float)depthBuffer_Main.GetDesc().Width;
vp.Height = (float)depthBuffer_Main.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
// Transparent scene
{
auto range = wiProfiler::BeginRangeGPU("Transparent Scene", cmd);
device->EventBegin("Transparent Scene", cmd);
device->BindResource(PS, &entityTiles_Transparent, TEXSLOT_RENDERPATH_ENTITYTILES, cmd);
device->BindResource(PS, &rtLinearDepth, TEXSLOT_LINEARDEPTH, cmd);
device->BindResource(PS, getReflectionsEnabled() ? &rtReflection : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_REFLECTION, cmd);
device->BindResource(PS, &rtSceneCopy, TEXSLOT_RENDERPATH_REFRACTION, cmd);
device->BindResource(PS, &rtWaterRipple, TEXSLOT_RENDERPATH_WATERRIPPLES, cmd);
uint32_t drawscene_flags = 0;
drawscene_flags |= wiRenderer::DRAWSCENE_TRANSPARENT;
drawscene_flags |= wiRenderer::DRAWSCENE_OCCLUSIONCULLING;
drawscene_flags |= wiRenderer::DRAWSCENE_HAIRPARTICLE;
wiRenderer::DrawScene(visibility_main, RENDERPASS_MAIN, cmd, drawscene_flags);
device->EventEnd(cmd);
wiProfiler::EndRange(range); // Transparent Scene
}
wiRenderer::DrawLightVisualizers(visibility_main, cmd);
wiRenderer::DrawSoftParticles(visibility_main, rtLinearDepth, false, cmd);
if (getVolumeLightsEnabled() && visibility_main.IsRequestedVolumetricLights())
{
device->EventBegin("Contribute Volumetric Lights", cmd);
wiRenderer::Postprocess_Upsample_Bilateral(rtVolumetricLights[0], rtLinearDepth,
*renderpass_transparent.desc.attachments[0].texture, cmd, true, 1.5f);
device->EventEnd(cmd);
}
if (getLightShaftsEnabled())
{
device->EventBegin("Contribute LightShafts", cmd);
wiImageParams fx;
fx.enableFullScreen();
fx.blendFlag = BLENDMODE_ADDITIVE;
wiImage::Draw(&rtSun[1], fx, cmd);
device->EventEnd(cmd);
}
if (getLensFlareEnabled())
{
wiRenderer::DrawLensFlares(visibility_main, depthBuffer_Copy, cmd);
}
wiRenderer::DrawDebugWorld(*scene, *camera, cmd);
device->RenderPassEnd(cmd);
// Distortion particles:
{
device->RenderPassBegin(&renderpass_particledistortion, cmd);
Viewport vp;
vp.Width = (float)rtParticleDistortion.GetDesc().Width;
vp.Height = (float)rtParticleDistortion.GetDesc().Height;
device->BindViewports(1, &vp, cmd);
wiRenderer::DrawSoftParticles(visibility_main, rtLinearDepth, true, cmd);
device->RenderPassEnd(cmd);
}
}
void RenderPath3D::RenderPostprocessChain(CommandList cmd) const
{
GraphicsDevice* device = wiRenderer::GetDevice();
const Texture* rt_first = nullptr; // not ping-ponged with read / write
const Texture* rt_read = GetGbuffer_Read(GBUFFER_COLOR_ROUGHNESS);
const Texture* rt_write = &rtPostprocess_HDR;
// 1.) HDR post process chain
{
if (getVolumetricCloudsEnabled())
{
const Texture* lightShaftTemp = nullptr;
wiRenderer::Postprocess_VolumetricClouds(*rt_read, *rt_write, *lightShaftTemp, rtLinearDepth, depthBuffer_Copy, cmd);
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
if (wiRenderer::GetTemporalAAEnabled() && !wiRenderer::GetTemporalAADebugEnabled())
{
GraphicsDevice* device = wiRenderer::GetDevice();
int output = device->GetFrameCount() % 2;
int history = 1 - output;
wiRenderer::Postprocess_TemporalAA(
*rt_read, rtTemporalAA[history],
*GetGbuffer_Read(GBUFFER_NORMAL_VELOCITY),
rtLinearDepth,
depthBuffer_Copy1,
rtTemporalAA[output],
cmd
);
rt_first = &rtTemporalAA[output];
}
if (getDepthOfFieldEnabled())
{
wiRenderer::Postprocess_DepthOfField(rt_first == nullptr ? *rt_read : *rt_first, *rt_write, rtLinearDepth, cmd, getDepthOfFieldFocus(), getDepthOfFieldStrength(), getDepthOfFieldAspect());
rt_first = nullptr;
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
if (getMotionBlurEnabled())
{
wiRenderer::Postprocess_MotionBlur(rt_first == nullptr ? *rt_read : *rt_first, *GetGbuffer_Read(GBUFFER_NORMAL_VELOCITY), rtLinearDepth, *rt_write, cmd, getMotionBlurStrength());
rt_first = nullptr;
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
if (getBloomEnabled())
{
wiRenderer::Postprocess_Bloom(rt_first == nullptr ? *rt_read : *rt_first, rtBloom, rtBloom_tmp, *rt_write, cmd, getBloomThreshold());
rt_first = nullptr;
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
}
// 2.) Tone mapping HDR -> LDR
{
rt_write = &rtPostprocess_LDR[0];
wiRenderer::Postprocess_Tonemap(
rt_first == nullptr ? *rt_read : *rt_first,
getEyeAdaptionEnabled() ? *wiRenderer::ComputeLuminance(*GetGbuffer_Read(GBUFFER_COLOR_ROUGHNESS), cmd) : *wiTextureHelper::getColor(wiColor::Gray()),
getMSAASampleCount() > 1 ? rtParticleDistortion_Resolved : rtParticleDistortion,
*rt_write,
cmd,
getExposure(),
getDitherEnabled(),
getColorGradingEnabled() ? (colorGradingTex != nullptr ? colorGradingTex->texture : wiTextureHelper::getColorGradeDefault()) : nullptr
);
rt_first = nullptr;
rt_read = rt_write;
rt_write = &rtPostprocess_LDR[1];
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
// 3.) LDR post process chain
{
if (getSharpenFilterEnabled())
{
wiRenderer::Postprocess_Sharpen(*rt_read, *rt_write, cmd, getSharpenFilterAmount());
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
if (getFXAAEnabled())
{
wiRenderer::Postprocess_FXAA(*rt_read, *rt_write, cmd);
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
if (getChromaticAberrationEnabled())
{
wiRenderer::Postprocess_Chromatic_Aberration(*rt_read, *rt_write, cmd, getChromaticAberrationAmount());
std::swap(rt_read, rt_write);
device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd);
}
// GUI Background blurring:
{
auto range = wiProfiler::BeginRangeGPU("GUI Background Blur", cmd);
device->EventBegin("GUI Background Blur", cmd);
wiRenderer::Postprocess_Downsample4x(*rt_read, rtGUIBlurredBackground[0], cmd);
wiRenderer::Postprocess_Downsample4x(rtGUIBlurredBackground[0], rtGUIBlurredBackground[2], cmd);
wiRenderer::Postprocess_Blur_Gaussian(rtGUIBlurredBackground[2], rtGUIBlurredBackground[1], rtGUIBlurredBackground[2], cmd, -1,-1, true);
device->EventEnd(cmd);
wiProfiler::EndRange(range);
}
}
}