Files
FlaxEngine/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp
2024-02-26 19:00:48 +01:00

165 lines
6.4 KiB
C++

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#if USE_EDITOR
#include "QuadOverdrawPass.h"
#include "Engine/Engine/Time.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/Assets/Material.h"
#include "Engine/Level/Actors/Decal.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderTargetPool.h"
#include "Engine/Renderer/RenderList.h"
void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer)
{
if (checkIfSkipPass())
{
context->Clear(lightBuffer, Color(0, Math::Sin(Time::Draw.UnscaledTime.GetTotalSeconds() * 5.0f) * 0.5f + 0.5f, 0, 1.0f));
return;
}
PROFILE_GPU_CPU("Quad Overdraw");
// Setup resources
const int32 width = renderContext.Buffers->GetWidth();
const int32 height = renderContext.Buffers->GetHeight();
auto tempDesc = GPUTextureDescription::New2D(width >> 1, height >> 1, PixelFormat::R32_UInt, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess);
auto lockTexture = RenderTargetPool::Get(tempDesc);
auto overdrawTexture = RenderTargetPool::Get(tempDesc);
auto liveCountTexture = RenderTargetPool::Get(tempDesc);
RENDER_TARGET_POOL_SET_NAME(lockTexture, "QuadOverdraw.Lock");
RENDER_TARGET_POOL_SET_NAME(overdrawTexture, "QuadOverdraw.Overdraw");
RENDER_TARGET_POOL_SET_NAME(liveCountTexture, "QuadOverdraw.LiveCount");
// Clear buffers
uint32 clearValueUINT[4] = { 0 };
clearValueUINT[0] = 0xffffffff;
context->ClearUA(lockTexture, clearValueUINT);
clearValueUINT[0] = 0x00000000;
context->ClearUA(overdrawTexture, clearValueUINT);
context->ClearUA(liveCountTexture, clearValueUINT);
context->ClearDepth(*renderContext.Buffers->DepthBuffer);
// Draw quad overdraw stats into UAVs
context->BindUA(0, lockTexture->View());
context->BindUA(1, overdrawTexture->View());
context->BindUA(2, liveCountTexture->View());
DrawCall drawCall;
drawCall.PerInstanceRandom = 1.0f;
MaterialBase::BindParameters bindParams(context, renderContext, drawCall);
bindParams.BindViewData();
renderContext.View.Pass = DrawPass::QuadOverdraw;
context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, (GPUTextureView*)nullptr);
renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBuffer);
auto boxModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/SimpleBox"));
auto defaultMaterial = GPUDevice::Instance->GetDefaultMaterial();
if (boxModel && boxModel->CanBeRendered() && defaultMaterial && defaultMaterial->IsReady())
{
// Draw decals
for (int32 i = 0; i < renderContext.List->Decals.Count(); i++)
{
const auto decal = renderContext.List->Decals[i];
ASSERT(decal && decal->Material);
Transform transform = decal->GetTransform();
transform.Scale *= decal->GetSize();
renderContext.View.GetWorldMatrix(transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.PerInstanceRandom = decal->GetPerInstanceRandom();
defaultMaterial->Bind(bindParams);
boxModel->Render(context);
}
}
renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBufferNoDecals);
auto skyModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Sphere"));
auto skyMaterial = Content::LoadAsyncInternal<Material>(TEXT("Engine/SkyboxMaterial"));
if (renderContext.List->Sky && skyModel && skyModel->CanBeRendered() && skyMaterial && skyMaterial->IsReady())
{
// Draw sky
auto box = skyModel->GetBox();
Matrix m1, m2;
Matrix::Scaling(renderContext.View.Far / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1);
Matrix::CreateWorld(renderContext.View.Position, Float3::Up, Float3::Backward, m2);
m1 *= m2;
drawCall.World = m1;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
skyMaterial->Bind(bindParams);
skyModel->Render(context);
}
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
GPUTextureView* readOnlyDepthBuffer = depthBuffer->View();
if (EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView))
readOnlyDepthBuffer = depthBuffer->ViewReadOnlyDepth();
context->ResetSR();
context->ResetRenderTarget();
context->SetRenderTarget(readOnlyDepthBuffer, (GPUTextureView*)nullptr);
renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::Forward);
renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::Distortion);
// TODO: draw volumetric particles
context->ResetRenderTarget();
context->ResetUA();
context->ResetSR();
// Convert stats into debug colors
context->BindSR(0, overdrawTexture->View());
context->SetRenderTarget(lightBuffer);
context->SetState(_ps);
context->DrawFullscreenTriangle();
// Free resources
RenderTargetPool::Release(liveCountTexture);
RenderTargetPool::Release(overdrawTexture);
RenderTargetPool::Release(lockTexture);
}
String QuadOverdrawPass::ToString() const
{
return TEXT("QuadOverdrawPass");
}
void QuadOverdrawPass::Dispose()
{
// Base
RendererPass::Dispose();
SAFE_DELETE_GPU_RESOURCE(_ps);
_shader = nullptr;
}
bool QuadOverdrawPass::setupResources()
{
if (GPUDevice::Instance->GetFeatureLevel() < FeatureLevel::SM5)
return true;
if (!_shader)
{
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/QuadOverdraw"));
if (!_shader)
return true;
#if COMPILE_WITH_DEV_ENV
_shader.Get()->OnReloading.Bind<QuadOverdrawPass, &QuadOverdrawPass::OnShaderReloading>(this);
#endif
}
if (!_shader->IsLoaded())
return true;
const auto shader = _shader->GetShader();
GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
if (!_ps)
_ps = GPUDevice::Instance->CreatePipelineState();
if (!_ps->IsValid())
{
psDesc.PS = shader->GetPS("PS");
if (_ps->Init(psDesc))
return true;
}
return false;
}
#endif