Optimize ProbesRenderer to use time-slicing for cubemap faces rendering and filtering
This commit is contained in:
@@ -106,6 +106,8 @@ private:
|
|||||||
Array<ProbeEntry> _probesToBake;
|
Array<ProbeEntry> _probesToBake;
|
||||||
|
|
||||||
ProbeEntry _current;
|
ProbeEntry _current;
|
||||||
|
int32 _workStep;
|
||||||
|
float _customCullingNear;
|
||||||
|
|
||||||
AssetReference<Shader> _shader;
|
AssetReference<Shader> _shader;
|
||||||
GPUPipelineState* _psFilterFace = nullptr;
|
GPUPipelineState* _psFilterFace = nullptr;
|
||||||
@@ -134,6 +136,7 @@ ProbesRendererService ProbesRendererServiceInstance;
|
|||||||
|
|
||||||
TimeSpan ProbesRenderer::UpdateDelay(0, 0, 0, 0, 100);
|
TimeSpan ProbesRenderer::UpdateDelay(0, 0, 0, 0, 100);
|
||||||
TimeSpan ProbesRenderer::ReleaseTimeout(0, 0, 0, 30);
|
TimeSpan ProbesRenderer::ReleaseTimeout(0, 0, 0, 30);
|
||||||
|
int32 ProbesRenderer::MaxWorkPerFrame = 1;
|
||||||
Delegate<Actor*> ProbesRenderer::OnRegisterBake;
|
Delegate<Actor*> ProbesRenderer::OnRegisterBake;
|
||||||
Delegate<Actor*> ProbesRenderer::OnFinishBake;
|
Delegate<Actor*> ProbesRenderer::OnFinishBake;
|
||||||
|
|
||||||
@@ -293,6 +296,7 @@ void ProbesRendererService::Update()
|
|||||||
|
|
||||||
// Clear flag
|
// Clear flag
|
||||||
_updateFrameNumber = 0;
|
_updateFrameNumber = 0;
|
||||||
|
_workStep = 0;
|
||||||
_current.Type = ProbeEntry::Types::Invalid;
|
_current.Type = ProbeEntry::Types::Invalid;
|
||||||
}
|
}
|
||||||
else if (_current.Type == ProbeEntry::Types::Invalid && timeSinceUpdate > ProbesRenderer::UpdateDelay)
|
else if (_current.Type == ProbeEntry::Types::Invalid && timeSinceUpdate > ProbesRenderer::UpdateDelay)
|
||||||
@@ -321,6 +325,7 @@ void ProbesRendererService::Update()
|
|||||||
_probesToBake.RemoveAtKeepOrder(firstValidEntryIndex);
|
_probesToBake.RemoveAtKeepOrder(firstValidEntryIndex);
|
||||||
_task->Enabled = true;
|
_task->Enabled = true;
|
||||||
_updateFrameNumber = 0;
|
_updateFrameNumber = 0;
|
||||||
|
_workStep = 0;
|
||||||
_lastProbeUpdate = timeNow;
|
_lastProbeUpdate = timeNow;
|
||||||
}
|
}
|
||||||
// Check if need to release data
|
// Check if need to release data
|
||||||
@@ -408,9 +413,11 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
PROFILE_GPU("Render Probe");
|
PROFILE_GPU("Render Probe");
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
float customCullingNear = -1;
|
|
||||||
const int32 probeResolution = _current.GetResolution();
|
const int32 probeResolution = _current.GetResolution();
|
||||||
const PixelFormat probeFormat = _current.GetFormat();
|
const PixelFormat probeFormat = _current.GetFormat();
|
||||||
|
if (_workStep == 0)
|
||||||
|
{
|
||||||
|
_customCullingNear = -1;
|
||||||
if (_current.Type == ProbeEntry::Types::EnvProbe)
|
if (_current.Type == ProbeEntry::Types::EnvProbe)
|
||||||
{
|
{
|
||||||
auto envProbe = (EnvironmentProbe*)_current.Actor.Get();
|
auto envProbe = (EnvironmentProbe*)_current.Actor.Get();
|
||||||
@@ -434,13 +441,12 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
Vector3 position = skyLight->GetPosition();
|
Vector3 position = skyLight->GetPosition();
|
||||||
float nearPlane = 10.0f;
|
float nearPlane = 10.0f;
|
||||||
float farPlane = Math::Max(nearPlane + 1000.0f, skyLight->SkyDistanceThreshold * 2.0f);
|
float farPlane = Math::Max(nearPlane + 1000.0f, skyLight->SkyDistanceThreshold * 2.0f);
|
||||||
customCullingNear = skyLight->SkyDistanceThreshold;
|
_customCullingNear = skyLight->SkyDistanceThreshold;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
LargeWorlds::UpdateOrigin(_task->View.Origin, position);
|
LargeWorlds::UpdateOrigin(_task->View.Origin, position);
|
||||||
_task->View.SetUpCube(nearPlane, farPlane, position - _task->View.Origin);
|
_task->View.SetUpCube(nearPlane, farPlane, position - _task->View.Origin);
|
||||||
}
|
}
|
||||||
_task->CameraCut();
|
|
||||||
|
|
||||||
// Resize buffers
|
// Resize buffers
|
||||||
bool resizeFailed = _output->Resize(probeResolution, probeResolution, probeFormat);
|
bool resizeFailed = _output->Resize(probeResolution, probeResolution, probeFormat);
|
||||||
@@ -449,31 +455,34 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
resizeFailed |= _task->Resize(probeResolution, probeResolution);
|
resizeFailed |= _task->Resize(probeResolution, probeResolution);
|
||||||
if (resizeFailed)
|
if (resizeFailed)
|
||||||
LOG(Error, "Failed to resize probe");
|
LOG(Error, "Failed to resize probe");
|
||||||
|
}
|
||||||
|
|
||||||
// Disable actor during baking (it cannot influence own results)
|
// Disable actor during baking (it cannot influence own results)
|
||||||
const bool isActorActive = _current.Actor->GetIsActive();
|
const bool isActorActive = _current.Actor->GetIsActive();
|
||||||
_current.Actor->SetIsActive(false);
|
_current.Actor->SetIsActive(false);
|
||||||
|
|
||||||
// Lower quality when rendering probes in-game to gain performance
|
// Lower quality when rendering probes in-game to gain performance
|
||||||
_task->View.MaxShadowsQuality = Engine::IsPlayMode() ? Quality::Low : Quality::Ultra;
|
_task->View.MaxShadowsQuality = Engine::IsPlayMode() || probeResolution <= 128 ? Quality::Low : Quality::Ultra;
|
||||||
|
|
||||||
// Render scene for all faces
|
// Render scene for all faces
|
||||||
for (int32 faceIndex = 0; faceIndex < 6; faceIndex++)
|
int32 workLeft = ProbesRenderer::MaxWorkPerFrame;
|
||||||
|
const int32 lastFace = Math::Min(_workStep + workLeft, 6);
|
||||||
|
for (int32 faceIndex = _workStep; faceIndex < lastFace; faceIndex++)
|
||||||
{
|
{
|
||||||
|
_task->CameraCut();
|
||||||
_task->View.SetFace(faceIndex);
|
_task->View.SetFace(faceIndex);
|
||||||
|
|
||||||
// Handle custom frustum for the culling (used to skip objects near the camera)
|
// Handle custom frustum for the culling (used to skip objects near the camera)
|
||||||
if (customCullingNear > 0)
|
if (_customCullingNear > 0)
|
||||||
{
|
{
|
||||||
Matrix p;
|
Matrix p;
|
||||||
Matrix::PerspectiveFov(PI_OVER_2, 1.0f, customCullingNear, _task->View.Far, p);
|
Matrix::PerspectiveFov(PI_OVER_2, 1.0f, _customCullingNear, _task->View.Far, p);
|
||||||
_task->View.CullingFrustum.SetMatrix(_task->View.View, p);
|
_task->View.CullingFrustum.SetMatrix(_task->View.View, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render frame
|
// Render frame
|
||||||
Renderer::Render(_task);
|
Renderer::Render(_task);
|
||||||
context->ClearState();
|
context->ClearState();
|
||||||
_task->CameraCut();
|
|
||||||
|
|
||||||
// Copy frame to cube face
|
// Copy frame to cube face
|
||||||
{
|
{
|
||||||
@@ -483,12 +492,17 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
context->Draw(_output->View());
|
context->Draw(_output->View());
|
||||||
context->ResetRenderTarget();
|
context->ResetRenderTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to the next face
|
||||||
|
_workStep++;
|
||||||
|
workLeft--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable actor back
|
// Enable actor back
|
||||||
_current.Actor->SetIsActive(isActorActive);
|
_current.Actor->SetIsActive(isActorActive);
|
||||||
|
|
||||||
// Filter all lower mip levels
|
// Filter all lower mip levels
|
||||||
|
if (workLeft > 0)
|
||||||
{
|
{
|
||||||
PROFILE_GPU("Filtering");
|
PROFILE_GPU("Filtering");
|
||||||
Data data;
|
Data data;
|
||||||
@@ -520,11 +534,18 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
context->Draw(_tmpFace->View(0, mipIndex));
|
context->Draw(_tmpFace->View(0, mipIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End
|
||||||
|
workLeft--;
|
||||||
|
_workStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
context->ClearState();
|
context->ClearState();
|
||||||
|
|
||||||
|
if (_workStep < 7)
|
||||||
|
return; // Continue rendering next frame
|
||||||
|
|
||||||
// Mark as rendered
|
// Mark as rendered
|
||||||
_updateFrameNumber = Engine::FrameCount;
|
_updateFrameNumber = Engine::FrameCount;
|
||||||
_task->Enabled = false;
|
_task->Enabled = false;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static TimeSpan ReleaseTimeout;
|
static TimeSpan ReleaseTimeout;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum amount of cubemap faces or filtering passes that can be performed per-frame (in total). Set it to 7 to perform whole cubemap capture within a single frame, lower values spread the work across multiple frames.
|
||||||
|
/// </summary>
|
||||||
|
static int32 MaxWorkPerFrame;
|
||||||
|
|
||||||
static Delegate<Actor*> OnRegisterBake;
|
static Delegate<Actor*> OnRegisterBake;
|
||||||
|
|
||||||
static Delegate<Actor*> OnFinishBake;
|
static Delegate<Actor*> OnFinishBake;
|
||||||
|
|||||||
Reference in New Issue
Block a user