Files
WickedEngine/WickedEngine/DeferredRenderableComponent.cpp
T
2017-04-07 02:01:04 +02:00

391 lines
13 KiB
C++

#include "DeferredRenderableComponent.h"
#include "wiRenderer.h"
#include "wiImage.h"
#include "wiImageEffects.h"
#include "wiHelper.h"
#include "wiTextureHelper.h"
#include "wiSprite.h"
#include "ResourceMapping.h"
#include "wiProfiler.h"
using namespace wiGraphicsTypes;
DeferredRenderableComponent::DeferredRenderableComponent()
{
Renderable3DComponent::setProperties();
setSSREnabled(true);
setSSAOEnabled(true);
setHairParticleAlphaCompositionEnabled(false);
setPreferredThreadingCount(0);
}
DeferredRenderableComponent::~DeferredRenderableComponent()
{
}
static wiRenderTarget rtGBuffer, rtDeferred, rtLight, rtSSS[2];
void DeferredRenderableComponent::ResizeBuffers()
{
Renderable3DComponent::ResizeBuffers();
FORMAT defaultTextureFormat = GraphicsDevice::GetBackBufferFormat();
// Protect against multiple buffer resizes when there is no change!
static UINT lastBufferResWidth = 0, lastBufferResHeight = 0, lastBufferMSAA = 0;
static FORMAT lastBufferFormat = FORMAT_UNKNOWN;
if (lastBufferResWidth == (UINT)wiRenderer::GetDevice()->GetScreenWidth() &&
lastBufferResHeight == (UINT)wiRenderer::GetDevice()->GetScreenHeight() &&
lastBufferMSAA == getMSAASampleCount() &&
lastBufferFormat == defaultTextureFormat)
{
return;
}
else
{
lastBufferResWidth = (UINT)wiRenderer::GetDevice()->GetScreenWidth();
lastBufferResHeight = (UINT)wiRenderer::GetDevice()->GetScreenHeight();
lastBufferMSAA = getMSAASampleCount();
lastBufferFormat = defaultTextureFormat;
}
rtGBuffer.Initialize(
wiRenderer::GetDevice()->GetScreenWidth(), wiRenderer::GetDevice()->GetScreenHeight()
, true, FORMAT_R8G8B8A8_UNORM);
rtGBuffer.Add(FORMAT_R16G16B16A16_FLOAT);
rtGBuffer.Add(FORMAT_R8G8B8A8_UNORM);
rtGBuffer.Add(FORMAT_R8G8B8A8_UNORM);
// NOTE: Light buffer precision seems OK when using FORMAT_R11G11B10_FLOAT format
// But the environmental light now also writes the AO to ALPHA so it has been changed to FORMAT_R16G16B16A16_FLOAT
rtDeferred.Initialize(
wiRenderer::GetDevice()->GetScreenWidth(), wiRenderer::GetDevice()->GetScreenHeight()
, false, FORMAT_R16G16B16A16_FLOAT);
rtLight.Initialize(
wiRenderer::GetDevice()->GetScreenWidth(), wiRenderer::GetDevice()->GetScreenHeight()
, false, FORMAT_R16G16B16A16_FLOAT); // diffuse
rtLight.Add(FORMAT_R16G16B16A16_FLOAT); // specular
rtSSS[0].Initialize(
wiRenderer::GetDevice()->GetScreenWidth(), wiRenderer::GetDevice()->GetScreenHeight()
, false, FORMAT_R16G16B16A16_FLOAT);
rtSSS[1].Initialize(
wiRenderer::GetDevice()->GetScreenWidth(), wiRenderer::GetDevice()->GetScreenHeight()
, false, FORMAT_R16G16B16A16_FLOAT);
}
void DeferredRenderableComponent::Initialize()
{
ResizeBuffers();
Renderable3DComponent::Initialize();
}
void DeferredRenderableComponent::Load()
{
Renderable3DComponent::Load();
}
void DeferredRenderableComponent::Start()
{
Renderable3DComponent::Start();
}
void DeferredRenderableComponent::Render()
{
if (getThreadingCount() > 1)
{
for (auto workerThread : workerThreads)
{
workerThread->wakeup();
}
for (auto workerThread : workerThreads)
{
workerThread->wait();
}
wiRenderer::GetDevice()->ExecuteDeferredContexts();
}
else
{
RenderFrameSetUp();
RenderShadows();
RenderReflections();
RenderScene();
RenderSecondaryScene(rtGBuffer, GetFinalRT());
RenderComposition(GetFinalRT(), rtGBuffer);
}
Renderable2DComponent::Render();
}
wiRenderTarget DeferredRenderableComponent::rtGBuffer, DeferredRenderableComponent::rtDeferred, DeferredRenderableComponent::rtLight, DeferredRenderableComponent::rtSSS[2];
void DeferredRenderableComponent::RenderScene(GRAPHICSTHREAD threadID)
{
wiProfiler::GetInstance().BeginRange("Opaque Scene", wiProfiler::DOMAIN_GPU, threadID);
wiRenderer::UpdateCameraCB(wiRenderer::getCamera(), threadID);
wiImageEffects fx((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight());
rtGBuffer.Activate(threadID, 0, 0, 0, 0);
{
wiRenderer::DrawWorld(wiRenderer::getCamera(), getTessellationEnabled(), threadID, SHADERTYPE_DEFERRED, rtReflection.GetTexture(), true, true);
}
rtLinearDepth.Activate(threadID); {
fx.blendFlag = BLENDMODE_OPAQUE;
fx.sampleFlag = SAMPLEMODE_CLAMP;
fx.quality = QUALITY_NEAREST;
fx.process.setLinDepth(true);
wiImage::Draw(rtGBuffer.depth->GetTexture(), fx, threadID);
fx.process.clear();
}
rtLinearDepth.Deactivate(threadID);
dtDepthCopy.CopyFrom(*rtGBuffer.depth, threadID);
wiRenderer::GetDevice()->UnBindResources(TEXSLOT_ONDEMAND0, TEXSLOT_ONDEMAND_COUNT, threadID);
wiRenderer::UpdateDepthBuffer(dtDepthCopy.GetTexture(), rtLinearDepth.GetTexture(), threadID);
if (getStereogramEnabled())
{
// We don't need the following for stereograms...
return;
}
rtGBuffer.Set(threadID); {
wiRenderer::DrawDecals(wiRenderer::getCamera(), threadID);
}
rtGBuffer.Deactivate(threadID);
wiRenderer::UpdateGBuffer(rtGBuffer.GetTexture(0), rtGBuffer.GetTexture(1), rtGBuffer.GetTexture(2), rtGBuffer.GetTexture(3), nullptr, threadID);
rtLight.Activate(threadID, rtGBuffer.depth); {
wiRenderer::DrawLights(wiRenderer::getCamera(), threadID);
}
if (getSSAOEnabled()){
fx.stencilRef = STENCILREF_DEFAULT;
fx.stencilComp = COMPARISON_LESS;
rtSSAO[0].Activate(threadID); {
fx.process.setSSAO(true);
fx.setMaskMap(wiTextureHelper::getInstance()->getRandom64x64());
fx.quality = QUALITY_BILINEAR;
fx.sampleFlag = SAMPLEMODE_MIRROR;
wiImage::Draw(nullptr, fx, threadID);
fx.process.clear();
}
rtSSAO[1].Activate(threadID); {
fx.blur = getSSAOBlur();
fx.blurDir = 0;
fx.blendFlag = BLENDMODE_OPAQUE;
wiImage::Draw(rtSSAO[0].GetTexture(), fx, threadID);
}
rtSSAO[2].Activate(threadID); {
fx.blur = getSSAOBlur();
fx.blurDir = 1;
fx.blendFlag = BLENDMODE_OPAQUE;
wiImage::Draw(rtSSAO[1].GetTexture(), fx, threadID);
fx.blur = 0;
}
fx.stencilRef = 0;
fx.stencilComp = 0;
}
if (getSSSEnabled())
{
fx.stencilRef = STENCILREF_SKIN;
fx.stencilComp = COMPARISON_LESS;
fx.quality = QUALITY_BILINEAR;
fx.sampleFlag = SAMPLEMODE_CLAMP;
static int sssPassCount = 6;
for (int i = 0; i < sssPassCount; ++i)
{
wiRenderer::GetDevice()->UnBindResources(TEXSLOT_ONDEMAND0, 1, threadID);
rtSSS[i % 2].Activate(threadID, rtGBuffer.depth, 0, 0, 0, 0);
XMFLOAT2 dir = XMFLOAT2(0, 0);
static float stren = 0.018f;
if (i % 2 == 0)
{
dir.x = stren*((float)wiRenderer::GetDevice()->GetScreenHeight() / (float)wiRenderer::GetDevice()->GetScreenWidth());
}
else
{
dir.y = stren;
}
fx.process.setSSSS(dir);
if (i == 0)
{
wiImage::Draw(rtLight.GetTexture(0), fx, threadID);
}
else
{
wiImage::Draw(rtSSS[(i + 1) % 2].GetTexture(), fx, threadID);
}
}
fx.process.clear();
wiRenderer::GetDevice()->UnBindResources(TEXSLOT_ONDEMAND0, 1, threadID);
rtSSS[0].Activate(threadID, rtGBuffer.depth); {
fx.setMaskMap(nullptr);
fx.quality = QUALITY_NEAREST;
fx.sampleFlag = SAMPLEMODE_CLAMP;
fx.blendFlag = BLENDMODE_OPAQUE;
fx.stencilRef = 0;
fx.stencilComp = 0;
wiImage::Draw(rtLight.GetTexture(0), fx, threadID);
fx.stencilRef = STENCILREF_SKIN;
fx.stencilComp = COMPARISON_LESS;
wiImage::Draw(rtSSS[1].GetTexture(), fx, threadID);
}
fx.stencilRef = 0;
fx.stencilComp = 0;
}
rtDeferred.Activate(threadID, rtGBuffer.depth); {
wiImage::DrawDeferred((getSSSEnabled() ? rtSSS[0].GetTexture(0) : rtLight.GetTexture(0)), rtLight.GetTexture(1)
, getSSAOEnabled() ? rtSSAO.back().GetTexture() : wiTextureHelper::getInstance()->getWhite()
, threadID, STENCILREF_DEFAULT);
wiRenderer::DrawSky(threadID);
}
if (getSSREnabled()){
rtSSR.Activate(threadID); {
wiRenderer::GetDevice()->GenerateMips(rtDeferred.GetTexture(0), threadID);
fx.process.setSSR(true);
fx.setMaskMap(nullptr);
wiImage::Draw(rtDeferred.GetTexture(), fx, threadID);
fx.process.clear();
}
}
wiProfiler::GetInstance().EndRange(); // Opaque Scene
}
wiRenderTarget& DeferredRenderableComponent::GetFinalRT()
{
if (getSSREnabled())
return rtSSR;
else
return rtDeferred;
}
void DeferredRenderableComponent::setPreferredThreadingCount(unsigned short value)
{
Renderable3DComponent::setPreferredThreadingCount(value);
if (!wiRenderer::GetDevice()->CheckCapability(GraphicsDevice::GRAPHICSDEVICE_CAPABILITY_MULTITHREADED_RENDERING))
{
if (value > 1)
wiHelper::messageBox("Multithreaded rendering not supported by your hardware! Falling back to single threading!", "Caution");
return;
}
switch (value){
case 0:
case 1:
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_IMMEDIATE);
break;
case 2:
workerThreads.push_back(new wiTaskThread([&]
{
RenderFrameSetUp(GRAPHICSTHREAD_REFLECTIONS);
RenderReflections(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
}));
workerThreads.push_back(new wiTaskThread([&]
{
RenderShadows(GRAPHICSTHREAD_SCENE);
RenderScene(GRAPHICSTHREAD_SCENE);
RenderSecondaryScene(rtGBuffer, GetFinalRT(), GRAPHICSTHREAD_SCENE);
RenderComposition(GetFinalRT(), rtGBuffer, GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
}));
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->ExecuteDeferredContexts();
break;
case 3:
workerThreads.push_back(new wiTaskThread([&]
{
RenderFrameSetUp(GRAPHICSTHREAD_REFLECTIONS);
RenderReflections(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
}));
workerThreads.push_back(new wiTaskThread([&]
{
RenderShadows(GRAPHICSTHREAD_SCENE);
RenderScene(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
}));
workerThreads.push_back(new wiTaskThread([&]
{
wiRenderer::UpdateDepthBuffer(dtDepthCopy.GetTexture(), rtLinearDepth.GetTexture(), GRAPHICSTHREAD_MISC1);
wiRenderer::UpdateGBuffer(rtGBuffer.GetTexture(0), rtGBuffer.GetTexture(1), rtGBuffer.GetTexture(2), nullptr, nullptr, GRAPHICSTHREAD_MISC1);
RenderSecondaryScene(rtGBuffer, GetFinalRT(), GRAPHICSTHREAD_MISC1);
RenderComposition(GetFinalRT(), rtGBuffer, GRAPHICSTHREAD_MISC1);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC1);
}));
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_MISC1);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC1);
wiRenderer::GetDevice()->ExecuteDeferredContexts();
break;
case 4:
default:
workerThreads.push_back(new wiTaskThread([&]
{
RenderFrameSetUp(GRAPHICSTHREAD_REFLECTIONS);
RenderReflections(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
}));
workerThreads.push_back(new wiTaskThread([&]
{
RenderShadows(GRAPHICSTHREAD_SCENE);
RenderScene(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
}));
workerThreads.push_back(new wiTaskThread([&]
{
wiRenderer::UpdateDepthBuffer(dtDepthCopy.GetTexture(), rtLinearDepth.GetTexture(), GRAPHICSTHREAD_MISC1);
wiRenderer::UpdateGBuffer(rtGBuffer.GetTexture(0), rtGBuffer.GetTexture(1), rtGBuffer.GetTexture(2), nullptr, nullptr, GRAPHICSTHREAD_MISC1);
RenderSecondaryScene(rtGBuffer, GetFinalRT(), GRAPHICSTHREAD_MISC1);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC1);
}));
workerThreads.push_back(new wiTaskThread([&]
{
wiRenderer::UpdateDepthBuffer(dtDepthCopy.GetTexture(), rtLinearDepth.GetTexture(), GRAPHICSTHREAD_MISC2);
wiRenderer::UpdateGBuffer(rtGBuffer.GetTexture(0), rtGBuffer.GetTexture(1), rtGBuffer.GetTexture(2), nullptr, nullptr, GRAPHICSTHREAD_MISC2);
RenderComposition(GetFinalRT(), rtGBuffer, GRAPHICSTHREAD_MISC2);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC2);
}));
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_REFLECTIONS);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_SCENE);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_SCENE);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_MISC1);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC1);
wiRenderer::RebindPersistentState(GRAPHICSTHREAD_MISC2);
wiRenderer::GetDevice()->FinishCommandList(GRAPHICSTHREAD_MISC2);
wiRenderer::GetDevice()->ExecuteDeferredContexts();
break;
};
}