Add RenderingUpscaleLocation for customizing upscaler location in render pipeline

This commit is contained in:
Wojciech Figat
2022-12-13 11:51:31 +01:00
parent ee019510ca
commit c17477abff
6 changed files with 91 additions and 23 deletions

View File

@@ -113,6 +113,17 @@ namespace FlaxEditor.Windows
set => MainRenderTask.Instance.RenderingPercentage = value; set => MainRenderTask.Instance.RenderingPercentage = value;
} }
[NoSerialize, DefaultValue(RenderingUpscaleLocation.AfterAntiAliasingPass), VisibleIf(nameof(UpscaleLocation_Visible))]
[EditorOrder(1401), EditorDisplay("Quality")]
[Tooltip("The image resolution upscale location within rendering pipeline.")]
public RenderingUpscaleLocation UpscaleLocation
{
get => MainRenderTask.Instance.UpscaleLocation;
set => MainRenderTask.Instance.UpscaleLocation = value;
}
private bool UpscaleLocation_Visible => MainRenderTask.Instance.RenderingPercentage < 1.0f;
[NoSerialize, DefaultValue(1.0f), Limit(0, 1)] [NoSerialize, DefaultValue(1.0f), Limit(0, 1)]
[EditorOrder(1500), EditorDisplay("Quality"), Tooltip("The global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.")] [EditorOrder(1500), EditorDisplay("Quality"), Tooltip("The global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.")]
public float FoliageDensityScale public float FoliageDensityScale

View File

@@ -182,6 +182,22 @@ API_ENUM(Attributes="Flags") enum class ActorsSources
DECLARE_ENUM_OPERATORS(ActorsSources); DECLARE_ENUM_OPERATORS(ActorsSources);
/// <summary>
/// The Post Process effect rendering location within the rendering pipeline.
/// </summary>
API_ENUM() enum class RenderingUpscaleLocation
{
/// <summary>
/// The up-scaling happens directly to the output buffer (backbuffer) after post processing and anti-aliasing.
/// </summary>
AfterAntiAliasingPass = 0,
/// <summary>
/// The up-scaling happens before the post processing after scene rendering (after geometry, lighting, volumetrics, transparency and SSR/SSAO).
/// </summary>
BeforePostProcessingPass = 1,
};
/// <summary> /// <summary>
/// Render task which draws scene actors into the output buffer. /// Render task which draws scene actors into the output buffer.
/// </summary> /// </summary>
@@ -244,6 +260,11 @@ public:
/// </summary> /// </summary>
API_FIELD() float RenderingPercentage = 1.0f; API_FIELD() float RenderingPercentage = 1.0f;
/// <summary>
/// The image resolution upscale location within rendering pipeline. Unused if RenderingPercentage is 1.
/// </summary>
API_FIELD() RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasingPass;
public: public:
/// <summary> /// <summary>
/// The custom set of actors to render. /// The custom set of actors to render.

View File

@@ -205,11 +205,6 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext)
context->SetRenderTarget(lut->View()); context->SetRenderTarget(lut->View());
context->DrawFullscreenTriangle(); context->DrawFullscreenTriangle();
} }
// TODO: this could run in async during scene rendering or sth
const Viewport viewport = renderContext.Task->GetViewport();
context->SetViewportAndScissors(viewport);
context->UnBindSR(0); context->UnBindSR(0);
return lut; return lut;

View File

@@ -265,8 +265,8 @@ void MotionBlurPass::Render(RenderContext& renderContext, GPUTexture*& input, GP
ASSERT(motionVectors); ASSERT(motionVectors);
auto context = GPUDevice::Instance->GetMainContext(); auto context = GPUDevice::Instance->GetMainContext();
MotionBlurSettings& settings = renderContext.List->Settings.MotionBlur; MotionBlurSettings& settings = renderContext.List->Settings.MotionBlur;
const int32 screenWidth = renderContext.Buffers->GetWidth(); const int32 screenWidth = input->Width();
const int32 screenHeight = renderContext.Buffers->GetHeight(); const int32 screenHeight = input->Height();
const int32 motionVectorsWidth = screenWidth / static_cast<int32>(settings.MotionVectorsResolution); const int32 motionVectorsWidth = screenWidth / static_cast<int32>(settings.MotionVectorsResolution);
const int32 motionVectorsHeight = screenHeight / static_cast<int32>(settings.MotionVectorsResolution); const int32 motionVectorsHeight = screenHeight / static_cast<int32>(settings.MotionVectorsResolution);
if ((renderContext.View.Flags & ViewFlags::MotionBlur) == 0 || if ((renderContext.View.Flags & ViewFlags::MotionBlur) == 0 ||

View File

@@ -482,8 +482,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input,
context->BindSR(7, colorGradingLutView); context->BindSR(7, colorGradingLutView);
// Composite final frame during single pass (done in full resolution) // Composite final frame during single pass (done in full resolution)
auto viewport = renderContext.Task->GetViewport(); context->SetViewportAndScissors((float)output->Width(), (float)output->Height());
context->SetViewportAndScissors(viewport);
context->SetRenderTarget(*output); context->SetRenderTarget(*output);
context->SetState(_psComposite.Get(compositePermutationIndex)); context->SetState(_psComposite.Get(compositePermutationIndex));
context->DrawFullscreenTriangle(); context->DrawFullscreenTriangle();

View File

@@ -122,12 +122,10 @@ void RendererService::Dispose()
SAFE_DELETE_GPU_RESOURCE(IMaterial::BindParameters::PerViewConstants); SAFE_DELETE_GPU_RESOURCE(IMaterial::BindParameters::PerViewConstants);
} }
void RenderAntiAliasingPass(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output) void RenderAntiAliasingPass(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output, const Viewport& outputViewport)
{ {
auto context = GPUDevice::Instance->GetMainContext(); auto context = GPUDevice::Instance->GetMainContext();
auto screenSize = renderContext.View.ScreenSize; context->SetViewportAndScissors(outputViewport);
context->SetViewportAndScissors(screenSize.X, screenSize.Y);
const auto aaMode = renderContext.List->Settings.AntiAliasing.Mode; const auto aaMode = renderContext.List->Settings.AntiAliasing.Mode;
if (aaMode == AntialiasingMode::FastApproximateAntialiasing) if (aaMode == AntialiasingMode::FastApproximateAntialiasing)
{ {
@@ -554,6 +552,27 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
Swap(frameBuffer, tempBuffer); Swap(frameBuffer, tempBuffer);
} }
// Upscaling after scene rendering but before post processing
bool useUpscaling = task->RenderingPercentage < 1.0f;
const Viewport outputViewport = task->GetOutputViewport();
if (useUpscaling && task->UpscaleLocation == RenderingUpscaleLocation::BeforePostProcessingPass)
{
useUpscaling = false;
RenderTargetPool::Release(tempBuffer);
tempDesc.Width = (int32)outputViewport.Width;
tempDesc.Height = (int32)outputViewport.Height;
tempBuffer = RenderTargetPool::Get(tempDesc);
context->ResetSR();
if (renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::CustomUpscale))
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::CustomUpscale, frameBuffer, tempBuffer);
else
MultiScaler::Instance()->Upscale(context, outputViewport, frameBuffer, tempBuffer->View());
if (tempBuffer->Width() == tempDesc.Width)
Swap(frameBuffer, tempBuffer);
RenderTargetPool::Release(tempBuffer);
tempBuffer = RenderTargetPool::Get(tempDesc);
}
// Depth of Field // Depth of Field
auto dofTemporary = DepthOfFieldPass::Instance()->Render(renderContext, frameBuffer); auto dofTemporary = DepthOfFieldPass::Instance()->Render(renderContext, frameBuffer);
frameBuffer = dofTemporary ? dofTemporary : frameBuffer; frameBuffer = dofTemporary ? dofTemporary : frameBuffer;
@@ -591,7 +610,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
{ {
context->ResetRenderTarget(); context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView()); context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors(task->GetOutputViewport()); context->SetViewportAndScissors(outputViewport);
MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View()); MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
RenderTargetPool::Release(tempBuffer); RenderTargetPool::Release(tempBuffer);
RenderTargetPool::Release(frameBuffer); RenderTargetPool::Release(frameBuffer);
@@ -599,35 +618,58 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
} }
// Anti Aliasing // Anti Aliasing
if (!renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, MaterialPostFxLocation::AfterAntiAliasingPass) && Math::IsOne(task->RenderingPercentage)) GPUTextureView* outputView = task->GetOutputView();
if (!renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, MaterialPostFxLocation::AfterAntiAliasingPass) && !useUpscaling)
{ {
// AA -> Back Buffer // AA -> Back Buffer
RenderAntiAliasingPass(renderContext, frameBuffer, task->GetOutputView()); RenderAntiAliasingPass(renderContext, frameBuffer, outputView, outputViewport);
} }
else else
{ {
// AA -> PostFx // AA -> PostFx
RenderAntiAliasingPass(renderContext, frameBuffer, *tempBuffer); RenderAntiAliasingPass(renderContext, frameBuffer, *tempBuffer, Viewport(Float2(renderContext.View.ScreenSize)));
context->ResetRenderTarget(); context->ResetRenderTarget();
Swap(frameBuffer, tempBuffer); Swap(frameBuffer, tempBuffer);
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer); renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer);
renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer); renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer);
// PostFx -> (up-scaling) -> Back Buffer // PostFx -> (up-scaling) -> Back Buffer
if (task->RenderingPercentage >= 1.0f) if (!useUpscaling)
{ {
PROFILE_GPU("Copy frame"); PROFILE_GPU("Copy frame");
context->SetRenderTarget(task->GetOutputView()); context->SetRenderTarget(outputView);
context->SetViewportAndScissors(task->GetOutputViewport()); context->SetViewportAndScissors(outputViewport);
context->Draw(frameBuffer); context->Draw(frameBuffer);
} }
else if (renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::CustomUpscale, MaterialPostFxLocation::MAX)) else if (renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::CustomUpscale))
{ {
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::CustomUpscale, frameBuffer, frameBuffer); if (outputView->GetParent()->Is<GPUTexture>())
{
// Upscale directly to the output texture
auto outputTexture = (GPUTexture*)outputView->GetParent();
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::CustomUpscale, frameBuffer, outputTexture);
if (frameBuffer == (GPUTexture*)outputView->GetParent())
Swap(frameBuffer, outputTexture);
}
else
{
// Use temporary buffer for upscaled frame if GetOutputView is owned by GPUSwapChain
RenderTargetPool::Release(tempBuffer);
tempDesc.Width = (int32)outputViewport.Width;
tempDesc.Height = (int32)outputViewport.Height;
tempBuffer = RenderTargetPool::Get(tempDesc);
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::CustomUpscale, frameBuffer, tempBuffer);
{
PROFILE_GPU("Copy frame");
context->SetRenderTarget(outputView);
context->SetViewportAndScissors(outputViewport);
context->Draw(frameBuffer);
}
}
} }
else else
{ {
MultiScaler::Instance()->Upscale(context, task->GetOutputViewport(), frameBuffer, task->GetOutputView()); MultiScaler::Instance()->Upscale(context, outputViewport, frameBuffer, outputView);
} }
} }