Files
GTASource/game/renderer/rendertargets.cpp
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

3864 lines
141 KiB
C++

//
// renderer/rendertargets.cpp
//
// Copyright (C) 1999-2014 Rockstar Games. All Rights Reserved.
//
#include "rendertargets.h"
// Rage headers
#include "bank/bank.h"
#include "bank/toggle.h"
#include "bank/combo.h"
#include "grcore/allocscope.h"
#include "grcore/gfxcontext.h"
#include "grcore/texture.h"
#include "grcore/texturegcm.h"
#include "grcore/texturexenon.h"
#include "grcore/wrapper_gcm.h"
#include "grcore/quads.h"
#include "gpuptfx/ptxgpubase.h"
#include "system/param.h"
#include "system/memory.h"
#if __XENON
#include "system/xtl.h"
#include "system/xgraphics.h"
#elif __PPU
#include "diag/tracker.h"
#endif // __PPU
// Framework headers
#include "grcore/debugdraw.h"
#if __WIN32PC || RSG_DURANGO
#include "grcore/texturepc.h"
#endif // __WIN32PC || RSG_DURANGO
#if __D3D11
#include "grcore/texture_d3d11.h"
#include "grcore/texturefactory_d3d11.h"
#include "grcore/rendertarget_d3d11.h"
#endif
#if RSG_ORBIS
#include "grcore/rendertarget_gnm.h"
#include "grcore/texturefactory_gnm.h"
#endif
// Game headers
#include "camera/viewports/ViewportManager.h"
#include "debug/debug.h"
#include "renderer/deferred/gbuffer.h"
#include "renderer/Mirrors.h"
#include "renderer/RenderPhases/RenderPhaseEntitySelect.h"
#include "renderer/RenderPhases/RenderPhaseMirrorReflection.h"
#include "renderer/RenderPhases/RenderPhaseWaterReflection.h"
#include "renderer/sprite2d.h"
#include "renderer/shadows/shadows.h"
#include "renderer/SSAO_shared.h"
#include "renderer/Water.h"
#include "shaders/shaderlib.h"
#include "../shader_source/Lighting/Shadows/cascadeshadows_common.fxh"
#include "control/replay/ReplaySupportClasses.h"
RENDER_OPTIMISATIONS()
#if DEVICE_EQAA
// Create full EQAA coverage for the back buffer and any other RT that is used with the depth buffer
// required to avoid DX runtime assertions on depth MSAA vs color MSAA mismatches
static bool UseFullBackbufferCoverage(const grcDevice::MSAAMode&)
{
//return !RSG_ORBIS; // doesn't work correctly somehow
return false;
}
#endif //DEVICE_EQAA
#if !__FINAL && (__D3D11 || RSG_ORBIS)
XPARAM(DX11Use8BitTargets);
#endif // !__FINAL && (__D3D11 || RSG_ORBIS)
PARAM(gamewidth,"Set width of game's backbuffer/gbuffer)");
PARAM(gameheight,"Set height of game's backbuffer/gbuffer");
PARAM(highColorPrecision, "Switch RGB11F to RGBAF16 format for PC");
#define KB64 (64 * 1024)
u16 CRenderTargets::ms_RenderTargetMemPoolArray[RTMEMPOOL_SIZE];
DECLARE_MTR_THREAD bool CRenderTargets::ms_RenderTargetActive = false;
bool CRenderTargets::ms_DepthDownsampleReady = false;;
grcRenderTarget* CRenderTargets::ms_BackBuffer = NULL;
#if DYNAMIC_BB
grcRenderTarget* CRenderTargets::ms_AltBackBuffer = NULL;
#endif
#if __XENON
// Aliases the 7e3 float back buffer as a 7e3 packed integer buffer
grcRenderTarget* CRenderTargets::ms_BackBuffer7e3ToIntAlias = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBuffers[3] = {NULL, NULL, NULL};
static grcRenderTarget* ms_DepthBufferAliases[3] = {NULL, NULL, NULL};
#else
grcRenderTarget* CRenderTargets::ms_DepthBuffer = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBuffer_PreAlpha = NULL;
#endif //__XENON
#if __PS3
static grcRenderTarget* ms_UIDepthBuffer;
static grcRenderTarget* m_DepthTargetQuarterPadding;
#endif
static grcRenderTarget* m_DepthTargetQuarter;
static grcRenderTarget* m_DepthTargetQuarterLinear;
#if RSG_PC && __D3D11
static grcRenderTarget* m_DepthTargetQuarter_ReadOnly;
static grcRenderTarget* m_DepthTargetQuarter_Copy;
static grcRenderTarget* m_DepthBuffer_PreAlpha_ReadOnly;
#endif // RSG_PC && __D3D11
#if RSG_PC
static grcRenderTarget* ms_UIDepthBuffer = NULL;
grcRenderTarget* CRenderTargets::ms_UIDepthBuffer_PreAlpha = NULL;
grcRenderTarget* CRenderTargets::ms_UIDepthBuffer_Resolved = NULL;
grcRenderTarget* CRenderTargets::ms_UIDepthBuffer_Resolved_ReadOnly = NULL;
#endif
#if LIGHT_VOLUME_USE_LOW_RESOLUTION
grcRenderTarget* m_volumeOffscreenBuffer;
grcRenderTarget* m_volumeReconstructionBuffer;
#endif
#if __XENON
grcRenderTarget* m_miniMapOffscreenBuffer = NULL;
grcRenderTarget* m_miniMapOffscreenDepthBuffer = NULL;
grcRenderTarget* m_BackBufferCopy = NULL;
#endif
#if __PPU
grcRenderTarget* CRenderTargets::ms_PatchedDepthBuffer;
grcBlendStateHandle CRenderTargets::ms_Refresh_BS;
grcDepthStencilStateHandle CRenderTargets::ms_RefreshStencil_DS;
grcDepthStencilStateHandle CRenderTargets::ms_RefreshStencilPreserveZFar_DS;
grcDepthStencilStateHandle CRenderTargets::ms_RefreshStencilZFar_DS;
grcDepthStencilStateHandle CRenderTargets::ms_RefreshZFar_G_DS;
grcDepthStencilStateHandle CRenderTargets::ms_RefreshZFar_L_DS;
bool CRenderTargets::ms_MSAARender = false;
bool CRenderTargets::ms_WithDepthRender = false;
#endif // __PPU
#if GTA_REPLAY
#if REPLAY_USE_PER_BLOCK_THUMBNAILS
grcTexture *CRenderTargets::ms_ReplayThumbnailTex[REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE] = { NULL };
grcRenderTarget *CRenderTargets::ms_ReplayThumbnailRT[REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE] = { NULL };
#endif // REPLAY_USE_PER_BLOCK_THUMBNAILS
#endif // GTA_REPLAY
#if __BANK
grcBlendStateHandle CRenderTargets::ms_BlitTransparent_BS;
#endif // __BANK
grcDepthStencilStateHandle CRenderTargets::ms_CopyDepth_DS;
#if __PS3
grcDepthStencilStateHandle CRenderTargets::ms_CopyDepthClearStencil_DS;
#endif
grcDepthStencilStateHandle CRenderTargets::ms_CopyColorStencilMask_DS;
grcBlendStateHandle CRenderTargets::ms_AlphaMaskToStencilMask_BS = grcStateBlock::BS_Invalid;
grcDepthStencilStateHandle CRenderTargets::ms_AlphaMaskToStencilMask_DS = grcStateBlock::DSS_Invalid;
#if __WIN32PC || RSG_DURANGO
grcRenderTarget* CRenderTargets::ms_DepthBufferCopy = NULL;
grcRenderTarget* CRenderTargets::ms_BackBufferCopy = NULL;
#if __D3D11
grcRenderTarget* CRenderTargets::ms_DepthBuffer_Stencil = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBufferCopy_Stencil = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBuffer_ReadOnly = NULL;
#if RSG_PC
grcRenderTarget* CRenderTargets::ms_DepthBuffer_ReadOnlyDepth = NULL;
#endif
bool CRenderTargets::ms_Initialized = false;
#if RSG_PC
grcRenderTarget* CRenderTargets::ms_BackBufferRTForPause = NULL;
grcTexture* CRenderTargets::ms_BackBufferTexForPause = NULL;
#endif
#endif
#elif RSG_ORBIS
grcRenderTarget* CRenderTargets::ms_BackBufferCopy = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBuffer_Stencil = NULL;
#endif // RSG_ORBIS
#if DEVICE_MSAA
grcRenderTarget* CRenderTargets::ms_BackBuffer_Resolved = NULL;
grcRenderTarget* CRenderTargets::ms_DepthBuffer_Resolved = NULL;
#if __D3D11
grcRenderTarget* CRenderTargets::ms_DepthBuffer_Resolved_ReadOnly = NULL;
#endif // __D3D11
#if ENABLE_PED_PASS_AA_SOURCE
grcRenderTarget* CRenderTargets::ms_BackBufferCopyAA = NULL;
#endif // ENABLE_PED_PASS_AA_SOURCE
#endif // DEVICE_MSAA
ASSERT_ONLY(static int g_CachedDownsampleDepthThreadID = -1;)
grcRenderTarget* CRenderTargets::GetBackBuffer(bool XENON_ONLY(realize))
{
#if __XENON
if (realize)
{
Assertf(ms_RenderTargetActive, "Cannot resolve the scene buffer when it is not locked");
grcResolveFlags flags;
if(((grcRenderTargetXenon*)ms_BackBuffer)->GetSurface()->Format == D3DFMT_A2B10G10R10F_EDRAM)
flags.ColorExpBias = -GRCDEVICE.GetColorExpBias();
ms_BackBuffer->Realize(&flags);
}
#elif !(__PPU || RSG_PC || RSG_DURANGO || RSG_ORBIS)
ASSERT(0, "CRenderTargets::GetBackBuffer - Not Implemented");
#endif
#if DYNAMIC_BB
return (ms_AltBackBuffer && sysThreadType::IsRenderThread() && static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->GetUseAltTarget()) ? ms_AltBackBuffer : ms_BackBuffer;
#else
#if RSG_PC
if (PostFX::GetPauseResolve() == PostFX::IN_RESOLVE_PAUSE)
return ms_BackBufferRTForPause;
else
#endif
return ms_BackBuffer;
#endif
}
#if DYNAMIC_BB
void CRenderTargets::InitAltBackBuffer()
{
if (ms_AltBackBuffer)
{
ESRAMManager::ESRAMCopyIn(ms_AltBackBuffer, ms_BackBuffer);
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetUseAltTarget(true);
}
}
void CRenderTargets::SetAltBackBuffer()
{
if (ms_BackBuffer && ms_AltBackBuffer)
{
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetUseAltTarget(true);
}
}
void CRenderTargets::ResetAltBackBuffer()
{
if (ms_BackBuffer)
{
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetUseAltTarget(false);
}
}
void CRenderTargets::FlushAltBackBuffer()
{
if (ms_BackBuffer && ms_AltBackBuffer)
{
ESRAMManager::ESRAMCopyOut(ms_BackBuffer, ms_AltBackBuffer);
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetUseAltTarget(false);
}
}
bool CRenderTargets::UseAltBackBufferTest()
{
#if !DYNAMIC_GB
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->GetUseAltTarget();
// return (DRAWLISTMGR->IsExecutingDrawSceneDrawList());
#else
return (DRAWLISTMGR->GetCurrExecDLInfo() && !DRAWLISTMGR->IsExecutingHudDrawList());
#endif
}
#endif
bool CRenderTargets::NeedsRescale()
{
#if __PS3
return !((VideoResManager::GetUIHeight() == VideoResManager::GetNativeHeight()) && (VideoResManager::GetUIWidth() == VideoResManager::GetNativeWidth()));
#else
return false;
#endif //__PS3
}
#if __PS3
void CRenderTargets::Rescale()
{
if(NeedsRescale())//PS3 final downscale from 720p game res to 480p.
{
grcRenderTarget* UIBuffer = GetHudBuffer();
grcTextureFactory::GetInstance().LockRenderTarget(0, grcTextureFactory::GetInstance().GetFrontBuffer(), NULL);
PF_PUSH_TIMEBAR_DETAIL("SD Final Downsample");
CSprite2d rescaleSprite;
rescaleSprite.BeginCustomList(CSprite2d::CS_RESOLVE_SDDOWNSAMPLEFILTER, UIBuffer);
CRenderTargets::DrawFullScreenTri(0.0f);
rescaleSprite.EndCustomList();
PF_POP_TIMEBAR_DETAIL();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
}
}
#endif //__PS3
grcRenderTarget* CRenderTargets::GetUIBackBuffer(bool XENON_ONLY(realize))
{
#if __PS3
if(NeedsRescale())
return CRenderTargets::GetHudBuffer();
else
return grcTextureFactory::GetInstance().GetFrontBuffer();
#elif __XENON
return grcTextureFactory::GetInstance().GetBackBuffer(realize);
#elif __D3D11 || RSG_ORBIS
return grcTextureFactory::GetInstance().GetBackBuffer();
#else
return grcTextureFactory::GetInstance().GetFrontBuffer();
#endif //__XENON
}
const grcRenderTarget* CRenderTargets::GetUIFrontBuffer()
{
return grcTextureFactory::GetInstance().GetFrontBuffer();
}
grcRenderTarget* CRenderTargets::GetDepthBuffer(bool XENON_ONLY(realize))
{
#if __XENON
int index = ((grcTextureFactoryXenon&)(grcTextureFactory::GetInstance())).GetCurrentFrontBufferIndex();
if(realize)
ms_DepthBuffers[index]->Realize();
return ms_DepthBuffers[index];
#else
return ms_DepthBuffer;
#endif //__XENON
}
#if __XENON || __PS3
grcRenderTarget* CRenderTargets::GetDepthBufferAsColor()
{
#if __XENON
return ms_DepthBufferAliases[((grcTextureFactoryXenon&)(grcTextureFactory::GetInstance())).GetCurrentFrontBufferIndex()];
#else
return ms_PatchedDepthBuffer;
#endif //__XENON
}
#endif //__XENON || __PS3
grcRenderTarget* CRenderTargets::GetUIDepthBuffer(bool MSAA_ONLY(realize))
{
#if __XENON
return grcTextureFactory::GetInstance().GetBackBufferDepth(false);
#elif __PS3
return ms_UIDepthBuffer;
#elif RSG_PC
if (!VideoResManager::IsSceneScaled())
{
if (realize)
return GetDepthResolved();
else
return ms_DepthBuffer;
}
else
{
if (realize)
return GRCDEVICE.GetMSAA()>1 ? ms_UIDepthBuffer_Resolved : ms_UIDepthBuffer;
else
return ms_UIDepthBuffer;
}
#else
# if DEVICE_MSAA
if (realize)
return GetDepthResolved();
# endif
return GetDepthBuffer();
#endif
}
grcRenderTarget* CRenderTargets::GetDepthBufferQuarterLinear(){ return m_DepthTargetQuarterLinear; }
grcRenderTarget* CRenderTargets::GetDepthBufferQuarter(){ return m_DepthTargetQuarter; }
grcRenderTarget* CRenderTargets::GetDepthBufferQuarter_Read_Target(bool WIN32PC_ONLY(doCopy))
{
#if RSG_PC
if (GRCDEVICE.IsReadOnlyDepthAllowed())
{
return m_DepthTargetQuarter_ReadOnly;
}else
{
if (doCopy)
{
m_DepthTargetQuarter_Copy->Copy( m_DepthTargetQuarter );
}
return m_DepthTargetQuarter_Copy;
}
#else
return m_DepthTargetQuarter;
#endif //RSG_PC
}
#if RSG_PC && __D3D11
grcRenderTarget* CRenderTargets::GetDepthBuffer_PreAlpha_ReadOnly(){ return m_DepthBuffer_PreAlpha_ReadOnly; }
#endif // RSG_PC && __D3D11
#if DEVICE_MSAA
void CRenderTargets::ResolveBackBuffer(bool depthReadOnly)
{
GRC_ALLOC_SCOPE_AUTO_PUSH_POP()
if (!ms_BackBuffer->GetMSAA())
{
ms_BackBufferCopy->Copy( ms_BackBuffer );
return;
}
UnlockSceneRenderTargets();
static_cast<grcRenderTargetMSAA*>(ms_BackBuffer)->Resolve( ms_BackBufferCopy );
if (depthReadOnly)
CRenderTargets::LockSceneRenderTargets_DepthCopy();
else
CRenderTargets::LockSceneRenderTargets();
}
#endif // DEVICE_MSAA
//Hud Targets
grcRenderTarget* m_OffscreenBuffers[4];
#if DEVICE_MSAA
grcRenderTarget* m_OffscreenBuffersResolved[4] = { NULL, NULL, NULL, NULL };
void CRenderTargets::ResolveSourceDepth(MSDepthResolve depthResolveType, grcRenderTarget* sourceMSAADepthTarget, grcRenderTarget* depthResolveTarget)
{
GRC_ALLOC_SCOPE_AUTO_PUSH_POP();
grcStateBlock::SetStates(grcStateBlock::RS_Default,
SSAO_OUTPUT_DEPTH ? grcStateBlock::DSS_ForceDepth : grcStateBlock::DSS_IgnoreDepth,
grcStateBlock::BS_Default);
grcTextureFactory::GetInstance().LockRenderTarget(0, NULL, depthResolveTarget);
CSprite2d::CustomShaderType type = CSprite2d::CS_COUNT;
switch( depthResolveType )
{
case depthResolve_Sample0:
type = CSprite2d::CS_RESOLVE_DEPTH_MS_SAMPLE0; break;
case depthResolve_Closest:
type = SUPPORT_INVERTED_PROJECTION ? CSprite2d::CS_RESOLVE_DEPTH_MS_MAX : CSprite2d::CS_RESOLVE_DEPTH_MS_MIN; break;
case depthResolve_Farthest:
type = SUPPORT_INVERTED_PROJECTION ? CSprite2d::CS_RESOLVE_DEPTH_MS_MIN : CSprite2d::CS_RESOLVE_DEPTH_MS_MAX; break;
case depthResolve_Dominant:
type = CSprite2d::CS_RESOLVE_DEPTH_DOMINANT; break;
default:
Errorf("invalid depth resolve type\n"); break;
}
CSprite2d resolveDepth;
resolveDepth.BeginCustomListMS(type, sourceMSAADepthTarget);
grcDrawSingleQuadf(-1.0, 1.0f, 1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0f, 1.0f,Color32(255, 255, 255, 255));
resolveDepth.EndCustomListMS();
grcTextureFactory::GetInstance().UnlockRenderTarget(0); //unlock and resolve
}
void CRenderTargets::ResolveDepth(MSDepthResolve depthResolveType, grcRenderTarget* alternateResolveTarget)
{
grcRenderTarget* depthResolveTarget = alternateResolveTarget ? alternateResolveTarget : CRenderTargets::GetDepthResolved();
ResolveSourceDepth(depthResolveType, CRenderTargets::GetDepthBuffer(), depthResolveTarget);
}
#endif // DEVICE_MSAA
void CRenderTargets::ResolveBuffer(unsigned index)
{
Assert(index < 4);
(void)index;
# if DEVICE_MSAA
grcRenderTarget *const pSource = m_OffscreenBuffers[index];
grcRenderTarget *const pDest = m_OffscreenBuffersResolved[index];
if (pSource->GetMSAA())
{
Assert( pDest != NULL && !pDest->GetMSAA() );
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE))
{
grcRenderTargetMSAA *const aaSource = static_cast<grcRenderTargetMSAA*>(pSource);
# if RSG_ORBIS
// decompress Fmask / eliminate fast clear
GRCDEVICE.FinishRendering( aaSource->GetColorTarget(), true );
# endif
# if NUMBER_OF_RENDER_THREADS == 1
// Need to have single threaded rendering to be able to
// correctly check this. Hopefully people will develop in
// single threaded mode often enough to pick up errors, as
// unnecissary resolves will burn performance.
Assert(static_cast<grcRenderTargetMSAA*>(pSource)->DebugGetLastResolved()
!= static_cast<grcRenderTargetMSAA*>(pDest)->GetResolveTarget());
# endif
aaSource->Resolve( static_cast<grcRenderTargetMSAA*>(pDest) );
}
}
# endif
}
grcRenderTarget* CRenderTargets::GetOffscreenBuffer(unsigned index)
{
Assert(index < 4);
return m_OffscreenBuffers[index];
}
grcRenderTarget* CRenderTargets::GetOffscreenBuffer_SingleSample(unsigned index)
{
Assert(index < 4);
#if DEVICE_MSAA
if (m_OffscreenBuffers[index]->GetMSAA())
return m_OffscreenBuffersResolved[index];
else
#endif
return m_OffscreenBuffers[index];
}
grcRenderTarget* CRenderTargets::GetOffscreenBuffer_Resolved(unsigned index)
{
#if DEVICE_MSAA
# if NUMBER_OF_RENDER_THREADS == 1
// Need to have single threaded rendering to be able to correctly check
// this. Hopefully people will develop in single threaded mode often
// enough to pick up errors (though chances are errors will be very
// visible anyways).
if (m_OffscreenBuffersResolved[index] != NULL)
{
Assert(CSystem::IsThisThreadId(SYS_THREAD_UPDATE)
|| static_cast<grcRenderTargetMSAA*>(m_OffscreenBuffers[index])->DebugGetLastResolved()
== static_cast<grcRenderTargetMSAA*>(m_OffscreenBuffersResolved[index])->GetResolveTarget());
}
# endif
#endif
return GetOffscreenBuffer_SingleSample(index);
}
#if __PS3
// If USE_DEPTHBUFFER_ZCULL_SHARING then this shares zcull memory with the backbuffer
grcRenderTarget* m_OffscreenDepthBuffer = NULL;
grcRenderTarget* m_OffscreenDepthBufferAlias = NULL;
grcRenderTarget* CRenderTargets::GetOffscreenDepthBuffer() { return m_OffscreenDepthBuffer; }
grcRenderTarget* CRenderTargets::GetOffscreenDepthBufferAsColor() { return m_OffscreenDepthBufferAlias; }
grcRenderTarget* CRenderTargets::SetOffscreenDepthBufferAsColor( grcRenderTarget* tgt ) { return m_OffscreenDepthBufferAlias = tgt; }
#endif
grcRenderTarget* CRenderTargets::GetVolumeOffscreenBuffer() { return LOW_RES_VOLUME_LIGHT_SWITCH( m_volumeOffscreenBuffer, ms_BackBufferCopy); } // Use quarter res target or use full res non-msaa target
#if LIGHT_VOLUME_USE_LOW_RESOLUTION
grcRenderTarget* CRenderTargets::GetVolumeReconstructionBuffer() { return m_volumeReconstructionBuffer; }
#endif //LIGHT_VOLUME_USE_LOW_RESOLUTION
#if __XENON
grcRenderTarget* CRenderTargets::GetMinimapOffscreenBuffer() { return m_miniMapOffscreenBuffer; }
grcRenderTarget* CRenderTargets::GetMinimapOffscreenDepthBuffer() { return m_miniMapOffscreenDepthBuffer; }
grcRenderTarget* CRenderTargets::GetBackBufferCopy() { return m_BackBufferCopy; }
#endif
#if RSG_ORBIS
void DisplayRenderTargetDetailsHeader()
{
Displayf("name\twidth\theight\tbpp\tmipCount\tpitch\talign\tphysSize");
}
#if !__NO_OUTPUT
uint64_t DisplayRenderTargetDetails(grcRenderTarget *target)
{
const sce::Gnm::Texture* tex = target->GetTexturePtr();
const sce::Gnm::DataFormat dataFormat = tex->getDataFormat();
u16 width = tex->getWidth();
u16 height = tex->getHeight();
u32 mipCount = tex->getLastMipLevel();
u32 bitsPerPixel = dataFormat.getBitsPerElement();
//const bool msaaEnabled = tex->getNumFragments() != sce::Gnm::kNumFragments1;
//const isDepth = dataFormat->getZFormat() != sce::Gnm::kZFormatInvalid;
const char* name = target->GetName();
u32 pitch = tex->getPitch();
uint64_t outSize;
sce::Gnm::AlignmentType outAlign;
sce::GpuAddress::computeTotalTiledTextureSize(&outSize, &outAlign, tex);
// N W H BBP MC P A S
Displayf("%s\t%d\t%d\t%d\t%d\t%d\t%d\t%lu",
name, width, height, bitsPerPixel, mipCount,
pitch, outAlign, outSize);
return outSize;
}
#endif // !__NO_OUTPUT
#endif // RSG_ORBIS
#if __XENON
void CRenderTargets::PreAllocateRenderTargetMemPool()
{
for (int i = 0; i< RTMEMPOOL_SIZE; i++)
ms_RenderTargetMemPoolArray[i]=kRTPoolIDInvalid;
CRenderTargets::AllocRenderTargetMemPool(1760256, XENON_RTMEMPOOL_GENERAL, kGeneralHeapCount);
CRenderTargets::AllocRenderTargetMemPool(3276800, XENON_RTMEMPOOL_GENERAL1, kGeneral1HeapCount);
int poolSize;
poolSize = CRenderTargets::GetRenderTargetMemPoolSize(1280, 720);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_GBUFFER0, kGBuffer0HeapCount);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_GBUFFER1, kGBuffer1HeapCount);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_TEMP_BUFFER, kTempBufferPoolHeapCount);
CRenderTargets::AllocRenderTargetMemPool(
CRenderTargets::GetRenderTargetMemPoolSize(512, 512),
XENON_RTMEMPOOL_PERLIN_NOISE,
kPerlinNoisePoolHeapCount);
grcTextureLock lock;
((grcTextureFactoryXenon&)(grcTextureFactory::GetInstance())).GetFrontBufferFromIndex(0)->LockRect(0, 0, lock, grcsRead | grcsAllowVRAMLock);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_FRONTBUFFER0, 2, lock.Base);
((grcTextureFactoryXenon&)(grcTextureFactory::GetInstance())).GetFrontBufferFromIndex(1)->LockRect(0, 0, lock, grcsRead | grcsAllowVRAMLock);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_FRONTBUFFER1, 2, lock.Base);
((grcTextureFactoryXenon&)(grcTextureFactory::GetInstance())).GetFrontBufferFromIndex(2)->LockRect(0, 0, lock, grcsRead | grcsAllowVRAMLock);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_FRONTBUFFER2, 2, lock.Base);
poolSize = CRenderTargets::GetRenderTargetMemPoolSize(1280*2, 720);
grcTextureFactory::GetInstance().GetBackBuffer(false)->LockRect(0, 0, lock, grcsRead | grcsAllowVRAMLock);
CRenderTargets::AllocRenderTargetMemPool(poolSize, XENON_RTMEMPOOL_GBUFFER23, kGBuffer23HeapCount, lock.Base);
}
int CRenderTargets::GetRenderTargetMemPoolSize(int width, int height)
{
int tw=(width>>5);
int th=(height>>5);
if ((tw<<5)<width) tw++;
if ((th<<5)<height) th++;
return ((tw<<5)*(th<<5)*4);
}
void CRenderTargets::AllocRenderTargetMemPool(int size, RTMemPoolID memPoodID, u8 heapCount, void* preallocatedBuffer)
{
char name[128];
sprintf(name, "pool %d", memPoodID);
Assert(memPoodID<RTMEMPOOL_SIZE);
Assert(ms_RenderTargetMemPoolArray[memPoodID]==kRTPoolIDInvalid);
//rounded up to 32x32 tiles
grcRTPoolCreateParams params;
params.m_Size = size;
params.m_HeapCount = heapCount;
if (memPoodID==XENON_RTMEMPOOL_SHADOWS || memPoodID==XENON_RTMEMPOOL_SHADOW_CACHE )
params.m_MaxTargets = 256; // more than the default for this pool
ms_RenderTargetMemPoolArray[memPoodID] = grcRenderTargetPoolMgr::CreatePool(name, params, preallocatedBuffer);
Assert(ms_RenderTargetMemPoolArray[memPoodID]!=kRTPoolIDInvalid);
}
#if !__NO_OUTPUT
void DisplayRenderTargetDetails(grcRenderTarget *target)
{
const char *name = target->GetName();
int width = target->GetWidth();
int height = target->GetHeight();
int poolId = target->GetPoolID();
int heapId = target->GetPoolHeap();
grcDeviceSurface *surface = ((rage::grcRenderTargetXenon*)target)->GetSurface();
grcTextureObject *texture = ((rage::grcRenderTargetXenon*)target)->GetTexturePtr();
bool rendereable = surface != NULL;
bool resolveable = texture != NULL;
XGTEXTURE_DESC texDesc;
XGTEXTURE_DESC surfaceDesc;
int bpp = 0;
int physBlockSize = 0;
int edramBlockSize = 0;
int physSize = 0;
int msaa = 0;
if( rendereable )
{
XGGetSurfaceDesc(surface,&surfaceDesc);
bpp = surfaceDesc.BitsPerPixel;
edramBlockSize = surfaceDesc.BitsPerPixel * surfaceDesc.HeightInBlocks * surfaceDesc.BytesPerBlock;
msaa = surfaceDesc.MultiSampleType > 0;
}
// For shared property, resolveable takes over.
if( resolveable )
{
XGGetTextureDesc(texture,0,&texDesc);
bpp = texDesc.BitsPerPixel;
physBlockSize = texDesc.BitsPerPixel * texDesc.HeightInBlocks * texDesc.BytesPerBlock;
physSize = XGSetTextureHeaderEx(texDesc.Width, texDesc.Height, 1, 0, texDesc.Format, 0, XGHEADEREX_NONPACKED,0, XGHEADER_CONTIGUOUS_MIP_OFFSET, 0, NULL, NULL, NULL);
}
Displayf("%d\t%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d",poolId,heapId,name,width,height,bpp,msaa,physBlockSize,edramBlockSize,physSize);
}
#endif // !__NO_OUTPUT
void DisplayRenderTargetDetailsHeader()
{
Displayf("poolId\theapId\t\tname\twidth\theight\tbpp\tmsaa\tphysBlockSize\tedramBlockSize\tphysSize");
}
#endif // __XENON
#if __PPU
static struct RenderTargetMemPoolDesc
{
const char* name;
u32 size;
u32 pitch;
u8 heaps;
bool tiled;
u8 location;
u8 compression;
} s_RenderTargetMemPoolDesc[RTMEMPOOL_SIZE] =
{
// Color Buffer
/* 00 */ { "PSN_RTMEMPOOL_P10240_TILED_LOCAL_COMPMODE_DISABLED", // 0: back buffer/Full Screen SSAO(Uses target directly), 1-3: ped blood and decoration, 4: Tiled Lighting 1/4 5: NONE 6: NONE 7: ped blood and decoration
115 * KB64, 10240, 8, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
/* 01 */ { "PSN_RTMEMPOOL_P1024_TILED_LOCAL_COMPMODE_DISABLED", // 0: POINT_SHADOW, 1: SPOT_SHADOW, 3: Ped Damage medRes, 4: ped Damage lowRes NOTE: ped damage skips over cached shadow textures using CParaboloidShadow::GetCacheTextureSize()
172 * KB64, 1024, 5, false, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
/* 02 */ { "PSN_RTMEMPOOL_P2048_TILED_LOCAL_COMPMODE_C32_2X1", // 0: REFLECTION_MAP_COLOUR, MIRROR_RT RT 1: FX_SEETHROUGH_COLOR, SSLR Intensity 2: Cube-map target
23 * KB64, 2048, 3, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_C32_2X1 },
/* 03 */ { "PSN_RTMEMPOOL_P512_TILED_LOCAL_COMPMODE_DISABLED", // 0: Imposters + HEIGHT_MAP_VS, 1: Water Wet Map Temp / Cube map reflections 2: Water Foam RT 3: Ped Headshot GBuffers LoRes 4: Ped Headshot GBuffers HiRes 5: Headshot Composite Buffer
#if USE_TREE_IMPOSTERS
10 * KB64, 512, 6, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
#else // USE_TREE_IMPOSTERS
7 * KB64, 512, 6, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
#endif // USE_TREE_IMPOSTERS
/* 04 */ { "PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2", // 0: GBuffer, 1: FX_SEETHROUGH_BLUR, MSAA reflection map, 2: NONE, 3: Volume Lights Offscreen buffer (low resolution), Volume Lights Reconstruction buffer, 4: NONE 5: Volume Lights Offscreen buffer(Full Resolution), Offscreen Depth, Particle Offscreen Downsampled Buffer 6: Offscreen buffers for HUD UI 7: Particle Offscreen Downsampled Buffer 8: PostFx Quarter Screen, SeeThrough Blur, Screenshot Buffer 9: Headshot Light Buffer 10: Meme Editor...
225 * KB64, 5120, 11, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
/* 05 */ { "PSN_RTMEMPOOL_P2560_TILED_LOCAL_COMPMODE_DISABLED",
// 0: Water Bump, Refraction Mask 1: Various PostFX Targets 2: NONE 3: FX_SEETHROUGH_DEPTH 4: MIRROR_DEPTH && mirror ped damage 5: Water Targets, Quarter Buffer Padding, Depth Quarter Linear 6: Procedural Ripple targets 7: Ped Damage 8: some of the pedDamage med & low res targets
// 9: SSAO Temp 0, SSAO Temp 1, 10: Water Lighting 1/4 + 1/16 temp RTs 11: Water Rain Bump 12: Temp classification textures 13: Shadowed PTX Buffer 14: pedheadshot colour target 15: pedheadshot colour target small 16: Water Reflection MSAA color and depth 17: ZCull Dummy 18: Water Bump 1/4
75* KB64, 2560, 19, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_DISABLED },
/* 06 */ { "PSN_RTMEMPOOL_P1024_TILED_LOCAL_COMPMODE_C32_2X1",// 0: Photo_RT 1: Water Bump Temp RT, 2: Water Lighting 1/64, 3: PostFX Light Adaptation 4: Water Bump Temp 1/4 RT
4 * KB64, 1024, 5, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_C32_2X1 },
/* 07 */ { "PSN_RTMEMPOOL_P1280_TILED_LOCAL_COMPMODE_C32_2X1", // 0 : sslr cutout 1 : WATER_REFLECTION_COLOUR 2: NONE 3: NONE 4 : NONE 5 : NONE 6: REFLECTION_MAP_COLOUR_MSAA(DISABLED)
4 * KB64, 1280, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_C32_2X1 },
// TODO +8 should be able to be removed, if we can remove something from heap 5
// Depth buffer
/* 08 */ { "PSN_RTMEMPOOL_P2560_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR", // 0: SHADOW_MAP_DIR, Depth Quarter 1: Light Rays Down Sampled Shadow
// If cascaded shadows stop being 640 wide, we need to move "Depth Quarter" back to P2560_TILED_LOCAL_COMPMODE_DISABLED and lose scull/zcull optimization in the up-sampler.
#if CASCADE_SHADOWS_RES_X <= 512 // support 4x 512x512 cascades arranged vertically
64 * KB64, 4*512, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
#elif CASCADE_SHADOWS_RES_X <= 640 // support 4x 640x640 cascades arranged vertically
115 * KB64, 4*640, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },//NOTE: Compression is disabled on __DEV builds! See: CASCADE_SHADOWS_ALTERNATE_SHADOW_MAPS
#elif CASCADE_SHADOWS_RES_X <= 800 // support 4x 800x800 cascades arranged vertically
163 * KB64, 3328, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
#elif CASCADE_SHADOWS_RES_X <= 1024 // support 4x 1024x1024 cascades arranged vertically
256 * KB64, 4*1024, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
#else // whatever, crash
1 * KB64, 512, 2, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
#endif
/* 09 */ { "PSN_RTMEMPOOL_P512_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR", // HEIGHT_MAP_DEPTH,
1 * KB64, 512, 1, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
/* 10 */ { "PSN_RTMEMPOOL_P1024_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_DIAGONAL", // 0: None, 1: Reflection Depth, 2: MSAA Cube Reflection Depth
2 * KB64, 1024, 3, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR },
// *THIS MUST BE LAST ENTRY* - see hack in PreAllocateRenderTargetMemPool():
/* 11 */ { "PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR_BBUFFER", //0: UI Depth Buffer 1: NonMSAADepth, 2: REFLECTION_MAP_COLOUR_CUBE_DEPTH 3: tree imposters, 4,5,6,7: ped damage 8: Scene Depth Buffer, 9, 10: ped damage
60 * KB64, 5120, 11, true, CELL_GCM_LOCATION_LOCAL, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR }, // no compression so we can copy as colour data
};
const char* s_CompressionMode[] =
{
"CELL_GCM_COMPMODE_C32_2X1",
"CELL_GCM_COMPMODE_C32_2X2",
"CELL_GCM_COMPMODE_Z32_SEPSTENCIL",
"CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REG",
"CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR",
"CELL_GCM_COMPMODE_Z32_SEPSTENCIL_DIAGONAL",
"CELL_GCM_COMPMODE_Z32_SEPSTENCIL_ROTATED",
};
#if !__NO_OUTPUT
void DisplayRenderTargetDetails(grcRenderTarget *target)
{
grcRenderTargetGCM *gcmRenderTarget = (grcRenderTargetGCM *)target;
int poolId = target->GetPoolID();
int heapId = target->GetPoolHeap();
u16 _width = gcmRenderTarget->GetWidth();
u16 height = gcmRenderTarget->GetHeight();
u32 bitsPerPixel = gcmRenderTarget->GetBitsPerPix();
u32 mipCount = gcmRenderTarget->GetMipMapCount();
bool msaa = gcmRenderTarget->GetMSAA() != grcDevice::MSAA_None;
u8 format = gcm::StripTextureFormat(gcmRenderTarget->GetGcmTexture().format);
bool isDepth = (format == CELL_GCM_TEXTURE_DEPTH24_D8) || (format == CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT) ||
(format == CELL_GCM_TEXTURE_DEPTH16) || (format == CELL_GCM_TEXTURE_DEPTH16_FLOAT);
const char *name = gcmRenderTarget->GetName();
bool inTiledMemory = gcmRenderTarget->IsTiled();
bool inLocalMemory = gcmRenderTarget->IsInLocalMemory();
bool isSwizzled = gcmRenderTarget->IsSwizzled();
bool isZCull = gcmRenderTarget->IsUsingZCull();
bool isCubeMap = gcmRenderTarget->GetType() == /*grcRenderTargetType::*/grcrtCubeMap;
// name,width,height,bitsPerPixel,mipCount
u16 width = (msaa == true) ? _width * 2: _width;
// HWwidth ,HW_Height,HW_mipmapCount
u32 HW_width = gcm::GetSurfaceWidth(width);
u32 HW_Height = gcm::GetSurfaceHeight(height,inLocalMemory);
u32 HW_mipmapCount = gcm::GetSurfaceMipMapCount(HW_width,HW_Height,isSwizzled);
// Pitch,Alignment,Size
u32 Pitch = gcm::GetSurfacePitch(HW_width, bitsPerPixel, isSwizzled);
u32 Alignment = gcm::GetSurfaceAlignment(inTiledMemory,isZCull);
u32 Size = gcm::GetSurfaceSize(HW_width,HW_Height,bitsPerPixel,mipCount,1, inLocalMemory, inTiledMemory, isSwizzled, isCubeMap, isZCull,NULL);
// zculledAlignment
u32 zculledAlignment = 0;
if( isDepth )
{
zculledAlignment = gcm::GetSurfaceAlignment(inTiledMemory,isZCull);
}
Displayf("%d\t%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", poolId,heapId,name,width,height,bitsPerPixel,mipCount,
HW_width ,HW_Height,HW_mipmapCount,
Pitch,Alignment,Size,
isZCull,zculledAlignment);
}
void DisplayRenderTargetDetailsHeader()
{
Displayf("poolId\theapId\tname\twidth\theight\tbitsPerPixel\tmipCount\tHW_width\tHW_Height\tHW_mipmapCount\tPitch\tAlignment\tSize\tuseZcull\tzculledAlignment");
}
#endif // !__NO_OUTPUT
XPARAM(EnableShadowCache); // TEMP for 32 bit hires CMs
void CRenderTargets::PreAllocateRenderTargetMemPool()
{
// Initialized to end of RSX local. Afaict, there is no nice define
// anywhere for this value, just needs to be hardcoded.
//
// The subtraction of 64KiB is annoyingly wasteful. We need to leave
// 16-bytes due to an RSX overfetch bug with S3TC or linear format textures
// (https://ps3.scedev.net/technotes/view/1127). But since the tiled
// regions need to be 64KiB aligned, we end up wasting a lot more than
// 16-bytes.
//
char *const vramEnd = (char*)0xcf900000;
char *vramPtr = vramEnd - 0x10000;
int i;
for (i=0; i<RTMEMPOOL_SIZE - 1; ++i)
{
RenderTargetMemPoolDesc& desc = s_RenderTargetMemPoolDesc[i];
const bool isPhysical = desc.location == CELL_GCM_LOCATION_LOCAL;
grcRTPoolCreateParams poolParams;
poolParams.m_Size = desc.size;
poolParams.m_HeapCount = desc.heaps;
poolParams.m_Alignment = gcm::GetSurfaceAlignment(desc.tiled, true),
poolParams.m_PhysicalMem = isPhysical;
poolParams.m_Pitch = desc.pitch;
poolParams.m_Compression = desc.compression;
poolParams.m_Tiled = desc.tiled;
void *buffer = NULL;
if (isPhysical)
{
vramPtr -= desc.size;
buffer = vramPtr;
}
poolParams.m_MaxTargets = (i==PSN_RTMEMPOOL_P1024_TILED_LOCAL_COMPMODE_DISABLED)?256:64; // there is only one pool has a more than the default max number of targets in them...
// this sucks, but for now it is compatible with the old way where the first target specified the type, zcull, etc. when we add those to the desc, we can remove this.
poolParams.m_InitOnCreate = (desc.compression<CELL_GCM_COMPMODE_Z32_SEPSTENCIL);
ms_RenderTargetMemPoolArray[i] = grcRenderTargetPoolMgr::CreatePool(desc.name, poolParams, buffer);
Assert(ms_RenderTargetMemPoolArray[i]!=kRTPoolIDInvalid);
Displayf("PSN RT mempool%d size=%d (%dKB, %dMB)", i, desc.size, desc.size/1024, desc.size/(1024*1024));
}
#if !__NO_OUTPUT
const uptr vramSizeKB = (vramEnd - vramPtr + 0x3ff) >> 10;
if (vramSizeKB != PSN_VRAM_RENDER_TARGET_TOTAL_KB)
{
Quitf("PSN_VRAM_RENDER_TARGET_TOTAL_KB (%u) is not the correct tally of the vram render targets. Should be %u.", PSN_VRAM_RENDER_TARGET_TOTAL_KB, vramSizeKB);
}
#endif
// that one's a special case: it reuse the depth buffer already allocated by rage.
RenderTargetMemPoolDesc& desc = s_RenderTargetMemPoolDesc[i];
Assertf(grcTextureFactory::GetInstance().GetBackBufferDepth(false) == NULL,"Depth buffer should be null at that point.");
u32 depthWidth = VideoResManager::GetUIWidth();
u32 depthHeight = VideoResManager::GetUIHeight();
u32 depthSize = gcm::GetSurfaceSize( depthWidth, /*u16 width, */
depthHeight, /*u16 height, */
32, /*u32 bitsPerPixel, */
1, /*u32 mipCount, */
1, /*u32 faceCount, */
true, /*bool inLocalMemory, */
true, /*bool inTiledMemory, */
false, /*bool isSwizzled, */
false, /*bool isCubeMap, */
true, /*bool isZCull, */
NULL /*u32* memoryOffsets*/);
u32 depthAlignment = gcm::GetSurfaceAlignment(true,true);
u32 depthPitch = gcm::GetSurfaceTiledPitch(depthWidth,32,false);
// no compression so we can copy as colour data
u8 compMode = CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR;
grcRTPoolCreateParams poolParams;
poolParams.m_Size = depthSize;
poolParams.m_HeapCount = desc.heaps;
poolParams.m_Alignment = depthAlignment,
poolParams.m_PhysicalMem = true;
poolParams.m_Pitch = depthPitch;
poolParams.m_Compression = compMode;
poolParams.m_Type = grcrtDepthBuffer;
ms_RenderTargetMemPoolArray[i] = grcRenderTargetPoolMgr::CreatePool(desc.name, poolParams);
Assert(ms_RenderTargetMemPoolArray[i]!=kRTPoolIDInvalid);
// Update description, for debug purpose
desc.size = depthSize;
desc.tiled = true;
desc.location = CELL_GCM_LOCATION_LOCAL;
desc.pitch = depthPitch;
desc.compression = compMode;
// Allocate and set a depth buffer.
// It's theoretically not needed but a) it's memory's shared with the other one and b) it helps laziness by not worrying about
// the fact that some of the memorytarget pool specs are initialized based on the first target being allocated!
grcTextureFactory::CreateParams params;
params.Multisample = grcDevice::MSAA_None;
params.InTiledMemory = true;
params.UseHierZ = true;
params.IsSRGB = false;
params.EnableCompression = ( compMode != CELL_GCM_COMPMODE_DISABLED );
// create depth buffer texture
grcRenderTargetGCM* depthBuffer = static_cast<grcRenderTargetGCM*>(CRenderTargets::CreateRenderTarget(
PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR_BBUFFER,
"UI DepthBuffer",
grcrtDepthBuffer,
depthWidth,
depthHeight,
32,
&params,
0)
);
Assert(depthBuffer);
depthBuffer->AllocateMemoryFromPool();
ms_UIDepthBuffer = depthBuffer;
// Rage, you lack depth.
static_cast<grcTextureFactoryGCM&>(grcTextureFactory::GetInstance()).SetBufferDepth(NULL);
}
//
// Purpose: Refresh the stencil cull on PS3 only.
//
void CRenderTargets::RefreshStencilCull(bool useEqual, int material, int mask, bool preserveZFarCull)
{
PF_PUSH_MARKER("Refresh Stencil Cull");
// see libgcm-Overview_e.pdf section 11
// NOTE: stencil mask must be set to 0xff or 0x00 for cellGcmSetClearZcullSurface() to work. to avoid setting a whole state block just for stencil mask we do it directly here.
GCM_DEBUG(GCM::cellGcmSetStencilMask(GCM_CONTEXT, 0xff));
GCM_DEBUG(GCM::cellGcmSetScullControl(GCM_CONTEXT, useEqual ? CELL_GCM_SCULL_SFUNC_EQUAL : CELL_GCM_SCULL_SFUNC_NOTEQUAL, material, mask));
GCM_DEBUG(GCM::cellGcmSetClearZcullSurface(GCM_CONTEXT, false, true)); // clear stencil cull only
// reload it (without modifying the values)
grcStateBlock::SetBlendState(ms_Refresh_BS);
if(preserveZFarCull)
grcStateBlock::SetDepthStencilState(ms_RefreshStencilPreserveZFar_DS,0xFF);
else
grcStateBlock::SetDepthStencilState(ms_RefreshStencil_DS,0xFF);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
GRCDEVICE.SetZMinMaxControl(true, true, false);
GRCDEVICE.SetDepthBoundsTestEnable(false);
CSprite2d zCullReload;
zCullReload.BeginCustomList(CSprite2d::CS_SCULL_RELOAD, NULL);
DrawFullScreenTri(0.0f);
zCullReload.EndCustomList();
GRCDEVICE.SetZMinMaxControl(true, false, false); // restore
PF_POP_MARKER();
}
void CRenderTargets::ResetStencilCull(bool useEqual, int material, int mask, bool clearZ, bool clearStencil)
{
PF_PUSH_MARKER("Reset Stencil Cull");
GCM_DEBUG(GCM::cellGcmSetStencilMask(GCM_CONTEXT, 0xff));
GCM_DEBUG(GCM::cellGcmSetScullControl(GCM_CONTEXT, useEqual ? CELL_GCM_SCULL_SFUNC_EQUAL : CELL_GCM_SCULL_SFUNC_NOTEQUAL, material, mask));
GCM_DEBUG(GCM::cellGcmSetClearZcullSurface(GCM_CONTEXT, clearZ, clearStencil));
PF_POP_MARKER();
}
void CRenderTargets::RefreshStencilZFarCull(bool useEqual, int material, int mask)
{
PF_PUSH_MARKER("Refresh Stencil ZFar Cull");
// see libgcm-Overview_e.pdf section 11
// NOTE: stencil mask must be set to 0xff or 0x00 for cellGcmSetClearZcullSurface() to work. to avoid setting a whole state block just for stencil mask we do it directly here.
GCM_DEBUG(GCM::cellGcmSetStencilMask(GCM_CONTEXT, 0xff));
GCM_DEBUG(GCM::cellGcmSetScullControl(GCM_CONTEXT, useEqual ? CELL_GCM_SCULL_SFUNC_EQUAL : CELL_GCM_SCULL_SFUNC_NOTEQUAL, material, mask));
GCM_DEBUG(GCM::cellGcmSetClearZcullSurface(GCM_CONTEXT, true, true));
// reload it (without modifying the values)
GRCDEVICE.SetZMinMaxControl(true, true, false);
GRCDEVICE.SetDepthBoundsTestEnable(false);
grcStateBlock::SetRasterizerState( grcStateBlock::RS_NoBackfaceCull);
grcStateBlock::SetBlendState(ms_Refresh_BS);
grcStateBlock::SetDepthStencilState(ms_RefreshStencilZFar_DS,0x00);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
CSprite2d zCullReload;
zCullReload.BeginCustomList(CSprite2d::CS_ZCULL_RELOAD, NULL);
grcDrawSingleQuadf(0,0,1,1,0,0,0,1,1,Color32(255,255,255,255));
zCullReload.EndCustomList();
GRCDEVICE.SetZMinMaxControl(true, false, false); // restore
PF_POP_MARKER();
}
void CRenderTargets::SetZCullControl(bool useDepthGreater)
{
GRCDEVICE.InsertFence(); // without the WaitForIdle this inserts, changing the zcull control direction causes some places on screen occasionally that fail the zcull test (and drop out lights, etc)
GCM_DEBUG(GCM::cellGcmSetZcullControl(GCM_CONTEXT, (useDepthGreater) ? CELL_GCM_ZCULL_GREATER : CELL_GCM_ZCULL_LESS, (useDepthGreater) ? CELL_GCM_ZCULL_MSB:CELL_GCM_ZCULL_LONES));
GCM_STATE(SetClearDepthStencil, (static_cast<u32>(((useDepthGreater)?0.0f:1.0f) * 0xffffff) << 8));
}
void CRenderTargets::RefreshZFarCull(bool useDepthGreater)
{
PF_PUSH_MARKER("Refresh ZFar Cull");
// Section 7.3.2.2 RSX-Users_Manual_e.pdf
SetZCullControl( useDepthGreater );
grcStateBlock::SetRasterizerState( grcStateBlock::RS_NoBackfaceCull);
grcStateBlock::SetBlendState(ms_Refresh_BS);
grcStateBlock::SetDepthStencilState(useDepthGreater ? ms_RefreshZFar_G_DS : ms_RefreshZFar_L_DS);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
GRCDEVICE.SetZMinMaxControl(true, true, false);
GRCDEVICE.SetDepthBoundsTestEnable(false);
GCM_DEBUG(GCM::cellGcmSetClearZcullSurface(GCM_CONTEXT, true, false));
CSprite2d zCullReload;
zCullReload.BeginCustomList((useDepthGreater) ? CSprite2d::CS_ZCULL_RELOAD_GT : CSprite2d::CS_ZCULL_RELOAD, NULL);
static float depth = 0.0f;
DrawFullScreenTri(depth);
zCullReload.EndCustomList();
GRCDEVICE.SetZMinMaxControl(true, false, false); // restore
PF_POP_MARKER();
}
static void ResolveMSAA(const grcWindow *win)
{
grcStateBlock::SetBlendState(grcStateBlock::BS_CompositeAlpha);
Color32 color(1.0f,1.0f,1.0f,1.0f);
CSprite2d msaaResolve;
msaaResolve.BeginCustomList(CSprite2d::CS_RESOLVE_MSAA2X, GBuffer::GetTarget(GBUFFER_RT_2));
if( win )
{
const float x1 = win->GetNormX() * 2.0f - 1.0f;
const float y1 = -(win->GetNormY() * 2.0f - 1.0f);
const float x2 = (win->GetNormX() + win->GetNormWidth()) * 2.0f - 1.0f;
const float y2 = -((win->GetNormY() + win->GetNormHeight()) * 2.0f - 1.0f);
grcDrawSingleQuadf( x1,y1,
x2,y2,
0.1f,
win->GetNormX(),win->GetNormY(),
win->GetNormX() + win->GetNormWidth(),win->GetNormY() + win->GetNormHeight(),
color);
}
else
{
const float x1 = -1.0f;
const float y1 = 1.0f;
const float x2 = 1.0f;
const float y2 = -1.0f;
grcDrawSingleQuadf( x1,y1,
x2,y2,
0.1f,
0.0f,0.0f,
1.0f,1.0f,
color);
}
msaaResolve.EndCustomList();
}
void CRenderTargets::BeginMSAARender()
{
if( false == ms_MSAARender )
{
grcViewport* viewPort = grcViewport::GetCurrent();
const grcWindow& win = viewPort->GetWindow();
// Lock MSAA buffer
// We just use the GBuffer 3 as an msaa target
grcRenderTarget *fbRT = GBuffer::GetTarget(GBUFFER_RT_2);
grcRenderTarget *depthRT = GBuffer::GetDepthTarget();
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
// Adding an evil 1 pixel border: we might be doing scissoring, and we are doing some quincunx filtering so we need that to be clean...
GRCDEVICE.Clear(true, Color32(0x00),true,1.0f,false,0);
ms_MSAARender = true;
}
}
void CRenderTargets::EndMSAARender()
{
if( ms_MSAARender )
{
// Unlock RT
grcViewport* viewPort = grcViewport::GetCurrent();
grcWindow win = viewPort->GetWindow();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
ResolveMSAA(&win);
ms_MSAARender = false;
}
}
void CRenderTargets::ClearStencilCull( int /*material*/)
{}
#endif // __PPU
#if __XENON
void CRenderTargets::RefreshStencilCull(bool useEqual, int material, int /*mask*/)
{
{
GBuffer::BeginUseHiStencil( material, useEqual);
}
}
void CRenderTargets::ClearStencilCull(int material)
{
GBuffer::EndUseHiStencil(material);
}
//
// Alias the 10bit float HDR back buffer with a 10bit integer format so that we don't have to expand to 16bit float on resolve.
// This cuts the resolve time in half and speeds up sampling but it requires you to decode color in the shader and prevents you
// from using texture filtering.
grcRenderTarget* CRenderTargets::GetBackBuffer7e3toInt( bool bRealize /*= false*/ )
{
Assertf(static_cast<grcRenderTargetXenon*>(grcTextureFactory::GetInstance().GetBackBuffer(false))->GetSurface()->Format == D3DFMT_A2B10G10R10F_EDRAM, "Can't resolve non-7e3 backbuffer format to 10bit int");
if ( bRealize )
{
// Change the render target to the same format as the destination texture
bool targetsActive = ms_RenderTargetActive;
if(targetsActive)
UnlockSceneRenderTargets();
#if RSG_ORBIS || __D3D11
grcTextureFactory::GetInstance().LockRenderTarget(0, ms_BackBuffer7e3ToIntAlias, NULL, 0, false, 0);
#else
grcTextureFactory::GetInstance().LockRenderTarget(0, ms_BackBuffer7e3ToIntAlias, NULL, 0, false);
#endif
// Restore the render target format to the correct format for future use
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = true;
resolveFlags.ClearDepthStencil = false;
resolveFlags.ClearColor = false;
resolveFlags.Color = Color32(0,0,0,0);
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
if(targetsActive)
LockSceneRenderTargets();
}
static_cast<grcRenderTargetXenon*>(ms_BackBuffer7e3ToIntAlias)->SetExpAdjust(3); // Use this to avoid division by 8
return ms_BackBuffer7e3ToIntAlias;
}
#endif // __XENON
#if RSG_PS3 || RSG_XENON
//
// Purpose: Convert an alpha mask to a stencil mask, on the consoles this will also setup early-stencil culling (HiStencil/SCull) so
// no need to do a HiZ/SCull refresh pass. This pass is slightly more expensive than a regular (non-alpha) HiZ/SCull refresh:
// 1280x720 & RGBA8 Source Texture: PS3 = 0.22ms, 360 = 0.26ms.
//
// ** Because of differences in the early-stencil hardware, the PS3 will write the stencil bit where the alpha mask passes, and
// the 360 will write the stencil bit where the alpha mask fails. If this becomes a major issue, then the 360 can be made to
// match the PS3's behavior but we will need to switch to FlushHiZStencil(D3DFHZS_SYNCHRONOUS) and reverse some alpha/stencil tests.
//
void CRenderTargets::ConvertAlphaMaskToStencilMask(int alphaRef, grcTexture* pSourceAlpha XENON_ONLY(, bool bUseStencilAsColor))
{
// Alpha Mask to Stencil Mask conversion stateblocks
if ( grcStateBlock::BS_Invalid == ms_AlphaMaskToStencilMask_BS )
{
grcBlendStateDesc BSDesc;
BSDesc.BlendRTDesc[0].BlendEnable = false;
BSDesc.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_NONE;
ms_AlphaMaskToStencilMask_BS = grcStateBlock::CreateBlendState(BSDesc);
}
if ( grcStateBlock::DSS_Invalid == ms_AlphaMaskToStencilMask_DS )
{
grcDepthStencilStateDesc SDDesc;
SDDesc.DepthEnable = false;
SDDesc.DepthWriteMask = false;
SDDesc.DepthFunc = grcRSV::CMP_LESS;//DEFAULT
SDDesc.StencilEnable = true;
SDDesc.StencilReadMask = DEFERRED_MATERIAL_SPECIALBIT;
SDDesc.StencilWriteMask = DEFERRED_MATERIAL_SPECIALBIT;
SDDesc.FrontFace.StencilFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilPassOp = grcRSV::STENCILOP_REPLACE;
SDDesc.FrontFace.StencilFunc = grcRSV::CMP_ALWAYS;
SDDesc.BackFace = SDDesc.FrontFace;
ms_AlphaMaskToStencilMask_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
}
PF_PUSH_MARKER("Alpha Mask to Stencil Mask");
{
#if __PS3
// see libgcm-Overview_e.pdf section 11
// NOTE: stencil mask must be set to 0xff or 0x00 for cellGcmSetClearZcullSurface() to work. to avoid setting a whole state block just for stencil mask we do it directly here.
GCM_DEBUG(GCM::cellGcmSetClearDepthStencil(GCM_CONTEXT, 0x0)); // Need to set this so that SCull is cleared to 'fail' state
GCM_DEBUG(GCM::cellGcmSetStencilMask(GCM_CONTEXT, 0xff));
GCM_DEBUG(GCM::cellGcmSetScullControl(GCM_CONTEXT, CELL_GCM_SCULL_SFUNC_EQUAL, DEFERRED_MATERIAL_SPECIALBIT, DEFERRED_MATERIAL_SPECIALBIT));
GCM_DEBUG(GCM::cellGcmSetClearZcullSurface(GCM_CONTEXT, false, true)); // clear stencil cull only
#elif __XENON
GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILENABLE, true ); // Must be true since we are using an alpha clip below
GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILWRITEENABLE, true );
GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILREF, DEFERRED_MATERIAL_SPECIALBIT );
GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILFUNC, D3DHSCMP_EQUAL );
GRCDEVICE.GetCurrent()->Clear(0, NULL, D3DCLEAR_HISTENCIL_PASS|D3DCLEAR_STENCIL, 0x0, 1.0f, 0x0 ); // There appears to be a bug if you only set D3DCLEAR_HISTENCIL_PASS (results in depth and stencil getting stomped, and hi-stencil not reliably being cleared)
GRCDEVICE.GetCurrent()->FlushHiZStencil( D3DFHZS_ASYNCHRONOUS );
#endif
// Use an alpha mask to set a stencil bit
grcStateBlock::SetBlendState(ms_AlphaMaskToStencilMask_BS, ~0U, ~0ULL);
grcStateBlock::SetDepthStencilState(ms_AlphaMaskToStencilMask_DS, DEFERRED_MATERIAL_SPECIALBIT);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
PS3_ONLY( GRCDEVICE.SetZMinMaxControl(true, true, false) );
#if DEPTH_BOUNDS_SUPPORT
GRCDEVICE.SetDepthBoundsTestEnable(false);
#endif //DEPTH_BOUNDS_SUPPORT
// Draw full screen triangle
CSprite2d zCullReload;
zCullReload.BeginCustomList(
XENON_ONLY(bUseStencilAsColor? CSprite2d::CS_ALPHA_MASK_TO_STENCIL_MASK_STENCIL_AS_COLOR : )CSprite2d::CS_ALPHA_MASK_TO_STENCIL_MASK,
pSourceAlpha
);
DrawFullScreenTri(0.0f);
zCullReload.EndCustomList();
// Enable HiStencil culling for 360
XENON_ONLY( GRCDEVICE.GetCurrent()->FlushHiZStencil( D3DFHZS_ASYNCHRONOUS ) );
XENON_ONLY( GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILWRITEENABLE, false ) );
XENON_ONLY( GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILENABLE, true ) );
PS3_ONLY( GRCDEVICE.SetZMinMaxControl(true, false, false) ); // restore
}
PF_POP_MARKER(); //"Alpha Mask to Stencil Mask"
}
#endif // RSG_PS3 || RSG_XENON
//
// Purpose: Draws a full screen triangle, effectively the same as full screen quad but achieves better pixel quad
// utilization since there are fewer edges on screen (and thus fewer partial pixel quads)
//
void CRenderTargets::DrawFullScreenTri ( float depth )
{
// 360 requires an offset to align pixels and texels, PS3 and DX10+ do not.
const bool bUseOffset = __XENON ? true : false;
float fHalfTexelOffsetX = 0.f;
float fHalfTexelOffsetY = 0.f;
if ( bUseOffset )
{
fHalfTexelOffsetX = 0.5f/GRCDEVICE.GetWidth();
fHalfTexelOffsetY = 0.5f/GRCDEVICE.GetHeight();
}
// use a tri as per docs to avoid edges on screen
grcBegin(drawTris,3);
grcVertex(0.0f, 0.0f, depth, 0.0f,0.0f,0.0f, Color32(255,255,255,255), 0.0f+fHalfTexelOffsetX, 1.0f+fHalfTexelOffsetY);
grcVertex(2.0f, 0.0f, depth, 0.0f,0.0f,0.0f, Color32(255,255,255,255), 2.0f+fHalfTexelOffsetX, 1.0f+fHalfTexelOffsetY);
grcVertex(0.0f, 2.0f, depth, 0.0f,0.0f,0.0f, Color32(255,255,255,255), 0.0f+fHalfTexelOffsetX,-1.0f+fHalfTexelOffsetY);
grcEnd();
}
void CRenderTargets::AllocateRenderTargets()
{
RAGE_TRACK(CRenderTargets);
RAGE_TRACK(AllocateRenderTargets);
USE_MEMBUCKET(MEMBUCKET_RENDER);
#if RSG_PC
ms_Initialized = true;
#endif
int iWidth = VideoResManager::GetSceneWidth();
int iHeight = VideoResManager::GetSceneHeight();
int UIWidth = VideoResManager::GetUIWidth();
int UIHeight = VideoResManager::GetUIHeight();
#if __XENON
{
// LDR temp buffer so that we have 32bit tone mapped target to sample from for anti-aliasing
grcTextureFactory::CreateParams osbparams;
osbparams.Format = grctfA8R8G8B8;
osbparams.HasParent = true;
osbparams.Parent = grcTextureFactory::GetInstance().GetBackBufferDepth(false);
osbparams.ColorExpBias = 0;
m_OffscreenBuffers[0] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GBUFFER0, "UI Buffer", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, kOffscreenBuffer0);
m_OffscreenBuffers[0]->AllocateMemoryFromPool();
m_OffscreenBuffers[1] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GBUFFER1, "OffscreenBuffer1", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, kOffscreenBuffer1);
m_OffscreenBuffers[1]->AllocateMemoryFromPool();
m_OffscreenBuffers[2] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GBUFFER0, "OffscreenBuffer2", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, kOffscreenBuffer2);
m_OffscreenBuffers[2]->AllocateMemoryFromPool();
m_OffscreenBuffers[3] = m_OffscreenBuffers[1];
osbparams.Parent = m_OffscreenBuffers[1];
m_miniMapOffscreenBuffer= CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GENERAL1, "MiniMapOffscreenBuffer", grcrtPermanent, 512, 512, 32, &osbparams, kMinimapOffscreenBufferHeap);
m_miniMapOffscreenBuffer->AllocateMemoryFromPool();
grcTextureFactory::CreateParams paramsMinimapDepthBuffer;
paramsMinimapDepthBuffer.HasParent = true;
paramsMinimapDepthBuffer.Parent = m_miniMapOffscreenBuffer;
paramsMinimapDepthBuffer.Format = grctfA2B10G10R10;
paramsMinimapDepthBuffer.IsResolvable = false;
m_miniMapOffscreenDepthBuffer = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GENERAL1, "MiniMapOffscreenDepthBuffer", grcrtDepthBuffer, 512, 512, 32, &paramsMinimapDepthBuffer, kMinimapOffscreenDepthBufferHeap);
grcTextureFactory::CreateParams paramsDepthBuffer;
paramsDepthBuffer.HasParent = true;
paramsDepthBuffer.Parent = NULL;
paramsDepthBuffer.Format = grctfA2B10G10R10;
ms_DepthBuffers[0] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER0, "DepthBuffer0", grcrtDepthBuffer, iWidth, iHeight, 32, &paramsDepthBuffer, 0);
ms_DepthBuffers[0]->AllocateMemoryFromPool();
ms_DepthBuffers[1] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER1, "DepthBuffer1", grcrtDepthBuffer, iWidth, iHeight, 32, &paramsDepthBuffer, 0);
ms_DepthBuffers[1]->AllocateMemoryFromPool();
ms_DepthBuffers[2] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER2, "DepthBuffer2", grcrtDepthBuffer, iWidth, iHeight, 32, &paramsDepthBuffer, 0);
ms_DepthBuffers[2]->AllocateMemoryFromPool();
paramsDepthBuffer.Format = grctfA8R8G8B8;
ms_DepthBufferAliases[0] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER0, "DepthBufferAlias0", grcrtPermanent, iWidth, iHeight, 32, &paramsDepthBuffer, 1);
ms_DepthBufferAliases[0]->AllocateMemoryFromPool();
ms_DepthBufferAliases[1] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER1, "DepthBufferAlias1", grcrtPermanent, iWidth, iHeight, 32, &paramsDepthBuffer, 1);
ms_DepthBufferAliases[1]->AllocateMemoryFromPool();
ms_DepthBufferAliases[2] = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_FRONTBUFFER2, "DepthBufferAlias2", grcrtPermanent, iWidth, iHeight, 32, &paramsDepthBuffer, 1);
ms_DepthBufferAliases[2]->AllocateMemoryFromPool();
grcTextureFactory::CreateParams paramsBackBuffer;
paramsBackBuffer.HasParent = true;
paramsBackBuffer.Parent = grcTextureFactory::GetInstance().GetBackBufferDepth(false);
paramsBackBuffer.ColorExpBias = -GRCDEVICE.GetColorExpBias();
paramsBackBuffer.Format = grctfA2B10G10R10;
ms_BackBuffer = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GBUFFER23, "BackBuffer", grcrtPermanent, iWidth, iHeight, 32, &paramsBackBuffer, kBackBufferHeap);
ms_BackBuffer->AllocateMemoryFromPool();
//////////////////////////////////////////////////////////////////////////
// part of temporary fix for edram overflow
paramsBackBuffer.Format = grctfA8R8G8B8;
m_BackBufferCopy = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_TEMP_BUFFER, "BackbufferCopy", grcrtPermanent, iWidth, iHeight, 32, &paramsBackBuffer, kTempBufferPoolHeap);
m_BackBufferCopy->AllocateMemoryFromPool();
//////////////////////////////////////////////////////////////////////////
grcTextureFactory::CreateParams params7e3toInt;
params7e3toInt.Format = grctfA2B10G10R10ATI;
params7e3toInt.HasParent = true;
params7e3toInt.Parent = grcTextureFactory::GetInstance().GetBackBufferDepth(false);
params7e3toInt.ColorExpBias = 0;
ms_BackBuffer7e3ToIntAlias = CRenderTargets::CreateRenderTarget(XENON_RTMEMPOOL_GBUFFER23, "BackBuffer 7e3/int Alias", grcrtPermanent, iWidth, iHeight, 32, &params7e3toInt, kBackBuffer7e3IntAliasHeap);
ms_BackBuffer7e3ToIntAlias->AllocateMemoryFromPool();
//640x360 Depth Buffer
// If any changes are made here for this target, please make the same changes to GBuffer::m_4xHiZRestoreQuarter
// as we use that for doing Hi-Stencil/Hi-Z refresh with the quarter depth buffer
grcTextureFactory::CreateParams params;
params.HasParent = true;
params.Parent = grcTextureFactory::GetInstance().GetBackBuffer(false);
params.Format = grctfA8R8G8B8;
params.AllocateFromPoolOnCreate = false;
params.PoolID = GetRenderTargetPoolID(XENON_RTMEMPOOL_GENERAL1);
params.PoolHeap = kTiledLightingHeap2;
params.UseHierZ = true;
//Setting the Hi-Z base to after the full res depth buffer so that it does not destroy the contents of Hi-Z after downsampling depth
params.HiZBase = static_cast<grcRenderTargetXenon*>(grcTextureFactory::GetInstance().GetBackBufferDepth(false))->GetHiZSize();
m_DepthTargetQuarter = grcTextureFactory::GetInstance().CreateRenderTarget("Depth Quarter", grcrtDepthBuffer, iWidth/2, iHeight/2, 32, &params);
//m_DepthTargetQuarter->AllocateMemoryFromPool(); // This happens in water.cpp
//R32F Version
//This is suppose to be the tiled lighting target 0 but since that allocation comes later I can't use it,the backbuffer depth should provide a sufficent EDRAM offset
params.Parent = grcTextureFactory::GetInstance().GetBackBufferDepth(false);
params.Format = grctfR32F;
params.PoolID = GetRenderTargetPoolID(XENON_RTMEMPOOL_GENERAL1);
params.PoolHeap = kSSAOWaterHeap;
m_DepthTargetQuarterLinear = grcTextureFactory::GetInstance().CreateRenderTarget("Depth Quarter Linear", grcrtPermanent, iWidth/2, iHeight/2, 32, &params);
//m_DepthTargetQuarterLinear->AllocateMemoryFromPool(); // This happens in water.cpp
}
#endif // __XENON
#if LIGHT_VOLUME_USE_LOW_RESOLUTION && RSG_DURANGO
grcTextureFactory::CreateParams volParams;
volParams.Multisample = 0;
volParams.UseFloat = true;
ORBIS_ONLY( volParams.EnableFastClear = false );
volParams.Format = grctfA16B16G16R16F; // up-sampling & reconstruction optimizations require that we have an alpha channel
const int nVolumeBPP = 64;
const int nVolWidth = iWidth/2;
const int nVolHeight =iHeight/2;
m_volumeOffscreenBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "Volume Lights Offscreen buffer", grcrtPermanent, nVolWidth, nVolHeight, nVolumeBPP, &volParams, 1 WIN32PC_ONLY(, m_volumeOffscreenBuffer));
m_volumeReconstructionBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "Volume Lights Reconstruction buffer", grcrtPermanent, nVolWidth, nVolHeight, nVolumeBPP, &volParams, 1 WIN32PC_ONLY(, m_volumeReconstructionBuffer));
#endif
// create offscreen Buffer
grcTextureFactory::CreateParams params;
// color
params.Multisample = 0;
params.HasParent = true;
params.Parent = NULL;
params.UseFloat = true;
params.UseHierZ = false;
params.InTiledMemory = true;
params.IsSwizzled = false;
params.EnableCompression = false;
u32 bpp = 64;
params.IsSRGB = true;
params.Format = grctfA16B16G16R16F;
#if !__FINAL && (__D3D11 || RSG_ORBIS)
if( PARAM_DX11Use8BitTargets.Get() )
{
params.Format = grctfA8R8G8B8;
params.UseFloat = false;
params.IsSRGB = true;
bpp = 32;
}
else
#endif // !__FINAL
{
params.Format = grctfA16B16G16R16F;
bpp = 64;
// Back Buffer needs alpha but BackBUfferCopy only needs alpha for fxaa
/*
#if __D3D11 || RSG_ORBIS
if (!PARAM_highColorPrecision.Get())
{
params.Format = grctfR11G11B10F;
bpp = 32;
}
#endif // __D3D11 || RSG_ORBIS
*/
}
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
grcDevice::MSAAMode multisample = GRCDEVICE.GetMSAA();
params.Multisample = multisample;
# if RSG_ORBIS
params.EnableFastClear = false;
# endif //RSG_ORBIS
# if DEVICE_EQAA
if (!UseFullBackbufferCoverage(multisample))
{
params.Multisample.DisableCoverage();
}
# else
const u32 multisampleQuality = GRCDEVICE.GetMSAAQuality();
params.MultisampleQuality = (u8)multisampleQuality;
# endif
ms_BackBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "BackBuffer", grcrtPermanent, iWidth, iHeight, bpp, &params, 0 WIN32PC_ONLY(, ms_BackBuffer) DURANGO_ONLY(, ms_BackBuffer));
#if DYNAMIC_BB
grcTextureFactory::CreateParams altParams = params;
#endif
if (!ms_BackBuffer)
{
Quitf(ERR_GFX_RENDERTARGET,"failed to create RenderTarget::ms_BackBuffer");
}
#endif // RSG_PC || RSG_DURANGO || RSG_ORBIS
#if DEVICE_MSAA
if(multisample)
{
#if ENABLE_PED_PASS_AA_SOURCE
ms_BackBufferCopyAA = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "BackBufferCopyAA", grcrtPermanent, iWidth, iHeight, bpp, &params, 0 WIN32PC_ONLY(, ms_BackBufferCopyAA) DURANGO_ONLY(, ms_BackBufferCopyAA));
#endif // ENABLE_PED_PASS_AA_SOURCE
grcTextureFactory::CreateParams ResolvedParams = params;
ResolvedParams.Multisample = grcDevice::MSAA_None;
ms_BackBuffer_Resolved = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "BackBuffer_Resolved", grcrtPermanent, iWidth, iHeight, bpp, &ResolvedParams, 0 WIN32PC_ONLY(, ms_BackBuffer_Resolved));
}
#endif // DEVICE_MSAA
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
ms_BackBufferCopy =
#if DEVICE_MSAA
multisample ? ms_BackBuffer_Resolved :
#endif //DEVICE_MSAA
CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "BackBufferCopy", grcrtPermanent, iWidth, iHeight, bpp, &params, 0 WIN32PC_ONLY(, ms_BackBufferCopy));
#endif // RSG_PC || RSG_DURANGO || RSG_ORBIS
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
params.UseHierZ = true;
params.Format = grctfD32FS8;
params.Lockable = 0;
int depthBpp = 40;
// DX11: TODO: Could set this up so the lockable textures are created on first use.
// Current method creates extra lockable render targets with associated extra memory usage
ENTITYSELECT_ONLY(params.Lockable = __BANK); // In __BANK these are lockable as they're used for entity select.
params.Multisample = grcDevice::MSAA_None;
#if __D3D11
grcTextureFactoryDX11 &textureFactory11 = static_cast<grcTextureFactoryDX11&>( grcTextureFactory::GetInstance() );
#endif
//We need a copy of the depth buffer pre alpha for the depth of field through windows, etc...
ms_DepthBuffer_PreAlpha = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "DepthBuffer Pre Alpha", grcrtDepthBuffer, iWidth, iHeight, depthBpp, &params, 0 WIN32PC_ONLY(, ms_DepthBuffer_PreAlpha) DURANGO_ONLY(, ms_DepthBuffer_PreAlpha));
#if RSG_PC
if (VideoResManager::IsSceneScaled() && multisample > 1)
ms_UIDepthBuffer_Resolved = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "UIDepthBuffer Resolved", grcrtDepthBuffer, UIWidth, UIHeight, depthBpp, &params, 0 WIN32PC_ONLY(, ms_UIDepthBuffer_Resolved));
params.Multisample = multisample;
ms_UIDepthBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "UIDepthBuffer", grcrtDepthBuffer, UIWidth, UIHeight, depthBpp, &params, 0 WIN32PC_ONLY(, ms_UIDepthBuffer));
if (VideoResManager::IsSceneScaled())
{
ms_UIDepthBuffer_PreAlpha = multisample > 1 ? ms_UIDepthBuffer_Resolved : ms_UIDepthBuffer;
if (GRCDEVICE.IsReadOnlyDepthAllowed())
{
ms_UIDepthBuffer_Resolved_ReadOnly = textureFactory11.CreateRenderTarget("UIDepthBuffer (read-only)"
,multisample > 1 ? ms_UIDepthBuffer_Resolved->GetTexturePtr() : ms_UIDepthBuffer->GetTexturePtr() , params.Format, DepthReadOnly
WIN32PC_ONLY(, ms_UIDepthBuffer_Resolved_ReadOnly));
}
}
#endif
#if RSG_PC && __D3D11
if (GRCDEVICE.IsReadOnlyDepthAllowed())
{
m_DepthBuffer_PreAlpha_ReadOnly = textureFactory11.CreateRenderTarget("DepthBuffer Pre Alpha (read-only)"
,VideoResManager::IsSceneScaled() ? ms_UIDepthBuffer_PreAlpha->GetTexturePtr() : ms_DepthBuffer_PreAlpha->GetTexturePtr() , params.Format, DepthReadOnly
WIN32PC_ONLY(, m_DepthBuffer_PreAlpha_ReadOnly) DURANGO_ONLY(, m_DepthBuffer_PreAlpha_ReadOnly));
}
#endif
params.Multisample = multisample;
#if !DEVICE_EQAA
params.MultisampleQuality = (u8)multisampleQuality;
#endif
#if RSG_ORBIS
params.EnableFastClear = true;
#endif //RSG_ORBIS
#if RSG_DURANGO
params.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_GBUF
| grcTextureFactory::TextureCreateParams::ESRPHASE_SHADOWS
| grcTextureFactory::TextureCreateParams::ESRPHASE_RAIN_COLLSION_MAP
| grcTextureFactory::TextureCreateParams::ESRPHASE_WATER_REFLECTION
| grcTextureFactory::TextureCreateParams::ESRPHASE_RAIN_UPDATE
| grcTextureFactory::TextureCreateParams::ESRPHASE_LIGHTING
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE
| grcTextureFactory::TextureCreateParams::ESRPHASE_HUD;
params.ESRAMMaxSize = 4 * 1024 * 1024;
#endif
ms_DepthBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "DepthBuffer", grcrtDepthBuffer, iWidth, iHeight, depthBpp, &params, 0 WIN32PC_ONLY(, ms_DepthBuffer) DURANGO_ONLY(, ms_DepthBuffer));
#if RSG_DURANGO
params.ESRAMPhase = 0;
params.ESRAMMaxSize = 0;
#endif
#if RSG_ORBIS
params.EnableFastClear = false;
#endif //RSG_ORBIS
#endif // RSG_PC || RSG_DURANGO || RSG_ORBIS
#if RSG_PC || RSG_DURANGO
#if __D3D11
grcTextureObject *const depthObjectMSAA = ms_DepthBuffer->GetTexturePtr();
if( GRCDEVICE.IsReadOnlyDepthAllowed() )
{
// no need for the copy, we use read-only depth instead
ms_DepthBufferCopy = textureFactory11.CreateRenderTarget("DepthBufferCopy (read-only)", depthObjectMSAA, params.Format, DepthReadOnly WIN32PC_ONLY(, ms_DepthBufferCopy) DURANGO_ONLY(, ms_DepthBufferCopy));
}else
#endif //__D3D11
{
ms_DepthBufferCopy = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "DepthBufferCopy", grcrtDepthBuffer, iWidth, iHeight, depthBpp, &params, 0 WIN32PC_ONLY(, ms_DepthBufferCopy));
}
#endif // RSG_PC || RSG_DURANGO || RSG_ORBIS
#if DEVICE_MSAA
if (multisample)
{
grcTextureFactory::CreateParams ResolvedParams = params;
ResolvedParams.Format = SSAO_OUTPUT_DEPTH ? grctfD32FS8 : grctfNone;
ResolvedParams.UseFloat = true; //Warning: floating point buffer will not store enough precision for far objects (close to 1)
ResolvedParams.Multisample = grcDevice::MSAA_None;
ms_DepthBuffer_Resolved = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "DepthBuffer_Resolved",
SSAO_OUTPUT_DEPTH ? grcrtDepthBuffer : grcrtPermanent, iWidth, iHeight, depthBpp, &ResolvedParams, 0 WIN32PC_ONLY(, ms_DepthBuffer_Resolved));
#if __D3D11
grcTextureObject *const depthObject = ms_DepthBuffer_Resolved->GetTexturePtr();
Assert(depthObject != NULL);
ms_DepthBuffer_Resolved_ReadOnly = textureFactory11.CreateRenderTarget("DepthBuffer_Resolved (read-only)", depthObject, ResolvedParams.Format, DepthReadOnly WIN32PC_ONLY(, ms_DepthBuffer_Resolved_ReadOnly) DURANGO_ONLY(, ms_DepthBuffer_Resolved_ReadOnly));
#endif // __D3D11
}
#endif // DEVICE_MSAA
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
grcTextureFactory::CreateParams depthParams;
depthParams.Format = grctfD32FS8;
m_DepthTargetQuarter = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "Depth Quarter", grcrtDepthBuffer, iWidth/2, iHeight/2, 32, &depthParams, 0 WIN32PC_ONLY(, m_DepthTargetQuarter));
#if __D3D11 && RSG_PC
if( GRCDEVICE.IsReadOnlyDepthAllowed() )
{
grcTextureObject* const pDepthQuarterObject = m_DepthTargetQuarter->GetTexturePtr();
Assert(pDepthQuarterObject != NULL);
m_DepthTargetQuarter_ReadOnly = textureFactory11.CreateRenderTarget("Depth Quarter(read-only)", pDepthQuarterObject, depthParams.Format, DepthReadOnly WIN32PC_ONLY(, m_DepthTargetQuarter_ReadOnly) DURANGO_ONLY(, m_DepthTargetQuarter_ReadOnly));
}else
{
m_DepthTargetQuarter_Copy = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "Depth Quarter (copy)", grcrtDepthBuffer, iWidth/2, iHeight/2, 32, &depthParams, 0 WIN32PC_ONLY(, m_DepthTargetQuarter_Copy));
}
#endif // __D3D11
//R32F Version
depthParams.StereoRTMode = grcDevice::STEREO;
depthParams.Format = grctfR32F;
m_DepthTargetQuarterLinear = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "Depth Quarter Linear", grcrtPermanent, iWidth/2, iHeight/2, 32, &depthParams, 0 WIN32PC_ONLY(, m_DepthTargetQuarterLinear));
#endif //RSG_PC || RSG_DURANGO || RSG_ORBIS
#if DEVICE_MSAA
grcTextureFactory::CreateParams osbparams;
osbparams.Format = grctfA8R8G8B8;
osbparams.Multisample = multisample;
# if RSG_ORBIS
osbparams.EnableFastClear = false;
# endif //RSG_ORBIS
# if DEVICE_EQAA
//osbparams.ForceHardwareResolve = !RSG_ORBIS;
osbparams.Multisample.DisableCoverage();
osbparams.ForceFragmentMask = false;
# else
osbparams.MultisampleQuality = (u8)multisampleQuality;
# endif // DEVICE_EQAA
#if RSG_DURANGO
osbparams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_9 | grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_10;
m_OffscreenBuffers[1] = CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer1", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 0 WIN32PC_ONLY(, m_OffscreenBuffers[1]));
#else
m_OffscreenBuffers[1] = NULL;
#endif
#if DYNAMIC_BB
{
altParams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_LIGHTING_1
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_0
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_1
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_2
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_3
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_4
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_5
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_6
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_7
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_8
| grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_9;
altParams.ESRAMMaxSize = 16 * 1024 * 1024;
ms_AltBackBuffer = CRenderTargets::CreateRenderTarget(RTMEMPOOL_NONE, "AltBackBuffer", grcrtPermanent, iWidth, iHeight, bpp, &altParams, 0 , ms_AltBackBuffer);
if (ms_AltBackBuffer && ms_BackBuffer)
{
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetAltTarget(ms_AltBackBuffer);
static_cast<grcRenderTargetDurango*>(ms_BackBuffer)->SetUseAltTestFunc(CRenderTargets::UseAltBackBufferTest);
}
}
#endif
#if RSG_DURANGO
osbparams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_HUD;
#endif
osbparams.Multisample = multisample;
#if DEVICE_EQAA
osbparams.ForceFragmentMask = multisample.NeedFmask();
osbparams.EnableHighQualityResolve = true;
#endif
m_OffscreenBuffers[2] = CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer2", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 0 WIN32PC_ONLY(, m_OffscreenBuffers[2]));
#if RSG_DURANGO
osbparams.ESRAMPhase = 0;
#endif
osbparams.Multisample = 0;
#if __DEV
m_OffscreenBuffers[0] = CreateRenderTarget(RTMEMPOOL_NONE, "UI Buffer", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 0 WIN32PC_ONLY(, m_OffscreenBuffers[0]));
#else
m_OffscreenBuffers[0] = NULL;
#endif
osbparams.Multisample = multisample;
m_OffscreenBuffers[3] = NULL;
#if RSG_PC
if (VideoResManager::IsSceneScaled())
m_OffscreenBuffers[3] = CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer3", grcrtPermanent, iWidth , iHeight, 32, &osbparams, 0 WIN32PC_ONLY(, m_OffscreenBuffers[3]));
#endif
grcTextureFactory::CreateParams resolvedParams = osbparams;
resolvedParams.Multisample = grcDevice::MSAA_None;
#if !DEVICE_EQAA
resolvedParams.MultisampleQuality = 0;
#endif
if (!multisample)
{
if (m_OffscreenBuffersResolved[1]) {delete m_OffscreenBuffersResolved[1]; m_OffscreenBuffersResolved[1] = NULL;}
if (m_OffscreenBuffersResolved[2]) {delete m_OffscreenBuffersResolved[2]; m_OffscreenBuffersResolved[2] = NULL;}
if (m_OffscreenBuffersResolved[3]) {delete m_OffscreenBuffersResolved[3]; m_OffscreenBuffersResolved[3] = NULL;}
}
m_OffscreenBuffersResolved[0] = NULL;
#if RSG_DURANGO
resolvedParams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_10 | grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_11;
#endif
m_OffscreenBuffersResolved[1] = multisample ? // m_OffscreenBuffers[1]->GetMSAA() ?
CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer1_Resolved", grcrtPermanent, iWidth, iHeight, 32, &resolvedParams, 0 WIN32PC_ONLY(, m_OffscreenBuffersResolved[1]))
: NULL;
#if RSG_DURANGO
resolvedParams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_HUD;
#endif
m_OffscreenBuffersResolved[2] = m_OffscreenBuffers[2]->GetMSAA() ?
CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer2_Resolved", grcrtPermanent, UIWidth, UIHeight, 32, &resolvedParams, 0 WIN32PC_ONLY(, m_OffscreenBuffersResolved[2]))
: NULL;
#if RSG_DURANGO
resolvedParams.ESRAMPhase = grcTextureFactory::TextureCreateParams::ESRPHASE_DRAWSCENE_11;
m_OffscreenBuffersResolved[3] = multisample ?
CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer1X_Resolved", grcrtPermanent, UIWidth, UIHeight, 32, &resolvedParams, 0 WIN32PC_ONLY(, m_OffscreenBuffersResolved[3]))
: NULL;
m_OffscreenBuffers[3] = m_OffscreenBuffers[1];
#else
m_OffscreenBuffersResolved[3] = NULL;
#if RSG_PC
if (VideoResManager::IsSceneScaled() && multisample)
m_OffscreenBuffersResolved[3] = CreateRenderTarget(RTMEMPOOL_NONE, "OffscreenBuffer1X_Resolved", grcrtPermanent, iWidth , iHeight, 32, &resolvedParams, 0 WIN32PC_ONLY(, m_OffscreenBuffersResolved[3]));
#endif
#endif
#endif // DEVICE_MSAA
#if __D3D11
grcRenderTargetD3D11 *const depthCopy = static_cast<grcRenderTargetD3D11*>( GRCDEVICE.IsReadOnlyDepthAllowed() ? ms_DepthBuffer : ms_DepthBufferCopy );
grcTextureFormat eStencilFormat = grctfX32S8;
ms_DepthBuffer_Stencil = textureFactory11.CreateRenderTarget( "StencilBuffer", depthObjectMSAA, eStencilFormat, DepthStencilRW WIN32PC_ONLY(, ms_DepthBuffer_Stencil) );
# if RSG_PC
static_cast<grcRenderTargetDX11*>(ms_DepthBuffer)->SetSecondaryTextureView(ms_DepthBuffer_Stencil->GetTextureView());
# endif
ms_DepthBufferCopy_Stencil = textureFactory11.CreateRenderTarget( "StencilBufferCopy",
depthCopy->GetTexturePtr(), eStencilFormat, DepthStencilRW WIN32PC_ONLY(, ms_DepthBufferCopy_Stencil) );
ms_DepthBuffer_ReadOnly = textureFactory11.CreateRenderTarget( "DepthBufferReadOnly", depthObjectMSAA, params.Format, DepthStencilReadOnly WIN32PC_ONLY(, ms_DepthBuffer_ReadOnly) );
#if RSG_PC
ms_DepthBuffer_ReadOnlyDepth = textureFactory11.CreateRenderTarget( "DepthBufferReadOnlyDepth", depthObjectMSAA, params.Format, DepthReadOnly WIN32PC_ONLY(, ms_DepthBuffer_ReadOnlyDepth) );
#endif
# if DEVICE_EQAA
if (multisample && multisample.m_uFragments==1)
{
textureFactory11.EnableMultisample(ms_DepthBuffer_Stencil);
textureFactory11.EnableMultisample(ms_DepthBufferCopy_Stencil);
textureFactory11.EnableMultisample(ms_DepthBuffer_ReadOnly);
}
# endif // DEVICE_EQAA
#endif // __D3D11
#if RSG_ORBIS
grcTextureFactoryGNM& textureFactoryGNM = static_cast<grcTextureFactoryGNM&>(grcTextureFactoryGNM::GetInstance());
grcTextureFormat eStencilFormat = grctfX24G8;
ms_DepthBuffer_Stencil = textureFactoryGNM.CreateRenderTarget( "StencilBuffer", ms_DepthBuffer, eStencilFormat );
#endif
#if __PPU
#if PSN_USE_FP16
grcTextureFactory::CreateParams params0;
params0.Multisample = 0;
params0.HasParent = true;
params0.Parent = NULL;
params0.UseFloat = true;
params0.InTiledMemory = true;
params0.IsSwizzled = false;
params0.EnableCompression = false;
params0.InLocalMemory = true;
params0.Format = grctfA16B16G16R16F;
params0.IsSRGB = false;
ms_BackBuffer = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P10240_TILED_LOCAL_COMPMODE_DISABLED, "BackBuffer FP16", grcrtPermanent, iWidth, iHeight, 64, &params0,0);
ms_BackBuffer->AllocateMemoryFromPool();
#else
ms_BackBuffer = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P10240_TILED_LOCAL_COMPMODE_DISABLED, "BackBuffer", grcrtPermanent, iWidth, iHeight, 32, &params,0);
ms_BackBuffer->AllocateMemoryFromPool();
#endif // PSN_USE_FP16
grcTextureFactory::CreateParams osbparams;
osbparams.Format = grctfA8R8G8B8;
m_OffscreenBuffers[3] = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2, "OffscreenBuffer3", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 6);
m_OffscreenBuffers[2] = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2, "OffscreenBuffer2", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 6);
m_OffscreenBuffers[1] = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2, "OffscreenBuffer1", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 6);
m_OffscreenBuffers[0] = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2, "UI Buffer", grcrtPermanent, UIWidth, UIHeight, 32, &osbparams, 6);
m_OffscreenBuffers[3]->AllocateMemoryFromPool();
m_OffscreenBuffers[2]->AllocateMemoryFromPool();
m_OffscreenBuffers[1]->AllocateMemoryFromPool();
m_OffscreenBuffers[0]->AllocateMemoryFromPool();
params.Format = grctfA8R8G8B8;
params.UseFloat = false;
params.EnableCompression = true;
params.UseHierZ = true;
ms_DepthBuffer = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR_BBUFFER, "DepthBuffer", grcrtDepthBuffer, iWidth, iHeight, 32, NULL, 8);
ms_DepthBuffer->AllocateMemoryFromPool();
params.InTiledMemory = true;
ms_PatchedDepthBuffer = ((grcRenderTargetGCM*)ms_DepthBuffer)->CreatePrePatchedTarget(false);
//640x360 Depth Buffer
params.Format = grctfD24S8;
params.EnableCompression = true;
params.UseHierZ = true;
params.Multisample = 0;
params.CreateAABuffer = false;
m_DepthTargetQuarter = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P2560_TILED_LOCAL_COMPMODE_Z32_SEPSTENCIL_REGULAR, "Depth Quarter", grcrtDepthBuffer, iWidth/2, iHeight/2, 32, &params, 0);
//m_DepthTargetQuarter->AllocateMemoryFromPool(); // This happens in CRenderer::Init()
params.Format = grctfA8R8G8B8;
params.EnableCompression = false;
params.UseHierZ = true;
params.Multisample = 0;
params.CreateAABuffer = false;
params.UseCustomZCullAllocation = USE_DEPTHBUFFER_ZCULL_SHARING ? true : false; // We force this target to share zcull with the back buffer once it's allocated
m_OffscreenDepthBuffer = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P5120_TILED_LOCAL_COMPMODE_DISABLED_2, "Offscreen Depth", grcrtDepthBuffer, iWidth, iHeight, 32, &params, 5);
//m_OffscreenDepthBuffer->AllocateMemoryFromPool(); // This happens in CRenderer::Init()
//m_OffscreenDepthBufferAlias = ((grcRenderTargetGCM*)m_OffscreenDepthBuffer)->CreatePrePatchedTarget(false); // This happens in CRenderer::Init()
params.UseCustomZCullAllocation = false; // Turn this off now so it doesn't create havoc down below
//R32F Version
params.Format = grctfR32F;
params.UseHierZ = false;
params.EnableCompression = true;
m_DepthTargetQuarterPadding = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P2560_TILED_LOCAL_COMPMODE_DISABLED, "Depth Quarter Padding", grcrtPermanent, 640, 360, 32, &params, 5);
m_DepthTargetQuarterLinear = CRenderTargets::CreateRenderTarget(PSN_RTMEMPOOL_P2560_TILED_LOCAL_COMPMODE_DISABLED, "Depth Quarter Linear", grcrtPermanent, iWidth/2, iHeight/2, 32, &params, 5);
//m_DepthTargetQuarterPadding->AllocateMemoryFromPool(); // This happens in Water.cpp
//m_DepthTargetQuarterLinear->AllocateMemoryFromPool(); // This happens in Water.cpp
// Stencil/Zfar cull stateblocks
{
grcBlendStateDesc BSDesc;
BSDesc.AlphaTestEnable = false;
BSDesc.BlendRTDesc[0].BlendEnable = false;
BSDesc.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_NONE;
ms_Refresh_BS = grcStateBlock::CreateBlendState(BSDesc);
}
// Stencil cull refresh stateblocks
{
grcDepthStencilStateDesc SDDesc;
SDDesc.DepthEnable = false;
SDDesc.DepthWriteMask = false;
SDDesc.DepthFunc = grcRSV::CMP_LESS;//DEFAULT
SDDesc.StencilEnable = true;
SDDesc.StencilReadMask = 0xFF; //DEFAULT
SDDesc.StencilWriteMask = 0xFF; //DEFAULT
SDDesc.FrontFace.StencilFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilPassOp = grcRSV::STENCILOP_INVERT;
SDDesc.FrontFace.StencilFunc = grcRSV::CMP_LESS;
SDDesc.BackFace = SDDesc.FrontFace;
ms_RefreshStencil_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
SDDesc.DepthEnable = true;
ms_RefreshStencilPreserveZFar_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
}
// Stencil cull + ZFAR refresh stateblocks
{
grcDepthStencilStateDesc SDDesc;
SDDesc.DepthEnable = true;//DEFAULT
SDDesc.DepthWriteMask = true;//DEFAULT
SDDesc.DepthFunc = rage::FixupDepthDirection(grcRSV::CMP_LESS);//DEFAULT
SDDesc.StencilEnable = true;
SDDesc.StencilReadMask = 0x00;
SDDesc.StencilWriteMask = 0xFF; //DEFAULT
SDDesc.FrontFace.StencilFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP; //DEFAULT
SDDesc.FrontFace.StencilPassOp = grcRSV::STENCILOP_INVERT;
SDDesc.FrontFace.StencilFunc = grcRSV::CMP_ALWAYS;//DEFAULT
SDDesc.BackFace = SDDesc.FrontFace;
ms_RefreshStencilZFar_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
}
// ZFAR refresh stateblocks
{
grcDepthStencilStateDesc SDDesc;
SDDesc.DepthEnable = true;
SDDesc.DepthWriteMask = true;
SDDesc.DepthFunc = rage::FixupDepthDirection(grcRSV::CMP_LESS);
SDDesc.StencilEnable = false;
ms_RefreshZFar_L_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
SDDesc.DepthFunc = rage::FixupDepthDirection(grcRSV::CMP_GREATEREQUAL);
ms_RefreshZFar_G_DS = grcStateBlock::CreateDepthStencilState(SDDesc);
}
#endif // __PPU
#if GTA_REPLAY
#if REPLAY_USE_PER_BLOCK_THUMBNAILS
{
grcTextureFactory::TextureCreateParams replayThumbnailParams(grcTextureFactory::TextureCreateParams::SYSTEM,
grcTextureFactory::TextureCreateParams::LINEAR, grcsRead|grcsWrite, NULL, grcTextureFactory::TextureCreateParams::RENDERTARGET,
grcTextureFactory::TextureCreateParams::MSAA_NONE);
for(u32 i=0; i<REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE; i++)
{
char name[256];
sprintf(name, "Replay thumbnail %d", i);
BANK_ONLY(grcTexture::SetCustomLoadName(name);)
ms_ReplayThumbnailTex[i] = grcTextureFactory::GetInstance().Create( CReplayThumbnail::GetThumbnailWidth(), CReplayThumbnail::GetThumbnailHeight(), grctfA8R8G8B8, NULL, 1U, &replayThumbnailParams);
BANK_ONLY(grcTexture::SetCustomLoadName(NULL);)
ms_ReplayThumbnailRT[i] = grcTextureFactory::GetInstance().CreateRenderTarget(name, ms_ReplayThumbnailTex[i]->GetTexturePtr());
}
}
#endif // REPLAY_USE_PER_BLOCK_THUMBNAILS
#endif // GTA_REPLAY
//Copy depth state
{
grcDepthStencilStateDesc dssDesc;
dssDesc.DepthFunc = grcRSV::CMP_ALWAYS;
dssDesc.DepthWriteMask = TRUE;
dssDesc.DepthEnable = TRUE;
ms_CopyDepth_DS = grcStateBlock::CreateDepthStencilState(dssDesc, "copyDepthDSS");
}
#if __PS3
{
grcDepthStencilStateDesc dssDesc;
dssDesc.DepthFunc = grcRSV::CMP_ALWAYS;
dssDesc.DepthWriteMask = TRUE;
dssDesc.DepthEnable = TRUE;
dssDesc.StencilEnable = TRUE;
dssDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_REPLACE;
dssDesc.FrontFace.StencilFailOp = grcRSV::STENCILOP_REPLACE;
dssDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_REPLACE;
dssDesc.FrontFace.StencilPassOp = grcRSV::STENCILOP_REPLACE;
dssDesc.FrontFace.StencilFunc = grcRSV::CMP_ALWAYS;
dssDesc.BackFace = dssDesc.FrontFace;
ms_CopyDepthClearStencil_DS = grcStateBlock::CreateDepthStencilState(dssDesc, "copyDepthClearStencilDSS");
}
#endif
//Copy with Stencil Mask
{
grcDepthStencilStateDesc dssDesc;
dssDesc.DepthFunc = grcRSV::CMP_NEVER;
dssDesc.DepthWriteMask = FALSE;
dssDesc.DepthEnable = FALSE;
dssDesc.StencilEnable = TRUE;
dssDesc.StencilReadMask = DEFERRED_MATERIAL_CLEAR;
dssDesc.StencilWriteMask = 0;
dssDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP;
dssDesc.FrontFace.StencilFailOp = grcRSV::STENCILOP_KEEP;
dssDesc.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP;
dssDesc.FrontFace.StencilPassOp = grcRSV::STENCILOP_KEEP;
dssDesc.FrontFace.StencilFunc = grcRSV::CMP_EQUAL;
dssDesc.BackFace = dssDesc.FrontFace;
ms_CopyColorStencilMask_DS = grcStateBlock::CreateDepthStencilState(dssDesc, "copyColorStencilMaskDSS");
}
#if RSG_PC
if (GRCDEVICE.UsingMultipleGPUs())
{
grcTextureFactory::TextureCreateParams TextureParams(
grcTextureFactory::TextureCreateParams::SYSTEM,
grcTextureFactory::TextureCreateParams::LINEAR, grcsRead|grcsWrite, NULL,
grcTextureFactory::TextureCreateParams::RENDERTARGET,
grcTextureFactory::TextureCreateParams::MSAA_NONE);
ms_BackBufferTexForPause = grcTextureFactory::GetInstance().Create(iWidth, iHeight, grctfA16B16G16R16F, NULL, 1, &TextureParams);
ms_BackBufferRTForPause = grcTextureFactory::GetInstance().CreateRenderTarget("BackBufferRT for Pause", ms_BackBufferTexForPause->GetTexturePtr());
}
#endif //RSG_PC
}
#if RSG_PC
void CRenderTargets::DeviceLost()
{
if (ms_Initialized)
{
DeAllocateRenderTargets();
}
}
void CRenderTargets::DeviceReset()
{
if (ms_Initialized)
{
AllocateRenderTargets();
}
}
#endif //RSG_PC
void CRenderTargets::DeAllocateRenderTargets()
{
RAGE_TRACK(CRenderTargets);
RAGE_TRACK(DeAllocateRenderTargets);
USE_MEMBUCKET(MEMBUCKET_RENDER);
#if RSG_PC || __PPU || RSG_DURANGO || RSG_ORBIS
#if RSG_PC || RSG_DURANGO
if (ms_BackBuffer) {delete ms_BackBuffer; ms_BackBuffer = NULL;}
if (ms_BackBufferCopy) {
delete ms_BackBufferCopy; ms_BackBufferCopy = NULL;
#if DEVICE_MSAA
ms_BackBuffer_Resolved = NULL;
#endif
}
if (ms_DepthBuffer) {delete ms_DepthBuffer; ms_DepthBuffer = NULL;}
if (ms_DepthBufferCopy) {delete ms_DepthBufferCopy; ms_DepthBufferCopy = NULL;}
if (m_DepthTargetQuarter) {delete m_DepthTargetQuarter; m_DepthTargetQuarter = NULL;}
if (m_DepthTargetQuarterLinear) {delete m_DepthTargetQuarterLinear; m_DepthTargetQuarterLinear = NULL;}
if (ms_DepthBuffer_PreAlpha) {delete ms_DepthBuffer_PreAlpha; ms_DepthBuffer_PreAlpha = NULL;}
#if RSG_PC && __D3D11
if (m_DepthTargetQuarter_ReadOnly) { delete m_DepthTargetQuarter_ReadOnly; m_DepthTargetQuarter_ReadOnly = NULL;}
if (m_DepthTargetQuarter_Copy) { delete m_DepthTargetQuarter_Copy; m_DepthTargetQuarter_Copy = NULL;}
if (m_DepthBuffer_PreAlpha_ReadOnly) { delete m_DepthBuffer_PreAlpha_ReadOnly; m_DepthBuffer_PreAlpha_ReadOnly = NULL;}
if (ms_UIDepthBuffer) {delete ms_UIDepthBuffer; ms_UIDepthBuffer = NULL;}
if (ms_UIDepthBuffer_Resolved_ReadOnly) {delete ms_UIDepthBuffer_Resolved_ReadOnly; ms_UIDepthBuffer_Resolved_ReadOnly = NULL;}
#endif // RSG_PC && __D3D11
if (m_OffscreenBuffers[0]) {delete m_OffscreenBuffers[0]; m_OffscreenBuffers[0] = NULL;}
if (m_OffscreenBuffers[1]) { DURANGO_ONLY(delete m_OffscreenBuffers[1];) m_OffscreenBuffers[1] = NULL;}
if (m_OffscreenBuffers[2]) {delete m_OffscreenBuffers[2]; m_OffscreenBuffers[2] = NULL;}
if (m_OffscreenBuffers[3]) {delete m_OffscreenBuffers[3]; m_OffscreenBuffers[3] = NULL;}
// Shared Render Targets
LOW_RES_VOLUME_LIGHT_ONLY( if (m_volumeOffscreenBuffer) { DURANGO_ONLY(delete m_volumeOffscreenBuffer;) m_volumeOffscreenBuffer = NULL;} )
LOW_RES_VOLUME_LIGHT_ONLY( if (m_volumeReconstructionBuffer) { DURANGO_ONLY(delete m_volumeReconstructionBuffer;) m_volumeReconstructionBuffer = NULL;} )
#endif //RSG_PC,RSG_DURANGO
#if GTA_REPLAY
#if REPLAY_USE_PER_BLOCK_THUMBNAILS
{
for(u32 i=0; i<REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE; i++)
{
if(ms_ReplayThumbnailTex[i]) { ms_ReplayThumbnailTex[i]->Release(); ms_ReplayThumbnailTex[i] = NULL; }
if(ms_ReplayThumbnailRT[i]) { delete ms_ReplayThumbnailRT[i]; ms_ReplayThumbnailRT[i] = NULL; }
}
}
#endif // REPLAY_USE_PER_BLOCK_THUMBNAILS
#endif
#if __D3D11 || RSG_ORBIS
if (ms_BackBufferCopy != ms_BackBuffer)
delete ms_BackBufferCopy;
ms_BackBufferCopy = NULL;
if (ms_DepthBuffer_Stencil) {delete ms_DepthBuffer_Stencil; ms_DepthBuffer_Stencil = NULL;}
if (ms_DepthBuffer_Resolved) {delete ms_DepthBuffer_Resolved; ms_DepthBuffer_Resolved = NULL;}
#endif
#if __D3D11
if (ms_DepthBufferCopy_Stencil) {delete ms_DepthBufferCopy_Stencil; ms_DepthBufferCopy_Stencil = NULL;}
if (ms_DepthBuffer_ReadOnly) {delete ms_DepthBuffer_ReadOnly; ms_DepthBuffer_ReadOnly = NULL;}
#if RSG_PC
if (ms_DepthBuffer_ReadOnlyDepth) {delete ms_DepthBuffer_ReadOnlyDepth; ms_DepthBuffer_ReadOnlyDepth = NULL;}
#endif
// if (ms_CopyDepth_DS) {delete ms_CopyDepth_DS; ms_CopyDepth_DS = NULL;}
#endif //__D3D11
#endif //RSG_PC || __PPU || RSG_DURANGO || RSG_ORBIS
#if RSG_PC
if (ms_BackBufferTexForPause) {ms_BackBufferTexForPause->Release(); ms_BackBufferTexForPause = NULL;}
if (ms_BackBufferRTForPause) {delete ms_BackBufferRTForPause; ms_BackBufferRTForPause = NULL;}
#endif //RSG_PC
}
struct RestoreHiStencil
{
XENON_ONLY(DWORD hasHiStencilEnabled; )
RestoreHiStencil(){
XENON_ONLY( GRCDEVICE.GetCurrent()->GetRenderState( D3DRS_HISTENCILENABLE, &hasHiStencilEnabled) );
}
~RestoreHiStencil(){
XENON_ONLY( GRCDEVICE.GetCurrent()->SetRenderState( D3DRS_HISTENCILENABLE, hasHiStencilEnabled ) );
}
};
void CRenderTargets::LockSceneRenderTargets(bool lockDepth)
{
RestoreHiStencil restore;
// on PSN, we will render to a rendertarget so we have easy access to the screen contents
Assertf(!ms_RenderTargetActive, "Attemping to lock scene rt when already active!");
grcRenderTarget *fbRT = CRenderTargets::GetBackBuffer();
grcRenderTarget *depthRT = lockDepth? CRenderTargets::GetDepthBuffer() : NULL;
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
ms_RenderTargetActive = true;
}
//
// Purpose: As BindCustomRenderTarget, but works for cases when we need to bind the same resource in a shader
// Under DX11 the copy is actually a read-only view of the original depth buffer
//
void CRenderTargets::LockSceneRenderTargets_DepthCopy()
{
#if RSG_PC || RSG_DURANGO
grcRenderTarget *fbRT = CRenderTargets::GetBackBuffer();
#if __D3D11
grcRenderTarget *depthRT = (GRCDEVICE.IsReadOnlyDepthAllowed()) ? CRenderTargets::GetDepthBuffer_ReadOnly() : CRenderTargets::GetDepthBufferCopy();
#else
grcRenderTarget *depthRT = CRenderTargets::GetDepthBufferCopy();
#endif
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
ms_RenderTargetActive = true;
#else
LockSceneRenderTargets();
#endif
}
void CRenderTargets::UnlockSceneRenderTargets()
{
RestoreHiStencil restore;
Assertf(ms_RenderTargetActive, "Render target release request when not active");
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = false;
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
ms_RenderTargetActive = false;
}
void CRenderTargets::LockUIRenderTargets()
{
//not sure if required on any other platforms
#if RSG_DURANGO || RSG_ORBIS || RSG_PC || RSG_PS3
grcTextureFactory::GetInstance().LockRenderTarget(0, CRenderTargets::GetUIBackBuffer(), CRenderTargets::GetUIDepthBuffer(true));
#endif
}
void CRenderTargets::UnlockUIRenderTargets(bool realize)
{
#if RSG_XENON
(void)realize;
#endif
#if RSG_DURANGO || RSG_ORBIS || RSG_PC || RSG_PS3
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = realize;
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
#endif
}
#if __D3D11
void CRenderTargets::LockUIRenderTargetsReadOnlyDepth()
{
grcTextureFactory::GetInstance().LockRenderTarget(0, CRenderTargets::GetUIBackBuffer(), CRenderTargets::GetDepthBufferResolved_ReadOnly());
}
#endif // __D3D11
grcRenderTarget* CRenderTargets::CreateRenderTarget(RTMemPoolID memPoolID, const char *name, grcRenderTargetType type, int width, int height, int bitsPerPixel, rage::grcTextureFactory::CreateParams *_params, u8 poolHeap, grcRenderTarget* originalTarget)
{
grcTextureFactory::CreateParams params;
if (_params)
params = *_params;
u16 poolId = (memPoolID == RTMEMPOOL_NONE ? kRTPoolIDInvalid : GetRenderTargetPoolID(memPoolID));
// don't want unpooled render targets, force kRTPoolIDAuto if needed
if (poolId == kRTPoolIDInvalid
XENON_ONLY(&& params.IsResolvable == true)) // if it's not resolvable we don't care
{
poolId = kRTPoolIDAuto;
}
params.PoolID = poolId;
params.PoolHeap = poolHeap;
// do not allocate from pool straight away unless no pool is specified
params.AllocateFromPoolOnCreate = (params.PoolID==kRTPoolIDAuto ? true : false);
grcRenderTarget *rt = grcTextureFactory::GetInstance().CreateRenderTarget(name, type, width, height, bitsPerPixel, &params, originalTarget);
Assert(rt);
return(rt);
}
grcRenderTarget* CRenderTargets::CreateRenderTarget(const char* name, grcTextureObject* sourceTexture, grcRenderTarget* originalTexture)
{
// Actually just create another render target that points at another one...
grcRenderTarget *rt = grcTextureFactory::GetInstance().CreateRenderTarget(name, sourceTexture, originalTexture);
Assert(rt);
return(rt);
}
void CRenderTargets::FreeRenderTargetMemPool()
{
for (s32 i=0; i<RTMEMPOOL_SIZE; i++)
{
if(ms_RenderTargetMemPoolArray[i])
grcRenderTargetPoolMgr::DestroyPool( ms_RenderTargetMemPoolArray[i] );
ms_RenderTargetMemPoolArray[i] = kRTPoolIDInvalid;
}
}
void CRenderTargets::DownsampleDepth()
{
#if __ASSERT
Assertf(g_CachedDownsampleDepthThreadID == -1 || ((int)g_RenderThreadIndex) == g_CachedDownsampleDepthThreadID, "Different Sub render threads are trying to Downsample Depth. Caching state logic should be updated. Cached Thread ID = %d, Current Thread ID = %u", g_CachedDownsampleDepthThreadID, g_RenderThreadIndex);
g_CachedDownsampleDepthThreadID = (int)g_RenderThreadIndex;
#endif //__ASSERT
if(!ms_DepthDownsampleReady)
{
GRC_ALLOC_SCOPE_AUTO_PUSH_POP();
grcCompositeRenderTargetHelper::DownsampleParams downsampleParams;
downsampleParams.srcDepth = MSAA_ONLY(GRCDEVICE.GetMSAA() ? CRenderTargets::GetDepthResolved() :) CRenderTargets::GetDepthBuffer();
downsampleParams.dstDepth = m_DepthTargetQuarter;
PS3_ONLY(downsampleParams.srcPatchedDepth = CRenderTargets::GetDepthBufferAsColor();)
grcCompositeRenderTargetHelper::DownsampleDepth(downsampleParams);
ms_DepthDownsampleReady = true;
}
}
void CRenderTargets::ResetRenderThreadInfo()
{
SetDownsampleDepthFlag(false);
ASSERT_ONLY(g_CachedDownsampleDepthThreadID = -1;)
}
//////////////////////////////////////////////////////////////////////////
#if __BANK
//////////////////////////////////////////////////////////////////////////
static atArray<const char*> s_RenderTargetNames;
static atArray<const char*> s_RenderTargetMemPoolNames;
static bkCombo* s_RenderTargetNamesCombo = NULL;
static int s_RenderTargetCount = 0;
static int s_RenderTargetIndex = 0;
static int s_RenderTargetPoolIndex = 0;
static int s_RenderTargetPoolCount = 0;
static Vector4 s_RenderTargetPos(200.0f, 200.0f, 1.0f, 200.0f); // xy = pos, z = aspect, w = size
static Vector4 s_RenderTargetPosAndSize; // xy=pos, zw=size (final coords)
static Vector4 s_RenderTargetUv(0.0f, 0.0f, 1.0f, 0.0f);
static int s_RenderTargetMip = 0;
static float s_RenderTargetBrightness = 1.0f;
static float s_RenderTargetOpacity = 1.0f;
static float s_RenderTargetDepthNearClip = 0.5f;
static float s_RenderTargetDepthFarClip = 4000.0f;
static float s_RenderTargetDepthNearClipGBuffer = 0.5f; // display-only
static float s_RenderTargetDepthFarClipGBuffer = 4000.0f; // display-only
static float s_RenderTargetDepthMin = 0.0f;
static float s_RenderTargetDepthMax = 4000.0f;
static bool s_bRenderTargetFullScreen = false;
static bool s_bRenderTargetShowInfo = true;
static bool s_bRenderTargetVisualise = false;
static bool s_bRenderTargetRelativeAspect = true;
static bool s_bRenderTargetNativeRes = false;
static bool s_bRenderTargetFlipHoriz = false; // for MIRROR_RT
static bool s_bRenderTargetWaterDraw = false; // water draw overlay
static Vector4 s_RenderTargetBounds = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
static bool s_bRenderTargetCentre = true;
static bool s_bRenderTargetRed = true;
static bool s_bRenderTargetGreen = true;
static bool s_bRenderTargetBlue = true;
static bool s_bRenderTargetAlpha = false;
# if DEVICE_EQAA
static int s_bRenderTargetAAMode = 0;
static int s_bRenderTargetSampleIndex = 0;
static const char *s_RenderTargetAAModeNames[] =
{
"Default",
"AA Sample Id",
"AA Fragment Id",
"AA FMASK",
"Resolve EQAA",
};
# endif //DEVICE_EQAA
bool CRenderTargets::IsShowingRenderTarget()
{
return s_RenderTargetIndex > 0;
}
bool CRenderTargets::IsShowingRenderTarget(const char* name)
{
if (s_RenderTargetIndex < 0 || s_RenderTargetIndex >= s_RenderTargetNames.GetCount())
{
return false;
}
if (s_RenderTargetNames[s_RenderTargetIndex] == NULL)
{
return false;
}
return stricmp(s_RenderTargetNames[s_RenderTargetIndex], name) == 0;
}
bool CRenderTargets::IsShowingRenderTargetWaterDraw()
{
return s_bRenderTargetWaterDraw;
}
Vec2V_Out CRenderTargets::ShowRenderTargetGetWindowMin()
{
return Vec2V(s_RenderTargetPosAndSize.x, s_RenderTargetPosAndSize.y);
}
Vec2V_Out CRenderTargets::ShowRenderTargetGetWindowMax()
{
return Vec2V(s_RenderTargetPosAndSize.x + s_RenderTargetPosAndSize.z, s_RenderTargetPosAndSize.y + s_RenderTargetPosAndSize.w);
}
void CRenderTargets::ShowRenderTarget(const char* name)
{
s_RenderTargetIndex = 0;
for (int i = 0; i < s_RenderTargetNames.size(); i++)
{
if (stricmp(s_RenderTargetNames[i], name) == 0)
{
s_RenderTargetIndex = i;
break;
}
}
}
void CRenderTargets::ShowRenderTargetOpacity(float opacity)
{
s_RenderTargetOpacity = opacity;
}
void CRenderTargets::ShowRenderTargetBrightness(float brightness)
{
s_RenderTargetBrightness = brightness;
}
void CRenderTargets::ShowRenderTargetNativeRes(bool nativeRes, bool flipHoriz, bool waterDraw)
{
s_bRenderTargetNativeRes = nativeRes;
s_bRenderTargetFlipHoriz = flipHoriz;
s_bRenderTargetWaterDraw = waterDraw;
}
void CRenderTargets::ShowRenderTargetSetBounds(float x, float y, float w, float h)
{
s_RenderTargetBounds = Vector4(x, y, w, h);
}
void CRenderTargets::ShowRenderTargetFullscreen(bool fullscreen)
{
s_bRenderTargetFullScreen = fullscreen;
}
int& CRenderTargets::ShowRenderTargetGetMipRef()
{
return s_RenderTargetMip;
}
void CRenderTargets::ShowRenderTargetInfo(bool show)
{
s_bRenderTargetShowInfo = show;
}
void CRenderTargets::ShowRenderTargetReset()
{
s_RenderTargetIndex = 0;
s_RenderTargetOpacity = 1.0f;
s_RenderTargetBrightness = 1.0f;
s_bRenderTargetNativeRes = false;
s_bRenderTargetFlipHoriz = false;
s_bRenderTargetWaterDraw = false;
s_RenderTargetBounds = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
s_bRenderTargetFullScreen = false;
s_bRenderTargetShowInfo = true;
s_bRenderTargetVisualise = false;
}
void CRenderTargets::DisplayRenderTargetOverlaps()
{
#if __PS3 || __XENON
Displayf("\nRender target overlaps (not counting MIP maps): [PoolID, HeapID]\n");
for (int nIndexA = 0; nIndexA < grcTextureFactory::GetRenderTargetCount(); ++nIndexA)
{
grcRenderTarget* pTargetA = grcTextureFactory::GetRenderTarget(nIndexA);
// If TargetA isn't resolvable then we don't care about overlaps
XENON_ONLY( if (static_cast<rage::grcRenderTargetXenon*>(pTargetA)->GetTexturePtr() == NULL) continue );
bool bNoOverlap = true;
u32 nStartAddressA = PS3_SWITCH( static_cast<grcRenderTargetGCM*>(pTargetA)->GetMemoryOffset(), 0 );
u32 nSizeA = PS3_SWITCH( pTargetA->GetPhysicalSize(), 0 );
XENON_ONLY( XGGetTextureLayout( static_cast<grcRenderTargetXenon*>(pTargetA)->GetTexturePtr(), &nStartAddressA, &nSizeA, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0 ) );
u32 nEndAddressA = nStartAddressA + nSizeA;
Displayf("[%d,%d] \"%s\" (0x%x - 0x%x) overlaps with:", pTargetA->GetPoolID(), pTargetA->GetPoolHeap(), pTargetA->GetName(), nStartAddressA, nEndAddressA);
for (int nIndexB = 0; nIndexB < grcTextureFactory::GetRenderTargetCount(); ++nIndexB)
{
if ( nIndexA == nIndexB )
continue;
grcRenderTarget* pTargetB = grcTextureFactory::GetRenderTarget(nIndexB);
// If TargetB isn't resolvable then we don't care about overlaps
XENON_ONLY( if (static_cast<rage::grcRenderTargetXenon*>(pTargetB)->GetTexturePtr() == NULL) continue );
u32 nStartAddressB = PS3_SWITCH( static_cast<grcRenderTargetGCM*>(pTargetB)->GetMemoryOffset(), 0 );
u32 nSizeB = PS3_SWITCH( pTargetB->GetPhysicalSize(), 0 );
XENON_ONLY( XGGetTextureLayout( static_cast<grcRenderTargetXenon*>(pTargetB)->GetTexturePtr(), &nStartAddressB, &nSizeB, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0 ) );
u32 nEndAddressB = nStartAddressB + nSizeB;
// If there's an overlap
if ( ( (nStartAddressA >= nStartAddressB) && (nStartAddressA < nEndAddressB) ) ||
( (nEndAddressA > nStartAddressB) && (nEndAddressA <= nEndAddressB) ) ||
( (nStartAddressA <= nStartAddressB) && (nEndAddressA > nStartAddressB) ) )
{
bNoOverlap = false;
Displayf("\t[%d,%d] \"%s\" (0x%x - 0x%x)", pTargetB->GetPoolID(), pTargetB->GetPoolHeap(), pTargetB->GetName(), nStartAddressB, nEndAddressB);
}
}
Displayf( bNoOverlap ? "\tNONE!\n" : "");
}
#endif // __PS3 || __XENON
}
void CRenderTargets::DumpRenderTargets()
{
#if !__WIN32PC && !__NO_OUTPUT && !RSG_DURANGO
DisplayRenderTargetDetailsHeader();
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
DisplayRenderTargetDetails(grcTextureFactory::GetRenderTarget(rt));
}
#endif
}
void CRenderTargets::AddWidgets(bkBank &bank)
{
bank.PushGroup("Render Targets");
VideoResManager::AddWidgets(bank);
grcRenderTarget::AddLoggingWidgets(bank);
bank.AddButton("Dump RenderTargets",DumpRenderTargets);
bank.AddButton("Dump RenderTarget Overlaps",DisplayRenderTargetOverlaps);
s_RenderTargetMemPoolNames.Grow() = "";
for (u16 pool = 0; pool != grcRenderTargetPoolMgr::GetMemPoolCount(); ++pool)
{
s_RenderTargetMemPoolNames.Grow() = grcRenderTargetPoolMgr::GetName(pool);
}
bank.AddCombo("Render Target Pool", &s_RenderTargetPoolIndex, s_RenderTargetMemPoolNames.GetCount(), &s_RenderTargetMemPoolNames[0], NullCB, "Lists the render target pool");
s_RenderTargetNames.Reset();
s_RenderTargetNames.Reserve(grcTextureFactory::GetRenderTargetCount());
s_RenderTargetNames.Grow() = "";
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
s_RenderTargetNames.Grow() = grcTextureFactory::GetRenderTarget(rt)->GetName();
}
s_RenderTargetCount = grcTextureFactory::GetRenderTargetCount()+1;
s_RenderTargetPoolCount = grcRenderTargetPoolMgr::GetMemPoolCount()+1;
const float maxZoom = 32.0f;
const float screenSize = maxZoom * float( Max<int>(VideoResManager::GetNativeWidth(), VideoResManager::GetNativeHeight()) );
s_RenderTargetNamesCombo = bank.AddCombo("Render Target", &s_RenderTargetIndex, s_RenderTargetNames.GetCount(), &s_RenderTargetNames[0], NullCB, "Lists the render targets");
#if DEVICE_EQAA
bank.AddCombo("MSAA Mode", &s_bRenderTargetAAMode, NELEM(s_RenderTargetAAModeNames), s_RenderTargetAAModeNames, NullCB, "Switch MSAA surface access mode");
bank.AddSlider("Sample/Fragment Index", &s_bRenderTargetSampleIndex, 0, 15, 1 );
#endif
bank.AddToggle("Show Info", &s_bRenderTargetShowInfo);
bank.AddToggle("Visualise", &s_bRenderTargetVisualise);
bank.AddSeparator();
bank.AddToggle("Fullscreen", &s_bRenderTargetFullScreen);
bank.AddToggle("Native Resolution", &s_bRenderTargetNativeRes);
bank.AddToggle("Flip Horizontal", &s_bRenderTargetFlipHoriz);
bank.AddToggle("Water Draw Overlay", &s_bRenderTargetWaterDraw);
bank.AddToggle("Relative Aspect", &s_bRenderTargetRelativeAspect);
bank.AddToggle("Centre", &s_bRenderTargetCentre);
bank.AddSlider("Mip Level", &s_RenderTargetMip, 0, 12, 1);
bank.AddSeparator();
bank.AddSlider("Pos X", &s_RenderTargetPos.x, -screenSize, screenSize, 1.f);
bank.AddSlider("Pos Y", &s_RenderTargetPos.y, -screenSize, screenSize, 1.f);
bank.AddSlider("Size", &s_RenderTargetPos.w, 0.0f, screenSize, 1.f);
bank.AddSlider("Aspect", &s_RenderTargetPos.z, 0.0f, 8.0f, 0.01f);
bank.AddSeparator();
bank.AddSlider("U", &s_RenderTargetUv.x, 0.f, 100.0f, 0.01f);
bank.AddSlider("V", &s_RenderTargetUv.y, 0.f, 100.0f, 0.01f);
bank.AddSlider("UV Size", &s_RenderTargetUv.z, 0.0f, 100.0f, 0.01f);
bank.AddSeparator();
bank.AddSlider("Brightness", &s_RenderTargetBrightness, 0.0f, 16.0f, 0.01f);
bank.AddSlider("Opacity", &s_RenderTargetOpacity, 0.0f, 1.0f, 0.01f);
bank.AddSlider("Depth Near Clip", &s_RenderTargetDepthNearClip, 0.0f, 16000.0f, 0.001f);
bank.AddSlider("Depth Far Clip", &s_RenderTargetDepthFarClip, 0.0f, 16000.0f, 1.0f);
bank.AddText("Depth Near Clip GBuffer", &s_RenderTargetDepthNearClipGBuffer);
bank.AddText("Depth Far Clip GBuffer", &s_RenderTargetDepthFarClipGBuffer);
bank.AddSlider("Depth Min", &s_RenderTargetDepthMin, 0.0f, 16000.0f, 0.001f);
bank.AddSlider("Depth Max", &s_RenderTargetDepthMax, 0.0f, 16000.0f, 0.001f);
bank.AddSeparator();
bank.AddToggle("Show Red", &s_bRenderTargetRed);
bank.AddToggle("Show Green", &s_bRenderTargetGreen);
bank.AddToggle("Show Blue", &s_bRenderTargetBlue);
bank.AddToggle("Show Alpha", &s_bRenderTargetAlpha);
bank.PopGroup();
// Also create debug rendering state blocks.
grcBlendStateDesc BSDesc;
BSDesc.BlendRTDesc[0].BlendEnable = true;
BSDesc.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_ADD;
#if !__WIN32 && !RSG_ORBIS
BSDesc.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_CONSTANTALPHA;
BSDesc.BlendRTDesc[0].DestBlend = grcRSV::BLEND_INVCONSTANTALPHA;
BSDesc.BlendRTDesc[0].BlendOpAlpha = grcRSV::BLENDOP_ADD;
BSDesc.BlendRTDesc[0].SrcBlendAlpha = grcRSV::BLEND_CONSTANTALPHA;
BSDesc.BlendRTDesc[0].DestBlendAlpha = grcRSV::BLEND_INVCONSTANTALPHA;
#endif // !__WIN32
ms_BlitTransparent_BS = grcStateBlock::CreateBlendState(BSDesc);
}
void CRenderTargets::UpdateBank(const bool forceLoad)
{
// For B*1923551 - Rare crash in CRenderTargets::UpdateBank(). List size count becomes stale during function execution.
// It`s an array over-run. Been caught in debugger once, loop count is one higher than the rendertarget list size. Can only conclude
// a target was unregistered after grcTextureFactory::GetRenderTargetCount() is called.
sysCriticalSection cs(grcTextureFactory::GetRenderTargetListCritSectionToken());
#if !__WIN32PC && !RSG_DURANGO && !RSG_ORBIS
static bool bCheckedPoolSizes = true;
if (bCheckedPoolSizes)
{
bCheckedPoolSizes = false;
CheckPoolSizes();
}
#endif // !__WIN32PC && !RSG_DURANGO && !RSG_ORBIS
// repopulate rendertargets
if (s_RenderTargetCount != grcTextureFactory::GetRenderTargetCount()+1 || forceLoad)
{
s_RenderTargetCount = grcTextureFactory::GetRenderTargetCount()+1;
s_RenderTargetNames.Reset();
s_RenderTargetNames.Reserve(s_RenderTargetCount);
for (int i=0; i!=s_RenderTargetCount; ++i)
{
s_RenderTargetNames.Grow() = NULL;
}
if (s_RenderTargetNamesCombo)
{
s_RenderTargetNamesCombo->UpdateCombo("Render target", &s_RenderTargetIndex, s_RenderTargetNames.GetCount(), &s_RenderTargetNames[0], NullCB, "Lists the render targets");
}
s_RenderTargetNames.Reset();
s_RenderTargetNames.Reserve(s_RenderTargetCount);
s_RenderTargetNames.Grow() = "";
for (int rt = 0; rt != s_RenderTargetCount-1; ++rt)
{
s_RenderTargetNames.Grow() = grcTextureFactory::GetRenderTarget(rt)->GetName();
}
if (s_RenderTargetNamesCombo)
{
for (int i=0; i!=s_RenderTargetCount; ++i)
s_RenderTargetNamesCombo->SetString(i, s_RenderTargetNames[i]);
}
}
if (s_RenderTargetIndex && s_RenderTargetIndex < s_RenderTargetCount)
{
DisplayRenderTarget(s_RenderTargetIndex - 1);
}
if (s_RenderTargetPoolIndex && s_RenderTargetPoolIndex < s_RenderTargetPoolCount)
{
DisplayRenderTargetMemPool(u16(s_RenderTargetPoolIndex-1));
}
const grcViewport* vp = gVpMan.GetUpdateGameGrcViewport();
if (vp)
{
s_RenderTargetDepthNearClipGBuffer = vp->GetNearClip();
s_RenderTargetDepthFarClipGBuffer = vp->GetFarClip();
}
}
// currently mode 0 = standard, and mode 1 = water
// if we end up needing more modes, i'll change this to an enum
void CRenderTargets::RenderBank(int mode)
{
if (s_RenderTargetIndex)
{
# if __XENON
grcRenderTarget *rt = grcTextureFactory::GetRenderTarget(s_RenderTargetIndex - 1);
if (IsShowingRenderTargetWaterDraw() && strcmp(s_RenderTargetNames[s_RenderTargetIndex], "WATER_REFLECTION_COLOUR") == 0)
{
const grcRenderTarget* waterTarget = Water::GetReflectionRT();
if (CRenderPhaseMirrorReflectionInterface::GetIsMirrorUsingWaterReflectionTechnique_Update())
{
waterTarget = CMirrors::GetMirrorWaterRenderTarget();
}
for (int i = 1; i < s_RenderTargetNames.GetCount(); i++)
{
grcRenderTarget* rt2 = grcTextureFactory::GetRenderTarget(i - 1);
if (rt2 == waterTarget)
{
rt = rt2;
break;
}
}
}
# else
grcRenderTarget *const rt = grcTextureFactory::GetRenderTarget(s_RenderTargetIndex - 1);
# endif
float multiplierWidth = (rt->GetType() == grcrtCubeMap) ? 4.0f : 1.0f;
float multiplierHeight = (rt->GetType() == grcrtCubeMap) ? 2.0f : 1.0f;
if (s_bRenderTargetFullScreen)
{
s_RenderTargetPosAndSize.x = 0.0f;
s_RenderTargetPosAndSize.y = 0.0f;
s_RenderTargetPosAndSize.z = (float)VideoResManager::GetNativeWidth();
s_RenderTargetPosAndSize.w = (float)VideoResManager::GetNativeHeight();
}
else
{
if (s_bRenderTargetNativeRes)
{
s_RenderTargetPosAndSize.z = (float)rt->GetWidth() * multiplierWidth;
s_RenderTargetPosAndSize.w = (float)rt->GetHeight() * multiplierHeight;
}
else
{
s_RenderTargetPosAndSize.z = s_RenderTargetPos.w*s_RenderTargetPos.z;
s_RenderTargetPosAndSize.w = s_RenderTargetPos.w;
if (s_bRenderTargetRelativeAspect)
{
s_RenderTargetPosAndSize.z *= (float)rt->GetWidth()/(float)rt->GetHeight();
}
}
if (s_bRenderTargetCentre)
{
s_RenderTargetPosAndSize.x = 0.5f*((float)VideoResManager::GetNativeWidth() - s_RenderTargetPosAndSize.z);
s_RenderTargetPosAndSize.y = 0.5f*((float)VideoResManager::GetNativeHeight() - s_RenderTargetPosAndSize.w);
}else
{
s_RenderTargetPosAndSize.x = s_RenderTargetPos.x;
s_RenderTargetPosAndSize.y = s_RenderTargetPos.y;
}
}
if (s_RenderTargetBounds.z != 0.0f &&
s_RenderTargetBounds.w != 0.0f)
{
s_RenderTargetPosAndSize = s_RenderTargetBounds;
}
if (s_bRenderTargetFlipHoriz)
{
s_RenderTargetPosAndSize.x += s_RenderTargetPosAndSize.z;
s_RenderTargetPosAndSize.z *= -1.0f;
}
BlitRenderTarget(
rt,
s_RenderTargetPosAndSize,
s_RenderTargetOpacity,
mode == 1);
}
}
#if __PPU
namespace rage {
extern u32 g_AllowTexturePatch;
};
#endif // __PPU
void CRenderTargets::BlitRenderTarget(grcRenderTarget* pRT, const Vector4 &posAndSize, float opacity, bool bUseDepth)
{
if(!pRT || opacity <= 0.0f)
return;
#if __PPU
int src_format = -1;
g_AllowTexturePatch = 0xFFFFFFFF;
#endif // __PPU
CSprite2d::CustomShaderType type = CSprite2d::CS_BLIT;
switch(pRT->GetType())
{
case grcrtDepthBuffer:
#if __PPU
case grcrtShadowMap:
{
u8 format = gcm::StripTextureFormat(((grcRenderTargetGCM *)pRT)->GetGcmTexture().format);
bool isDepth = (format == CELL_GCM_TEXTURE_DEPTH24_D8) || (format == CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT);
if( isDepth )
{
src_format = GRCDEVICE.PatchShadowToDepthBuffer(pRT, false);
type = CSprite2d::CS_BLIT_DEPTH;
}
else
{
type = (s_bRenderTargetAlpha) ? CSprite2d::CS_BLIT_SHOW_ALPHA : CSprite2d::CS_BLIT_NOFILTERING;
}
}
#else
# if DEVICE_MSAA
if (pRT->GetMSAA())
type = strstr(pRT->GetName(),"Stencil") ? CSprite2d::CS_BLIT_MSAA_STENCIL : CSprite2d::CS_BLIT_MSAA_DEPTH;
else
# endif // DEVICE_MSAA
type = strstr(pRT->GetName(),"Stencil") ? CSprite2d::CS_BLIT_STENCIL : CSprite2d::CS_BLIT_DEPTH;
#endif // __PPU
break;
case grcrtCubeMap:
{
type = CSprite2d::CS_BLIT_CUBE_MAP;
}
break;
default:
{
#if DEVICE_MSAA
if (pRT->GetMSAA())
type = CSprite2d::CS_BLIT_MSAA;
else
#endif // DEVICE_MSAA
if (pRT->GetArraySize() > 1)
type = CSprite2d::CS_BLIT_TEX_ARRAY;
else
type = (s_bRenderTargetAlpha) ? CSprite2d::CS_BLIT_SHOW_ALPHA : CSprite2d::CS_BLIT_NOFILTERING;
}
break;
}
CSprite2d spriteBlit;
spriteBlit.SetTexture(pRT);
Vector4 params0(s_RenderTargetBrightness * s_bRenderTargetRed,
s_RenderTargetBrightness * s_bRenderTargetGreen,
s_RenderTargetBrightness * s_bRenderTargetBlue,
s_bRenderTargetAlpha * 1.0f);
Vector4 params1((float)s_RenderTargetMip, 0.0f, 0.0f, 0.0f);
#if DEVICE_EQAA
const grcRenderTargetMSAA *const rtAA = static_cast<grcRenderTargetMSAA*>(pRT);
if (s_bRenderTargetAAMode && rtAA->GetResolveFragmentMask())
{
type = CSprite2d::CS_BLIT_FMASK;
const CoverageData &coverage = rtAA->GetCoverageData();
const grcDevice::MSAAMode mode = (coverage.donor ? coverage.donor : rtAA)->GetMSAA();
params1.x = (float)( mode.m_uSamples );
params1.y = (float)( mode.m_uFragments );
params1.z = mode.GetFmaskShift();
params1.w = (float)((s_bRenderTargetAAMode<<8) + s_bRenderTargetSampleIndex);
}
#endif //DEVICE_EQAA
if (type == CSprite2d::CS_BLIT_DEPTH)
{
params1.x = s_RenderTargetDepthMin;
params1.y = s_RenderTargetDepthMax;
// see CalculateProjectionParams
const float n = s_RenderTargetDepthNearClip;
const float f = s_RenderTargetDepthFarClip;
const float Q = f/(f - n);
params1.z = XENON_SWITCH(n*Q, -n*Q);
params1.w = XENON_SWITCH(Q - 1.0f, -Q);
}
spriteBlit.SetRenderState();
spriteBlit.SetGeneralParams(params0, params1);
// adjustment for displaying multiple render targets
static float g_x_start = -0.125f;
static float g_y_start = 0.4f;
static float g_x_off = 0.325f;
static float g_y_off = -0.6f;
static const int NUM_RT_DISPLAY_ROW = 4;
const float deviceWidth = float( VideoResManager::GetNativeWidth() );
const float deviceHeight = float( VideoResManager::GetNativeHeight() );
const float normX = posAndSize.x / deviceWidth;
const float normWidth = posAndSize.z / deviceWidth;
const float normY = posAndSize.y / deviceHeight;
const float normHeight = posAndSize.w / deviceHeight;
const int rtArraySize = type == CSprite2d::CS_BLIT_TEX_ARRAY ? pRT->GetArraySize() : 1;
const float x1 = normX * 2.0f - 1.0f + g_x_start * (int)(Min(rtArraySize,NUM_RT_DISPLAY_ROW) - 1);
const float y1 = -(normY * 2.0f - 1.0f) + g_y_start * (int)(rtArraySize / (NUM_RT_DISPLAY_ROW+1));
const float x2 = (normX + normWidth) * 2.0f - 1.0f + g_x_start * (int)(Min(rtArraySize,NUM_RT_DISPLAY_ROW) - 1);
const float y2 = -((normY + normHeight) * 2.0f - 1.0f) + g_y_start * (int)(rtArraySize / (NUM_RT_DISPLAY_ROW+1));;
const bool bTransparent = (opacity < 1.0f);
if (bTransparent)
{
Color32 col(0,0,0,(int)(opacity*255.0f + 0.5f));
grcStateBlock::SetBlendState(ms_BlitTransparent_BS,col.GetColor(),~0ULL);
}
else
{
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
}
grcStateBlock::SetDepthStencilState(bUseDepth ? grcStateBlock::DSS_LessEqual : grcStateBlock::DSS_IgnoreDepth);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
for (int i = 0; i < rtArraySize; i++)
{
if (type == CSprite2d::CS_BLIT_TEX_ARRAY)
{
params1.w = (float)i;
spriteBlit.SetGeneralParams(params0, params1);
}
spriteBlit.BeginCustomList(type, pRT);
grcDrawSingleQuadf(
x1+g_x_off*(int)(i%NUM_RT_DISPLAY_ROW), y1+g_y_off*(int)(i/NUM_RT_DISPLAY_ROW),
x2+g_x_off*(int)(i%NUM_RT_DISPLAY_ROW), y2+g_y_off*(int)(i/NUM_RT_DISPLAY_ROW),
(__XENON && !bUseDepth) ? 1.0f : 0.0f,
s_RenderTargetUv.x,
s_RenderTargetUv.y,
s_RenderTargetUv.x + s_RenderTargetUv.z,
s_RenderTargetUv.y + s_RenderTargetUv.z,
Color32(255, 255, 255, 255));
spriteBlit.EndCustomList();
}
spriteBlit.SetTexture( static_cast<grcTexture*>(NULL) );
#if __PPU
if (src_format != -1)
{
GRCDEVICE.PatchDepthToShadowBuffer(pRT, src_format, false);
}
g_AllowTexturePatch = 0;
#endif // __PPU
}
int GetMaxUsedSize(u16 poolID)
{
u32 max = 0;
u8 heapCount = grcRenderTargetPoolMgr::GetHeapCount(poolID);
for (u8 i = 0; i < heapCount; ++i) {
u32 val = grcRenderTargetPoolMgr::GetUsedMem(poolID,i);
if (val > max)
max = val;
}
return max;
}
int GetMinFreeSize(u16 poolID)
{
u32 min = grcRenderTargetPoolMgr::GetAllocated(poolID);
u8 heapCount = grcRenderTargetPoolMgr::GetHeapCount(poolID);
for (u8 i = 0; i < heapCount; ++i) {
u32 val = grcRenderTargetPoolMgr::GetFreeMem(poolID,i);
if (val < min)
min = val;
}
return min;
}
int GetMaxFreeSize(u16 poolID)
{
u32 max = 0;
u8 heapCount = grcRenderTargetPoolMgr::GetHeapCount(poolID);
for (u8 i = 0; i < heapCount; ++i) {
u32 val = grcRenderTargetPoolMgr::GetFreeMem(poolID,i);
if (val > max)
max = val;
}
return max;
}
Vec2V pixelToScreen(u32 x, u32 y) { return (Vec2V((float)x, (float)y) / Vec2V(1280.0f, 720.0f)); }
void CRenderTargets::DisplayRenderTargetMemPool(u16 index)
{
if (s_RenderTargetPoolIndex > 0 && s_bRenderTargetVisualise)
{
u32 startX = 50, startY = 50;
u32 sizeX = 1180, sizeY = 620;
u32 heapOffset = (u32)ceilf(sizeX / float(grcRenderTargetPoolMgr::GetHeapCount(index)));
grcDebugDraw::RectAxisAligned(
pixelToScreen(startX, startY),
pixelToScreen(startX + sizeX, startY + sizeY),
Color32(0, 0, 0, 128),
true);
u32 poolStartAddress = UINT_MAX;
u32 poolEndAddress = 0;
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
#if __PS3
grcRenderTarget* pTarget = grcTextureFactory::GetRenderTarget(rt);
((rage::grcRenderTargetGCM*)pTarget)->LockSurface(0, 0);
#elif __XENON
grcRenderTarget* pTarget = grcTextureFactory::GetRenderTarget(rt);
((rage::grcRenderTargetXenon*)pTarget)->LockSurface(0, 0);
#endif
}
for (int h = 0; h < grcRenderTargetPoolMgr::GetHeapCount(index); ++h)
{
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
grcRenderTarget* pTarget = grcTextureFactory::GetRenderTarget(rt);
if (pTarget && pTarget->GetPoolID() == index && pTarget->GetPoolHeap() == h)
{
u32 startAddress = PS3_SWITCH( static_cast<grcRenderTargetGCM*>(pTarget)->GetMemoryOffset(), 0 );
u32 size = PS3_SWITCH( pTarget->GetPhysicalSize(), 0 );
#if __XENON
if( static_cast<grcRenderTargetXenon*>(pTarget)->GetTexturePtr() )
{
XGGetTextureLayout( static_cast<grcRenderTargetXenon*>(pTarget)->GetTexturePtr(), &startAddress, &size, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0 );
}
#endif
u32 endAddress = startAddress + size;
poolStartAddress = Min<u32>(poolStartAddress, startAddress);
poolEndAddress = Max<u32>(poolEndAddress, endAddress);
}
}
}
for (int h = 0; h < grcRenderTargetPoolMgr::GetHeapCount(index); ++h)
{
if (h < grcRenderTargetPoolMgr::GetHeapCount(index) - 1)
{
grcDebugDraw::Line(
pixelToScreen(startX + (h + 1) * heapOffset, startY + 0),
pixelToScreen(startX + (h + 1) * heapOffset, startY + sizeY),
Color32(255, 0, 0, 128),
true);
}
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
grcRenderTarget* pTarget = grcTextureFactory::GetRenderTarget(rt);
if (pTarget->GetPoolHeap() == h && pTarget->GetPoolID() == index)
{
u32 startAddress = PS3_SWITCH( static_cast<grcRenderTargetGCM*>(pTarget)->GetMemoryOffset(), 0 );
u32 size = PS3_SWITCH( pTarget->GetPhysicalSize(), 0 );
#if __XENON
if( static_cast<grcRenderTargetXenon*>(pTarget)->GetTexturePtr() )
{
XGGetTextureLayout( static_cast<grcRenderTargetXenon*>(pTarget)->GetTexturePtr(), &startAddress, &size, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0 );
}
#endif
u32 endAddress = startAddress + size;
int heapId = pTarget->GetPoolHeap();
u32 startOffset = u32(((startAddress - poolStartAddress) / float(poolEndAddress - poolStartAddress)) * sizeY);
u32 endOffset = u32(((endAddress - poolStartAddress) / float(poolEndAddress - poolStartAddress)) * sizeY);
grcDebugDraw::RectAxisAligned(
pixelToScreen(startX + (heapId + 0) * heapOffset, startY + startOffset),
pixelToScreen(startX + (heapId + 1) * heapOffset, startY + endOffset),
Color32(255, 0, 0, 32),
true);
grcDebugDraw::Line(
pixelToScreen(startX + (heapId + 0) * heapOffset, startY + startOffset),
pixelToScreen(startX + (heapId + 1) * heapOffset, startY + startOffset),
Color32(255, 0, 0, 128),
true);
grcDebugDraw::Line(
pixelToScreen(startX + (heapId + 0) * heapOffset, startY + endOffset),
pixelToScreen(startX + (heapId + 1) * heapOffset, startY + endOffset),
Color32(255, 0, 0, 128),
true);
if (endOffset - startOffset >= 20)
{
grcDebugDraw::TextFontPush(grcSetup::GetMiniFixedWidthFont());
grcDebugDraw::Text(
pixelToScreen(startX + (heapId + 0) * heapOffset + 5, startY + startOffset + 5),
Color32(255, 255, 255, 255),
pTarget->GetName());
grcDebugDraw::TextFontPop();
}
}
}
}
}
if (!s_bRenderTargetShowInfo)
return;
grcDebugDraw::AddDebugOutput("%s: allocated %d used %d free %d worst %d waste %d",
grcRenderTargetPoolMgr::GetName(index),
grcRenderTargetPoolMgr::GetAllocated(index),
GetMaxUsedSize(index),
GetMinFreeSize(index),
grcRenderTargetPoolMgr::GetLowestFreeMem(index),
GetMaxFreeSize(index)
);
#if __PPU
grcDebugDraw::AddDebugOutput("pitch %d heaps %d location %s compression %s",
grcRenderTargetPoolMgr::GetMemoryPoolPitch(index),
grcRenderTargetPoolMgr::GetHeapCount(index),
grcRenderTargetPoolMgr::GetIsPhysical(index)?"LOCAL":"MAIN",
grcRenderTargetPoolMgr::GetCompression(index)?s_CompressionMode[grcRenderTargetPoolMgr::GetCompression(index)-7]:"CELL_GCM_COMPMODE_DISABLED"
);
int unused = grcRenderTargetGCM::GetBitFieldTiledMemory().CountBits(false);
if (unused)
grcDebugDraw::AddDebugOutput(Color32(255, 0,0,255), "%d unused tiling regions", unused);
#endif
int heapCount = grcRenderTargetPoolMgr::GetHeapCount(index);
for (int h = 0; h != heapCount; ++h)
{
for (int rt = 0; rt != grcTextureFactory::GetRenderTargetCount(); ++rt)
{
grcRenderTarget * renderTarget = grcTextureFactory::GetRenderTarget(rt);
if (renderTarget && renderTarget->GetPoolID() == index && renderTarget->GetPoolHeap() == h)
{
#if __PPU
grcRenderTargetGCM* rt = (grcRenderTargetGCM*)renderTarget;
u32 pitch = rt->GetPitch();
size_t size = gcm::GetSharedSurfaceSize(
rt->GetWidth(), rt->GetHeight(),
rt->GetBitsPerPix(),
rt->GetMipMapCount(),
rt->GetLayerCount(),
rt->IsInLocalMemory(), rt->IsTiled(), rt->IsSwizzled(), rt->GetType() == grcrtCubeMap, rt->IsUsingZCull(), 1, NULL);
#endif // __PPU
grcDebugDraw::AddDebugOutput("heap %d - %s width %d height %d mips %d " PPU_ONLY("pitch %d/%d bipp %d%s %dKb"),
renderTarget->GetPoolHeap(),
renderTarget->GetName(),
renderTarget->GetWidth(),
renderTarget->GetHeight(),
renderTarget->GetMipMapCount()
#if __PPU
,rt->GetPitch()
,rt->IsTiled() ? ( gcm::GetSurfaceTiledPitch(rt->GetWidth(), rt->GetBitsPerPix(), rt->IsSwizzled())) :
( gcm::GetSurfacePitch (rt->GetWidth(), rt->GetBitsPerPix(), rt->IsSwizzled()))
,rt->GetBitsPerPix()
,rt->IsTiled()?" TILED":""
,size >> 10
#endif // __PPU
);
}
}
}
}
void CRenderTargets::DisplayRenderTarget(u32 index)
{
grcRenderTarget * renderTarget = grcTextureFactory::GetRenderTarget(index);
if (renderTarget && s_bRenderTargetShowInfo)
{
#if __PPU
grcRenderTargetGCM* rt = (grcRenderTargetGCM*)renderTarget;
u32 pitch = rt->GetPitch();
size_t size = gcm::GetSharedSurfaceSize(
rt->GetWidth(), rt->GetHeight(),
rt->GetBitsPerPix(),
rt->GetMipMapCount(),
rt->GetLayerCount(),
rt->IsInLocalMemory(), rt->IsTiled(), rt->IsSwizzled(), rt->GetType() == grcrtCubeMap, rt->IsUsingZCull(), 1, NULL);
#endif // _PSN
grcDebugDraw::AddDebugOutput(" %s width %d height %d mips %d " PPU_ONLY("pitch %d/%d bipp %d%s %dKb"),
renderTarget->GetName(),
renderTarget->GetWidth(),
renderTarget->GetHeight(),
renderTarget->GetMipMapCount()
#if __PPU
,rt->GetPitch()
,rt->IsTiled() ? ( gcm::GetSurfaceTiledPitch(rt->GetWidth(), rt->GetBitsPerPix(), rt->IsSwizzled())) :
( gcm::GetSurfacePitch (rt->GetWidth(), rt->GetBitsPerPix(), rt->IsSwizzled()))
,rt->GetBitsPerPix()
,rt->IsTiled()?" TILED":""
,size >> 10
#endif // __PPU
);
#if __PPU
if (rt->IsInMemoryPool())
{
grcDebugDraw::AddDebugOutput(" -> %s (%d)", grcRenderTargetPoolMgr::GetName(renderTarget->GetPoolID()), renderTarget->GetPoolHeap());
}
else
grcDebugDraw::AddDebugOutput(" -> NOT POOLED");
#endif // __PPU
}
}
void CRenderTargets::CheckPoolSizes()
{
int RtCount = grcTextureFactory::GetRenderTargetCount();
for (int i = 0; i != RTMEMPOOL_SIZE; ++i)
{
u16 poolID = ms_RenderTargetMemPoolArray[i];
if (poolID == 65535) // necessary for running with USE_D3D_DEBUG_LIBS
{
continue;
}
bool bNotWasting = FALSE;
for(int j=0; j<grcRenderTargetPoolMgr::GetHeapCount(poolID); j++)
{
int used = grcRenderTargetPoolMgr::GetUsedMem(poolID,(u8)j);
u32 memUsed = used;
#if __PS3
u32 pitch = grcRenderTargetPoolMgr::GetMemoryPoolPitch(poolID);
Assertf( ( used % pitch ) == 0, "used (%d) %% pitch (%d) = %d", used, pitch, used % pitch );
// now align this height according to the memory region
u32 linesUsed = used/pitch;
u32 linesNeeded = rage::gcm::GetSurfaceHeight( linesUsed, grcRenderTargetPoolMgr::GetIsPhysical(poolID) );
memUsed = linesNeeded*pitch;
#endif // __PS3
Assertf(memUsed <= ( u32 )grcRenderTargetPoolMgr::GetAllocated(poolID), "%s uses %d/%d",grcRenderTargetPoolMgr::GetName(poolID),memUsed / (1024*64),( u32 )grcRenderTargetPoolMgr::GetAllocated(poolID)/ (1024*64));
u32 memFree = grcRenderTargetPoolMgr::GetAllocated(poolID) - memUsed;
// we're allowed to waste up to 64k in order to align the tile region size
const u32 maxWastage = KB64;
bNotWasting = bNotWasting || (memFree < maxWastage);
if(!bNotWasting)
{
Displayf("grcRenderTargetMemPool '%s': heap %d, memFree: %d KB (%d pages)", grcRenderTargetPoolMgr::GetName(poolID), j, memFree/1024, memFree / (64*1024));
for(int k=0;k<RtCount;k++)
{
grcRenderTarget * renderTarget = grcTextureFactory::GetRenderTarget(k);
if(renderTarget && renderTarget->GetPoolID() == poolID && renderTarget->GetPoolHeap() == j)
{
Displayf(" %s",renderTarget->GetName());
}
}
}
}
#if __PS3
u32 maxPitch = 0;
for(int j=0;j<RtCount;j++)
{
grcRenderTarget * renderTarget = grcTextureFactory::GetRenderTarget(j);
if(renderTarget && renderTarget->GetPoolID() == poolID )
{
const u32 width = renderTarget->GetWidth();
const u32 bpp = ((grcRenderTargetGCM*)renderTarget)->GetBitsPerPixel();
const bool swizzled = renderTarget->IsSwizzled();
const bool isTiled = ((grcRenderTargetGCM*)renderTarget)->IsTiled();
u32 rtPitch = isTiled ? gcm::GetSurfaceTiledPitch(width, bpp, swizzled) : gcm::GetSurfacePitch(width, bpp, swizzled);
maxPitch = Max(maxPitch,rtPitch);
}
}
Assertf(maxPitch == grcRenderTargetPoolMgr::GetMemoryPoolPitch(poolID),"grcRenderTargetMemPool '%s' has a pitch of %d while the biggest required pitch is %d",grcRenderTargetPoolMgr::GetName(poolID),grcRenderTargetPoolMgr::GetMemoryPoolPitch(poolID),maxPitch);
#endif // __PS3
Assertf(bNotWasting==true, "grcRenderTargetMemPool '%s' is wasting memory on all heaps",grcRenderTargetPoolMgr::GetName(poolID));
if(!bNotWasting)
{
Displayf("grcRenderTargetMemPool '%s' is wasting memory on all heaps",grcRenderTargetPoolMgr::GetName(poolID));
#if __PS3
Displayf("grcRenderTargetMemPool '%s' Pitch %d",grcRenderTargetPoolMgr::GetName(poolID), grcRenderTargetPoolMgr::GetMemoryPoolPitch(poolID));
#endif
for(int j=0;j<RtCount;j++)
{
grcRenderTarget * renderTarget = grcTextureFactory::GetRenderTarget(j);
if(renderTarget && renderTarget->GetPoolID() == poolID )
{
#if __PPU
const u32 width = renderTarget->GetWidth();
const u32 bpp = renderTarget->GetBitsPerPixel();
const bool swizzled = renderTarget->IsSwizzled();
const bool isTiled = ((grcRenderTargetGCM*)renderTarget)->IsTiled();
u32 rtPitch = isTiled ? gcm::GetSurfaceTiledPitch(width, bpp, swizzled) : gcm::GetSurfacePitch(width, bpp, swizzled);
Displayf("RT %s Pitch %d",renderTarget->GetName(),rtPitch);
#else
Displayf("RT %s",renderTarget->GetName());
#endif
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
#endif // __BANK
//////////////////////////////////////////////////////////////////////////
#if __PS3
void CRenderTargets::CopyDepthBuffer( grcRenderTarget* srcDepthbuffer, grcRenderTarget* dstDepthBuffer, u8 stencilRef )
{
PF_PUSH_TIMEBAR_DETAIL("Copy Depth");
CSprite2d copyDepth;
copyDepth.SetDepthTexture( srcDepthbuffer );
grcTextureFactory::GetInstance().LockRenderTarget(0, NULL, dstDepthBuffer);
grcBlendStateHandle BS_Backup = grcStateBlock::BS_Default_WriteMaskNone;
grcDepthStencilStateHandle DSS_Backup = grcStateBlock::DSS_Active;
grcRasterizerStateHandle RS_Backup = grcStateBlock::RS_Active;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default_WriteMaskNone);
grcStateBlock::SetDepthStencilState(ms_CopyDepthClearStencil_DS, stencilRef);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
copyDepth.BeginCustomList(CSprite2d::CS_COPYDEPTH, NULL);
grcDrawSingleQuadf(-1.0, 1.0f, 1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0f, 1.0f,Color32(255,255,255,255));
copyDepth.EndCustomList();
grcStateBlock::SetStates(RS_Backup, DSS_Backup, BS_Backup);
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
PF_POP_TIMEBAR_DETAIL();
}
#endif // __PS3
#if __WIN32PC || RSG_DURANGO || RSG_ORBIS
void CRenderTargets::PreAllocateRenderTargetMemPool(void)
{
}
#endif
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
#if DEBUG_TRACK_MSAA_RESOLVES
bool CRenderTargets::IsBackBufferResolved()
{
#if DEVICE_MSAA
if (ms_BackBuffer->GetMSAA()>1)
{
return static_cast<grcRenderTargetMSAA*>(ms_BackBuffer)->HasBeenResolvedTo( ms_BackBufferCopy );
}else
#endif
{
return true;
}
}
#endif
void CRenderTargets::CopyBackBuffer()
{
PIX_TAGGING_ONLY( PIXBegin( 0x1, "Copying BackBuffer."); )
#if DEVICE_MSAA
if (ms_BackBuffer->GetMSAA()>1)
{
#if RSG_PC
if(PostFX::GetPauseResolve() == PostFX::IN_RESOLVE_PAUSE) // resolved earlier...
ms_BackBufferCopy->Copy( ms_BackBuffer );
else
#endif
static_cast<grcRenderTargetMSAA*>(ms_BackBuffer)->Resolve( ms_BackBufferCopy );
}
else
#endif
{
ms_BackBufferCopy->Copy( ms_BackBuffer );
}
PIX_TAGGING_ONLY( PIXEnd(); )
}
#endif //RSG_PC || RSG_DURANGO || RSG_ORBIS
void CRenderTargets::CopyDepthBuffer( grcRenderTarget* srcDepthBuffer, grcRenderTarget* dstDepthBuffer )
{
#if RSG_PC
// no copy is done if the depth copy is just and RO view into the depth
if (srcDepthBuffer->GetTexturePtr() == dstDepthBuffer->GetTexturePtr())
return;
#endif // RSG_PC
GRC_ALLOC_SCOPE_AUTO_PUSH_POP()
#if __D3D11
#if D3D11_RENDER_TARGET_COPY_OPTIMISATION_TEST
grcRenderTargetDX11 *srcD3D11 = static_cast<grcRenderTargetDX11*>(srcDepthBuffer);
bool needsCopying = srcD3D11->HasBeenWrittenTo();
Assert(needsCopying);
if( !needsCopying )
return;
srcD3D11->SetHasBeenWrittenTo(false);
#endif
PIX_TAGGING_ONLY( PIXBegin( 0x1, "Copying DepthBuffer."); )
if( GRCDEVICE.GetDxFeatureLevel() > 1000 )
{
#if RSG_DURANGO
//On Durango it actually appears to be faster to use a pixel shader to copy the target
CopyDepthManual(srcDepthBuffer, dstDepthBuffer);
#elif RSG_PC
if (srcDepthBuffer->GetWidth() != dstDepthBuffer->GetWidth() || srcDepthBuffer->GetHeight() != dstDepthBuffer->GetHeight())
{
grcTextureFactory::GetInstance().LockRenderTarget(0, NULL, dstDepthBuffer);
PUSH_DEFAULT_SCREEN();
grcStateBlock::SetStates(grcStateBlock::RS_Default, grcStateBlock::DSS_ForceDepth, grcStateBlock::BS_Default);
CSprite2d sprite;
sprite.SetDepthTexture(srcDepthBuffer);
sprite.SetGeneralParams(Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, 0.0f));
sprite.BeginCustomList(CSprite2d::CS_COPYDEPTH, NULL);
grcDrawSingleQuadf(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color_black);
sprite.EndCustomList();
grcStateBlock::SetStates(grcStateBlock::RS_Default, grcStateBlock::DSS_Default, grcStateBlock::BS_Default);
POP_DEFAULT_SCREEN();
grcTextureFactory::GetInstance().UnlockRenderTarget(0, NULL);
}
else
dstDepthBuffer->Copy( srcDepthBuffer );
#else
dstDepthBuffer->Copy( srcDepthBuffer );
#endif
}
else
{
//Need to make sure we call this in the correct place to set everything up correctly.
//On DX10 we have to do a full screen pass to manually copy the depth
CopyDepthManual(srcDepthBuffer, dstDepthBuffer);
}
PIX_TAGGING_ONLY( PIXEnd(); )
#elif RSG_ORBIS
PIX_TAGGING_ONLY( PIXBegin( 0x1, "Copying DepthBuffer."); )
dstDepthBuffer->Copy( srcDepthBuffer );
PIX_TAGGING_ONLY( PIXEnd(); )
#endif
}
#if RSG_PC || RSG_DURANGO
#if RSG_PC && __D3D11
grcRenderTarget* CRenderTargets::GetBackBufferCopy(bool bDoCopy/*=false*/)
{
if(bDoCopy) CopyBackBuffer();
#if RSG_PC
if (PostFX::GetPauseResolve() == PostFX::IN_RESOLVE_PAUSE)
return ms_BackBufferRTForPause;
else
#endif
return ms_BackBufferCopy;
}
void CRenderTargets::ResolveForMultiGPU(int bResolve)
{
if (!AssertVerify(GRCDEVICE.UsingMultipleGPUs() && ms_BackBufferTexForPause))
{
return;
}
static int g_GPUCounter = 0;
if (bResolve == (int)PostFX::RESOLVE_PAUSE)
{
/*
* Copy the current backbuffer to staging texture and create rendertarget to be used by postfx (necessary for multi GPU)
*/
grcRenderTarget *pSrc = (CRenderTargets::GetBackBufferCopy(true));
ms_BackBufferTexForPause->Copy((grcTexture*)pSrc);
((grcTextureDX11*)ms_BackBufferTexForPause)->UpdateCPUCopy();
g_GPUCounter = GRCDEVICE.GetGPUCount(true);
}
else if (bResolve == (int)PostFX::IN_RESOLVE_PAUSE)
{
if (g_GPUCounter > 0)
{
// Update GPU copy of backbuffer tex for the current GPU index
((grcTextureDX11*)ms_BackBufferTexForPause)->UpdateGPUCopyFromBackingStore();
g_GPUCounter--;
}
}
else if (bResolve == (int)PostFX::UNRESOLVE_PAUSE)
{
// we used to de-allocate targets here
}
}
#endif
void CRenderTargets::CopyTarget(grcRenderTarget *src, grcRenderTarget *dst, grcRenderTarget *dstStencil, u8 stencilRef)
{
if (dstStencil == NULL || stencilRef >= 0xFF)
{
PF_PUSH_TIMEBAR_DETAIL("CopyTarget");
#if RSG_PC || RSG_DURANGO // Not sure if Orbis supports grcRenderTarget->Copy()
dst->Copy(src);
#else
CSprite2d copyTarget;
grcTextureFactory::GetInstance().LockRenderTarget(0, dst, NULL);
grcBlendStateHandle BS_Backup = grcStateBlock::BS_Active;
grcDepthStencilStateHandle DSS_Backup = grcStateBlock::DSS_Active;
grcRasterizerStateHandle RS_Backup = grcStateBlock::RS_Active;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
copyTarget.BeginCustomList(CSprite2d::CS_BLIT_NOFILTERING, src);
grcDrawSingleQuadf(-1.0, 1.0f, 1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0f, 1.0f,Color32(255,255,255,255));
copyTarget.EndCustomList();
grcStateBlock::SetStates(RS_Backup, DSS_Backup, BS_Backup);
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = false;
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
#endif
PF_POP_TIMEBAR_DETAIL();
}
else
{
PF_PUSH_TIMEBAR_DETAIL("CopyTarget StencilRef");
grcTextureFactory::GetInstance().LockRenderTarget(0, dst, dstStencil);
grcBlendStateHandle BS_Backup = grcStateBlock::BS_Active;
grcDepthStencilStateHandle DSS_Backup = grcStateBlock::DSS_Active;
grcRasterizerStateHandle RS_Backup = grcStateBlock::RS_Active;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
grcStateBlock::SetDepthStencilState(ms_CopyColorStencilMask_DS, stencilRef);
CSprite2d copyTarget;
copyTarget.BeginCustomList(CSprite2d::CS_BLIT_NOFILTERING, src);
grcDrawSingleQuadf(-1.0, 1.0f, 1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0f, 1.0f,Color32(255,255,255,255));
copyTarget.EndCustomList();
grcStateBlock::SetStates(RS_Backup, DSS_Backup, BS_Backup);
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = false;
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
PF_POP_TIMEBAR_DETAIL();
}
}
#endif //RSG_PC || RSG_DURANGO
void CRenderTargets::CopyDepthManual(grcRenderTarget *srcDepthbuffer, grcRenderTarget *dstDepthBuffer)
{
PF_PUSH_TIMEBAR_DETAIL("Copy Depth");
CSprite2d copyDepth;
copyDepth.SetDepthTexture( srcDepthbuffer );
grcTextureFactory::GetInstance().LockRenderTarget(0, NULL, dstDepthBuffer);
grcBlendStateHandle BS_Backup = grcStateBlock::BS_Active;
grcDepthStencilStateHandle DSS_Backup = grcStateBlock::DSS_Active;
grcRasterizerStateHandle RS_Backup = grcStateBlock::RS_Active;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetDepthStencilState(ms_CopyDepth_DS);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
copyDepth.BeginCustomList(CSprite2d::CS_COPYDEPTH, NULL);
grcDrawSingleQuadf(-1.0, 1.0f, 1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0f, 1.0f,Color32(255,255,255,255));
copyDepth.EndCustomList();
grcStateBlock::SetStates(RS_Backup, DSS_Backup, BS_Backup);
grcResolveFlags resolveFlags;
resolveFlags.NeedResolve = false;
grcTextureFactory::GetInstance().UnlockRenderTarget(0, &resolveFlags);
PF_POP_TIMEBAR_DETAIL();
}
#if __D3D11
//returns depth buffer to use as shader resource.
grcRenderTarget* CRenderTargets::LockReadOnlyDepth( bool needsCopy, bool bLockBothDepthStencilRO, grcRenderTarget* depthAndStencilBuffer, grcRenderTarget* depthBufferCopy, grcRenderTarget* depthAndStencilBufferReadOnly)
{
grcTextureFactoryDX11& textureFactory11 = static_cast<grcTextureFactoryDX11&>(grcTextureFactoryDX11::GetInstance());
grcRenderTarget* depthBufferReturn = NULL;
//On Dx11 we can use a read only depth buffer when depth writes are turned off
//and use the main depth buffer as a shader resource
if( GRCDEVICE.IsReadOnlyDepthAllowed() )
{
if ( bLockBothDepthStencilRO)
textureFactory11.LockDepthAndCurrentColorTarget( depthAndStencilBufferReadOnly );
else
textureFactory11.LockDepthAndCurrentColorTarget( depthBufferCopy );
depthBufferReturn = GetDepthBuffer();
}
//On DX10/10.1 we need to copy the depth buffer and use the copy.
else
{
if( needsCopy )
{
CopyDepthBuffer( depthAndStencilBuffer, depthBufferCopy);
}
depthBufferReturn = depthBufferCopy;
}
return depthBufferReturn;
}
void CRenderTargets::UnlockReadOnlyDepth()
{
grcTextureFactoryDX11& textureFactory11 = static_cast<grcTextureFactoryDX11&>(grcTextureFactoryDX11::GetInstance());
if( GRCDEVICE.IsReadOnlyDepthAllowed() )
{
grcResolveFlags resolveFlags;
resolveFlags.MipMap = false;
textureFactory11.UnlockDepthAndCurrentColorTarget(&resolveFlags);
}
}
#endif //__D3D11
#if GTA_REPLAY
#if REPLAY_USE_PER_BLOCK_THUMBNAILS
grcTexture* CRenderTargets::GetReplayThumbnailTexture(u32 idx)
{
grcAssert(idx < REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE);
return ms_ReplayThumbnailTex[idx];
}
grcRenderTarget* CRenderTargets::GetReplayThumbnailRT(u32 idx)
{
grcAssert(idx < REPLAY_PER_FRAME_THUMBNAILS_LIST_SIZE);
return ms_ReplayThumbnailRT[idx];
}
#endif // REPLAY_USE_PER_BLOCK_THUMBNAILS
#endif // GTA_REPLAY
//////////////////////////////////////////////////////////////////////////
// VideoResManager
#if RSG_PC
int VideoResManager::m_scalingMode;
#endif
int VideoResManager::m_nativeWidth;
int VideoResManager::m_nativeHeight;
int VideoResManager::m_gameWidth;
int VideoResManager::m_gameHeight;
int VideoResManager::m_UIWidth;
int VideoResManager::m_UIHeight;
//////////////////////////////////////////////////////////////////////////
//
VideoResManager::eDownscaleFactor VideoResManager::GetDownscaleFactor( u32 const rawDownscale )
{
VideoResManager::eDownscaleFactor result = DOWNSCALE_SIXTEENTH;
switch( rawDownscale )
{
case 1:
{
result = DOWNSCALE_ONE;
break;
}
case 2:
{
result = DOWNSCALE_HALF;
break;
}
case 4:
{
result = DOWNSCALE_QUARTER;
break;
}
case 8:
{
result = DOWNSCALE_EIGHTH;
break;
}
default:
{
// default to 16th, as set earlier.
break;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////
//
#if RSG_PC
void VideoResManager::GetSceneScale(int scalingMode, int& scaleNumerator, int& scaleDenominator)
{
switch (scalingMode)
{
default:
case 0: // x 1.000
scaleNumerator = 1;
scaleDenominator = 1;
break;
case 1: // x 0.500
scaleNumerator = 1;
scaleDenominator = 2;
break;
case 2: // x 0.6667
scaleNumerator = 2;
scaleDenominator = 3;
break;
case 3: // x 0.750
scaleNumerator = 3;
scaleDenominator = 4;
break;
case 4: // x 0.833
scaleNumerator = 5;
scaleDenominator = 6;
break;
case 5: // x 1.250
scaleNumerator = 5;
scaleDenominator = 4;
break;
case 6: // x 1.500
scaleNumerator = 3;
scaleDenominator = 2;
break;
case 7: // x 1.750
scaleNumerator = 7;
scaleDenominator = 4;
break;
case 8: // x 2.0
scaleNumerator = 2;
scaleDenominator = 1;
break;
case 9: // x 2.5
scaleNumerator = 5;
scaleDenominator = 2;
break;
}
}
#endif
void VideoResManager::Init()
{
m_nativeWidth = GRCDEVICE.GetWidth();
m_nativeHeight = GRCDEVICE.GetHeight();
#if RSG_PC
int scaleNumerator = 1;
int scaleDenominator = 1;
GetSceneScale(m_scalingMode,scaleNumerator, scaleDenominator);
m_gameWidth = PSN_BUFFER_WIDTH*scaleNumerator/scaleDenominator;
m_gameHeight = PSN_BUFFER_HEIGHT*scaleNumerator/scaleDenominator;
#else
m_gameWidth = PSN_BUFFER_WIDTH;
m_gameHeight = PSN_BUFFER_HEIGHT;
#endif
m_UIWidth = PSN_BUFFER_WIDTH;
m_UIHeight = PSN_BUFFER_HEIGHT;
// override if defined
PARAM_gamewidth.Get(m_gameWidth);
PARAM_gameheight.Get(m_gameHeight);
#if RSG_PC
DeviceReset();
#endif // RSG_PC
}
//////////////////////////////////////////////////////////////////////////
//
void VideoResManager::Shutdown()
{
}
#if RSG_PC
//////////////////////////////////////////////////////////////////////////
//
void VideoResManager::DeviceLost()
{
}
void VideoResManager::DeviceReset()
{
int scaleNumerator = 1;
int scaleDenominator = 1;
GetSceneScale(m_scalingMode,scaleNumerator, scaleDenominator);
m_gameWidth = GRCDEVICE.GetWidth()*scaleNumerator/scaleDenominator;
m_gameHeight = GRCDEVICE.GetHeight()*scaleNumerator/scaleDenominator;
m_nativeWidth = GRCDEVICE.GetWidth();
m_nativeHeight = GRCDEVICE.GetHeight();
m_UIWidth = PSN_BUFFER_WIDTH;
m_UIHeight = PSN_BUFFER_HEIGHT;
}
#endif
//////////////////////////////////////////////////////////////////////////
//
#if __BANK
void VideoResManager::AddWidgets(bkBank &bank)
{
bank.PushGroup("Video Resolution Manager", false);
bank.AddSlider("Native Width", &m_nativeWidth, m_nativeWidth, m_nativeWidth, 0);
bank.AddSlider("Native Height", &m_nativeHeight, m_nativeHeight, m_nativeHeight, 0);
bank.AddSeparator();
bank.AddSlider("Game Width", &m_gameWidth, m_gameWidth, m_gameWidth, 0);
bank.AddSlider("Game Height", &m_gameHeight, m_gameHeight, m_gameHeight, 0);
bank.PopGroup();
}
#endif // __BANK