Add support for rendering percentage scale with upscaling to backbuffer

This commit is contained in:
Wojtek Figat
2021-07-20 11:06:25 +02:00
parent 5cbf091a7a
commit 929bd2a8c8
11 changed files with 129 additions and 54 deletions

View File

@@ -90,7 +90,7 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
}
// Generate depth
MultiScaler::Instance()->DownscaleDepth(context, halfDepthWidth, halfDepthHeight, DepthBuffer->View(), HalfResDepth->View());
MultiScaler::Instance()->DownscaleDepth(context, halfDepthWidth, halfDepthHeight, DepthBuffer, HalfResDepth->View());
return HalfResDepth;
}

View File

@@ -296,13 +296,27 @@ void SceneRenderTask::OnPostRender(GPUContext* context, RenderContext& renderCon
Viewport SceneRenderTask::GetViewport() const
{
Viewport viewport;
if (Output)
viewport = Viewport(0, 0, static_cast<float>(Output->Width()), static_cast<float>(Output->Height()));
else if (SwapChain)
viewport = Viewport(0, 0, static_cast<float>(SwapChain->GetWidth()), static_cast<float>(SwapChain->GetHeight()));
else if (Buffers != nullptr)
viewport = Buffers->GetViewport();
else
viewport = Viewport(0, 0, 1280, 720);
viewport.Width *= RenderingPercentage;
viewport.Height *= RenderingPercentage;
return viewport;
}
Viewport SceneRenderTask::GetOutputViewport() const
{
if (Output && Output->IsAllocated())
return Viewport(0, 0, static_cast<float>(Output->Width()), static_cast<float>(Output->Height()));
if (SwapChain)
return Viewport(0, 0, static_cast<float>(SwapChain->GetWidth()), static_cast<float>(SwapChain->GetHeight()));
if (Buffers != nullptr)
return Buffers->GetViewport();
return Viewport(0, 0, 1280, 720);
return GetViewport();
}
GPUTextureView* SceneRenderTask::GetOutputView() const
@@ -352,11 +366,11 @@ void SceneRenderTask::OnBegin(GPUContext* context)
// Setup render buffers for the output rendering resolution
if (Output)
{
Buffers->Init(Output->Width(), Output->Height());
Buffers->Init((int32)((float)Output->Width() * RenderingPercentage), (int32)((float)Output->Height() * RenderingPercentage));
}
else if (SwapChain)
{
Buffers->Init(SwapChain->GetWidth(), SwapChain->GetHeight());
Buffers->Init((int32)((float)SwapChain->GetWidth() * RenderingPercentage), (int32)((float)SwapChain->GetHeight() * RenderingPercentage));
}
}
@@ -385,7 +399,7 @@ bool SceneRenderTask::Resize(int32 width, int32 height)
{
if (Output && Output->Resize(width, height))
return true;
if (Buffers && Buffers->Init(width, height))
if (Buffers && Buffers->Init((int32)((float)width * RenderingPercentage), (int32)((float)height * RenderingPercentage)))
return true;
return false;
}
@@ -423,7 +437,7 @@ void MainRenderTask::OnBegin(GPUContext* context)
#if !USE_EDITOR
// Sync render buffers size with the backbuffer
const auto size = Screen::GetSize();
Buffers->Init((int32)size.X, (int32)size.Y);
Buffers->Init((int32)(size.X * RenderingPercentage), (int32)(size.Y * RenderingPercentage));
#endif
SceneRenderTask::OnBegin(context);

View File

@@ -263,6 +263,11 @@ public:
/// </summary>
API_FIELD() ActorsSources ActorsSource = ActorsSources::Scenes;
/// <summary>
/// The scale of the rendering resolution relative to the output dimensions. If lower than 1 the scene and postprocessing will be rendered at a lower resolution and upscaled to the output backbuffer.
/// </summary>
API_FIELD() float RenderingPercentage = 1.0f;
/// <summary>
/// The custom set of actors to render.
/// </summary>
@@ -336,10 +341,15 @@ public:
public:
/// <summary>
/// Gets the rendering render task viewport.
/// Gets the rendering render task viewport (before upsampling).
/// </summary>
API_PROPERTY() Viewport GetViewport() const;
/// <summary>
/// Gets the rendering output viewport (after upsampling).
/// </summary>
API_PROPERTY() Viewport GetOutputViewport() const;
/// <summary>
/// Gets the rendering output view.
/// </summary>

View File

@@ -326,12 +326,12 @@ void RenderList::RunCustomPostFxPass(GPUContext* context, RenderContext& renderC
}
}
bool RenderList::HasAnyPostAA(RenderContext& renderContext) const
bool RenderList::HasAnyPostFx(RenderContext& renderContext, PostProcessEffectLocation postProcess, MaterialPostFxLocation materialPostFx) const
{
for (int32 i = 0; i < Settings.PostFxMaterials.Materials.Count(); i++)
{
auto material = Settings.PostFxMaterials.Materials[i].Get();
if (material && material->IsReady() && material->IsPostFx() && material->GetInfo().PostFxLocation == MaterialPostFxLocation::AfterAntiAliasingPass)
if (material && material->IsReady() && material->IsPostFx() && material->GetInfo().PostFxLocation == materialPostFx)
{
return true;
}
@@ -341,7 +341,7 @@ bool RenderList::HasAnyPostAA(RenderContext& renderContext) const
for (int32 i = 0; i < renderContext.List->PostFx.Count(); i++)
{
auto fx = renderContext.List->PostFx[i];
if (fx->IsReady() && fx->GetLocation() == PostProcessEffectLocation::AfterAntiAliasingPass)
if (fx->IsReady() && fx->GetLocation() == postProcess)
{
return true;
}

View File

@@ -489,11 +489,13 @@ public:
void RunCustomPostFxPass(GPUContext* context, RenderContext& renderContext, PostProcessEffectLocation location, GPUTexture*& input, GPUTexture*& output);
/// <summary>
/// Determines whether any Custom PostFx or Material PostFx has to be rendered after AA pass. Used to pick a faster rendering path by the frame rendering module.
/// Determines whether any Custom PostFx or Material PostFx specified by given type. Used to pick a faster rendering path by the frame rendering module.
/// </summary>
/// <param name="renderContext">The rendering context.</param>
/// <returns>True if render any postFx after AA, otherwise false.</returns>
bool HasAnyPostAA(RenderContext& renderContext) const;
/// <param name="postProcess">The PostFx location to check (for scripts).</param>
/// <param name="materialPostFx">The PostFx location to check (for materials).</param>
/// <returns>True if render any postFx of the given type, otherwise false.</returns>
bool HasAnyPostFx(RenderContext& renderContext, PostProcessEffectLocation postProcess, MaterialPostFxLocation materialPostFx) const;
public:

View File

@@ -332,7 +332,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
// Render reflections debug view
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
context->Draw(lightBuffer->View());
RenderTargetPool::Release(lightBuffer);
return;
@@ -349,7 +349,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
{
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
GBufferPass::Instance()->RenderDebug(renderContext);
RenderTargetPool::Release(lightBuffer);
return;
@@ -367,7 +367,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
RenderTargetPool::Release(lightBuffer);
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
context->Draw(tempBuffer);
return;
}
@@ -381,7 +381,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
{
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
context->Draw(lightBuffer);
RenderTargetPool::Release(lightBuffer);
return;
@@ -421,7 +421,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
if (renderContext.View.Mode == ViewMode::NoPostFx || renderContext.View.Mode == ViewMode::Wireframe)
{
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
context->Draw(forwardPassResult);
return;
}
@@ -475,13 +475,13 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
{
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetOutputViewport());
MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
return;
}
// Anti Aliasing
if (!renderContext.List->HasAnyPostAA(renderContext))
if (!renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, MaterialPostFxLocation::AfterAntiAliasingPass) && Math::IsOne(task->RenderingPercentage))
{
// AA -> Back Buffer
RenderAntiAliasingPass(renderContext, frameBuffer, task->GetOutputView());
@@ -495,12 +495,17 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer);
renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer);
// PostFx -> Back Buffer
// PostFx -> (up-scaling) -> Back Buffer
if (Math::IsOne(task->RenderingPercentage))
{
PROFILE_GPU("Copy frame");
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
context->SetViewportAndScissors(task->GetViewport());
context->Draw(frameBuffer);
}
else
{
MultiScaler::Instance()->Upscale(context, task->GetOutputViewport(), frameBuffer, task->GetOutputView());
}
}
}

View File

@@ -187,8 +187,8 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture
const bool useTemporal = settings.TemporalEffect && !renderContext.Task->IsCameraCut;
// Prepare resolutions for passes
const int32 width = renderContext.Buffers->GetWidth();
const int32 height = renderContext.Buffers->GetHeight();
const int32 width = buffers->GetWidth();
const int32 height = buffers->GetHeight();
const int32 traceWidth = width / static_cast<int32>(settings.RayTracePassResolution);
const int32 traceHeight = height / static_cast<int32>(settings.RayTracePassResolution);
const int32 resolveWidth = width / static_cast<int32>(settings.RayTracePassResolution);
@@ -262,7 +262,7 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture
const double integral = round(time / scale) * scale;
data.TemporalTime = static_cast<float>(time - integral);
renderContext.Buffers->LastFrameTemporalSSR = Engine::FrameCount;
buffers->LastFrameTemporalSSR = Engine::FrameCount;
if (buffers->TemporalSSR == nullptr)
{
// Missing temporal buffer

View File

@@ -4,10 +4,10 @@
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Content/Content.h"
MultiScaler::MultiScaler()
: _psHalfDepth(nullptr)
{
}
PACK_STRUCT(struct Data {
Vector2 TexelSize;
Vector2 Padding;
});
String MultiScaler::ToString() const
{
@@ -21,6 +21,7 @@ bool MultiScaler::Init()
_psBlur5.CreatePipelineStates();
_psBlur9.CreatePipelineStates();
_psBlur13.CreatePipelineStates();
_psUpscale = GPUDevice::Instance->CreatePipelineState();
// Load asset
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/MultiScaler"));
@@ -64,6 +65,12 @@ bool MultiScaler::setupResources()
if (_psBlur13.Create(psDesc, shader, "PS_Blur13"))
return true;
}
if (!_psUpscale->IsValid())
{
psDesc.PS = shader->GetPS("PS_Upscale");
if (_psUpscale->Init(psDesc))
return true;
}
if (!_psHalfDepth->IsValid())
{
psDesc.PS = shader->GetPS("PS_HalfDepth");
@@ -84,6 +91,7 @@ void MultiScaler::Dispose()
// Cleanup
SAFE_DELETE_GPU_RESOURCE(_psHalfDepth);
SAFE_DELETE_GPU_RESOURCE(_psUpscale);
_psBlur5.Delete();
_psBlur9.Delete();
_psBlur13.Delete();
@@ -120,14 +128,14 @@ void MultiScaler::Filter(const FilterMode mode, GPUContext* context, const int32
ps = &_psBlur13;
break;
default:
CRASH;
CRASH;
return;
}
// Prepare
Data data;
data.TexelSize.X = 1.0f / width;
data.TexelSize.Y = 1.0f / height;
data.TexelSize.X = 1.0f / (float)width;
data.TexelSize.Y = 1.0f / (float)height;
auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
@@ -176,7 +184,7 @@ void MultiScaler::Filter(const FilterMode mode, GPUContext* context, const int32
ps = &_psBlur13;
break;
default:
CRASH;
CRASH;
return;
}
@@ -205,7 +213,7 @@ void MultiScaler::Filter(const FilterMode mode, GPUContext* context, const int32
context->ResetRenderTarget();
}
void MultiScaler::DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstHeight, GPUTextureView* src, GPUTextureView* dst)
void MultiScaler::DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstHeight, GPUTexture* src, GPUTextureView* dst)
{
PROFILE_GPU_CPU("Downscale Depth");
@@ -219,8 +227,8 @@ void MultiScaler::DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstH
// Prepare
Data data;
data.TexelSize.X = 2.0f / (float)dstWidth;
data.TexelSize.Y = 2.0f / (float)dstHeight;
data.TexelSize.X = 1.0f / (float)src->Width();
data.TexelSize.Y = 1.0f / (float)src->Height();
auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
@@ -236,3 +244,31 @@ void MultiScaler::DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstH
context->ResetRenderTarget();
context->UnBindCB(0);
}
void MultiScaler::Upscale(GPUContext* context, const Viewport& viewport, GPUTexture* src, GPUTextureView* dst)
{
PROFILE_GPU_CPU("Upscale");
context->SetViewportAndScissors(viewport);
context->SetRenderTarget(dst);
if (checkIfSkipPass())
{
context->Draw(src);
}
else
{
Data data;
data.TexelSize.X = 1.0f / (float)src->Width();
data.TexelSize.Y = 1.0f / (float)src->Height();
auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->BindSR(0, src);
context->SetState(_psUpscale);
context->DrawFullscreenTriangle();
context->UnBindCB(0);
}
context->ResetRenderTarget();
}

View File

@@ -12,23 +12,12 @@ class MultiScaler : public RendererPass<MultiScaler>
{
private:
PACK_STRUCT(struct Data {
Vector2 TexelSize;
Vector2 Padding;
});
AssetReference<Shader> _shader;
GPUPipelineState* _psHalfDepth;
GPUPipelineState* _psHalfDepth = nullptr;
GPUPipelineStatePermutationsPs<2> _psBlur5;
GPUPipelineStatePermutationsPs<2> _psBlur9;
GPUPipelineStatePermutationsPs<2> _psBlur13;
public:
/// <summary>
/// Init
/// </summary>
MultiScaler();
GPUPipelineState* _psUpscale = nullptr;
public:
@@ -84,7 +73,16 @@ public:
/// <param name="dstHeight">The height of the destination texture (in pixels).</param>
/// <param name="src">The source texture.</param>
/// <param name="dst">The destination texture.</param>
void DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstHeight, GPUTextureView* src, GPUTextureView* dst);
void DownscaleDepth(GPUContext* context, int32 dstWidth, int32 dstHeight, GPUTexture* src, GPUTextureView* dst);
/// <summary>
/// Upscales the texture.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="viewport">The viewport of the destination texture.</param>
/// <param name="src">The source texture.</param>
/// <param name="dst">The destination texture.</param>
void Upscale(GPUContext* context, const Viewport& viewport, GPUTexture* src, GPUTextureView* dst);
public:
@@ -96,6 +94,7 @@ public:
void OnShaderReloading(Asset* obj)
{
_psHalfDepth->ReleaseGPU();
_psUpscale->ReleaseGPU();
_psBlur5.Release();
_psBlur9.Release();
_psBlur13.Release();