1625 lines
48 KiB
C++
1625 lines
48 KiB
C++
//
|
|
// name: system.cpp
|
|
// description: Class grouping all the system level classes
|
|
//
|
|
#include "system.h"
|
|
|
|
#if __WIN32PC
|
|
#include "system/xtl.h"
|
|
#include "grcore/config.h"
|
|
#include <windows.h>
|
|
#if __D3D
|
|
#include "grcore/config.h"
|
|
#include "system/param.h"
|
|
#include "system/d3d9.h"
|
|
#endif
|
|
#include "grcore/texturepc.h"
|
|
#endif
|
|
|
|
#include "file/tcpip.h"
|
|
#include "grcore/texturedefault.h"
|
|
#include "grcore/fastquad.h"
|
|
|
|
#if __PPU
|
|
#include <sys/timer.h>
|
|
#include "rline/rlnp.h"
|
|
namespace rage
|
|
{
|
|
extern rlNp g_rlNp;
|
|
extern bool g_IsExiting;
|
|
}
|
|
#endif
|
|
|
|
// Rage headers
|
|
#include "audioengine/engine.h"
|
|
#include "bank/bank.h"
|
|
#include "bank/bkmgr.h"
|
|
#include "diag/output.h"
|
|
#include "file/asset.h"
|
|
#include "file/remote.h"
|
|
#include "fwdrawlist/drawlist.h"
|
|
#include "fwrenderer/instancing.h"
|
|
#include "fwrenderer/renderthread.h"
|
|
#include "grcore/device.h"
|
|
#include "grcore/font.h"
|
|
#include "grcore/gfxcontext.h"
|
|
#include "grcore/gputrace_gnm.h"
|
|
#include "grcore/texture.h"
|
|
#include "grcore/viewport.h"
|
|
#include "grmodel/model.h"
|
|
#include "grmodel/setup.h"
|
|
#include "grmodel/shader.h"
|
|
#include "move/move.h"
|
|
#include "network/Live/LiveManager.h"
|
|
#include "network/Live/NetworkTelemetry.h"
|
|
#include "paging/dictionary.h"
|
|
#include "paging/streamer.h"
|
|
#include "parser/manager.h"
|
|
#include "phbound/bound.h"
|
|
#include "grprofile/drawmanager.h"
|
|
#include "profile/profiler.h"
|
|
#include "grprofile/stats.h"
|
|
#include "profile/timebars.h"
|
|
#if RSG_DURANGO
|
|
#include "rline/durango/rlxbltitleid_interface.h"
|
|
#endif
|
|
#include "system/appcontent.h"
|
|
#include "system/bootmgr.h"
|
|
#include "system/memory.h"
|
|
#include "system/param.h"
|
|
#include "system/systeminfo.h"
|
|
#include "system/task.h"
|
|
#include "system/threadregistry.h"
|
|
#include "system/timemgr.h"
|
|
#include "system/timer.h"
|
|
#include "system/userlist.h"
|
|
#include "system/xtl.h"
|
|
|
|
// Framework headers
|
|
#include "fwsys/timer.h"
|
|
#include "fwdebug/picker.h"
|
|
#include "video/media_transcoding_allocator.h"
|
|
#include "video/VideoPlayback.h"
|
|
#include "video/VideoPlaybackThumbnailManager.h"
|
|
|
|
// Game headers
|
|
#include "camera/viewports/ViewportManager.h"
|
|
#include "camera/CamInterface.h"
|
|
#include "control/replay/replay.h"
|
|
#include "control/videorecording/videorecording.h"
|
|
#include "core/game.h"
|
|
#include "debug/AutomatedTest.h"
|
|
#include "debug/BudgetDisplay.h"
|
|
#include "debug/GtaPicker.h"
|
|
#include "frontend/HudTools.h"
|
|
#include "frontend/ProfileSettings.h"
|
|
#include "frontend/Scaleform/ScaleFormMgr.h"
|
|
#include "game/config.h"
|
|
#include "Peds/pedDefines.h" // For setting MAXNOOFPEDS from configuration file.
|
|
#include "renderer/DrawLists/drawList.h"
|
|
#include "renderer/DrawLists/drawListMgr.h"
|
|
#include "renderer/renderThread.h"
|
|
#include "renderer/lights/lights.h"
|
|
#include "renderer/OcclusionQueries.h"
|
|
#include "renderer/RenderPhases/RenderPhaseCascadeShadows.h"
|
|
#include "shaders/shaderlib.h"
|
|
#include "streaming/streaming.h"
|
|
#include "streaming/streamingvisualize.h"
|
|
#include "system/controlmgr.h"
|
|
#include "system/filemgr.h"
|
|
#include "system/SettingsManager.h"
|
|
#include "system/threadpriorities.h"
|
|
#include "streaming/streamingdefs.h"
|
|
#include "timecycle/TimeCycle.h"
|
|
#include "tools/SmokeTest.h"
|
|
#include "Renderer/PostProcessFX.h"
|
|
#include "vfx/misc/MovieManager.h"
|
|
#include "renderer/Util/RenderDocManager.h"
|
|
|
|
#if __PS3
|
|
#include <sys/dbg.h>
|
|
extern "C" int snIsDebuggerRunning (void);
|
|
#endif //__PS3
|
|
|
|
#if __D3D11
|
|
#include "grcore/texture_d3d11.h"
|
|
#endif //__D3D11
|
|
#include "Vehicles/vehiclepopulation.h" // For setting CVehiclePopulation::ms_maxNumberOfCarsInUse from configuration file.
|
|
#include "vfx/misc/LODLightManager.h"
|
|
#include "vfx/misc/Coronas.h"
|
|
#include "vfx/misc/FogVolume.h"
|
|
#include "vfx/particles/PtFxManager.h"
|
|
|
|
#if !__NO_OUTPUT
|
|
#include "Debug/Debug.h"
|
|
#endif //!__NO_OUTPUT
|
|
|
|
#define FORCE_FRAME_LIMIT (RSG_PC||RSG_DURANGO) // Please do not set this based on !RSG_FINAL -- that just leads to trouble
|
|
|
|
#define FRAME_LIMIT_BEFORE_PRESENT (FORCE_FRAME_LIMIT && IS_CONSOLE) // Console traditionally runs the frame limiter before Present (and I don't want to change that just now)
|
|
#define FRAME_LIMIT_AFTER_PRESENT (FORCE_FRAME_LIMIT && RSG_PC && 1) // PC seems to get better results from limiting after Present (I suspect this is because the sleep sometimes over shoots just a bit and we miss v-sync)
|
|
|
|
#if (__WIN32PC)
|
|
#define DEFAULT_FRAME_LIMIT 0
|
|
#define DEFAULT_FRAME_LOCK 1
|
|
#else
|
|
#define DEFAULT_FRAME_LIMIT 2 // Limit frame rate using busy-wait loop below (only if DEFAULT_FRAME_LIMIT is enabled)
|
|
#define DEFAULT_FRAME_LOCK 2 // Lock the back buffer flips
|
|
#endif
|
|
|
|
NOSTRIP_XPARAM(fullscreen);
|
|
NOSTRIP_XPARAM(windowed);
|
|
NOSTRIP_XPARAM(ignoreprofile);
|
|
PARAM(altGameConfig, "Use alternative gameconfig xml");
|
|
NOSTRIP_PC_PARAM(numTaskSchedulers, "Set the number of task scheduler threads");
|
|
|
|
#define GAMECFG_FILENAME "common:/data/gameconfig.xml"
|
|
|
|
#if RSG_ORBIS && !__FINAL
|
|
PARAM(enableGpuTraceCapture,"Enable Razor GPU Trace Capture");
|
|
static bool g_requestedTraceCapture = false;
|
|
static int g_traceCaptureState = -1;
|
|
#endif // RSG_ORBIS
|
|
|
|
namespace rage {
|
|
NOSTRIP_XPARAM(hdr);
|
|
NOSTRIP_XPARAM(width);
|
|
NOSTRIP_XPARAM(height);
|
|
#if RSG_ORBIS || RSG_DURANGO
|
|
NOSTRIP_XPARAM(multiSample);
|
|
NOSTRIP_XPARAM(multiFragment);
|
|
#endif
|
|
NOSTRIP_PC_XPARAM(frameLimit);
|
|
NOSTRIP_XPARAM(clearhddcache);
|
|
#if __PPU
|
|
NOSTRIP_XPARAM(nodepth);
|
|
NOSTRIP_XPARAM(force720);
|
|
NOSTRIP_XPARAM(MSAA);
|
|
#endif // __PPU
|
|
|
|
#if !__FINAL && __XENON
|
|
extern size_t g_sysExtraMemory;
|
|
#endif // !__FINAL && __XENON
|
|
}
|
|
|
|
bool CSystem::ms_bDebuggerDetected = false;
|
|
|
|
// --- Structure/Class Definitions ----------------------------------------------
|
|
// Custom draw list commands
|
|
class dlCmdBeginRender : public dlCmdBase {
|
|
public:
|
|
enum {
|
|
INSTRUCTION_ID = DC_BeginRender,
|
|
};
|
|
#if RSG_ORBIS && !__FINAL
|
|
dlCmdBeginRender()
|
|
{
|
|
m_traceCapture = g_requestedTraceCapture;
|
|
g_requestedTraceCapture = false;
|
|
}
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
|
|
s32 GetCommandSize() { return(sizeof(*this)); }
|
|
static void ExecuteStatic(dlCmdBase & cmd) { ((dlCmdBeginRender &) cmd).Execute(); }
|
|
void Execute();
|
|
|
|
#if RSG_ORBIS && !__FINAL
|
|
private:
|
|
bool m_traceCapture;
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
};
|
|
|
|
void dlCmdBeginRender::Execute()
|
|
{
|
|
#if RSG_ORBIS && !__FINAL
|
|
if( m_traceCapture )
|
|
{
|
|
g_traceCaptureState = 0;
|
|
}
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
|
|
CSystem::BeginRender();
|
|
}
|
|
|
|
|
|
class dlCmdEndRender : public dlCmdBase {
|
|
public:
|
|
enum {
|
|
INSTRUCTION_ID = DC_EndRender,
|
|
};
|
|
|
|
s32 GetCommandSize() { return(sizeof(*this)); }
|
|
static void ExecuteStatic(dlCmdBase & /*cmd*/);
|
|
};
|
|
|
|
void dlCmdEndRender::ExecuteStatic(dlCmdBase &)
|
|
{
|
|
#if GRCCONTEXT_ALLOC_SCOPES_SUPPORTED
|
|
// When executing a drawlist, the base allocation scope is locked.
|
|
// Temporarily unlock to prevent asserts when submitting the context.
|
|
Assert(grcGfxContext::isLockedAllocScope());
|
|
grcGfxContext::unlockAllocScope();
|
|
#endif
|
|
|
|
CSystem::EndRender();
|
|
|
|
#if GRCCONTEXT_ALLOC_SCOPES_SUPPORTED
|
|
grcGfxContext::lockAllocScope();
|
|
#endif
|
|
}
|
|
|
|
|
|
// --- Static Globals -----------------------------------------------------------
|
|
#if FORCE_FRAME_LIMIT
|
|
s32 gFrameLimit = DEFAULT_FRAME_LIMIT;
|
|
#endif // FORCE_FRAME_LIMIT
|
|
static sysTimer gFrameTimer;
|
|
|
|
#if __D3D && __WIN32PC
|
|
static D3DDEVINFO_RESOURCEMANAGER gD3dResourceData;
|
|
#endif
|
|
|
|
#if __BANK && __XENON
|
|
static void EndRingBufferMemUsage();
|
|
static void StartRingBufferMemUsage();
|
|
#endif
|
|
|
|
|
|
// ---- thread local ------
|
|
__THREAD bool gb_mainThread = false;
|
|
|
|
// --- Code ---------------------------------------------------------------------
|
|
|
|
|
|
void SetWindowsSystemParameters()
|
|
{
|
|
#if __WIN32PC
|
|
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
|
|
#endif
|
|
}
|
|
|
|
void InitMemoryBuckets()
|
|
{
|
|
grcTexture::sm_MemoryBucket = MEMBUCKET_RENDER;
|
|
grmModel::sm_MemoryBucket = MEMBUCKET_RENDER;
|
|
phBound::sm_MemoryBucket = MEMBUCKET_PHYSICS;
|
|
sfScaleformManager::sm_MemoryBucket = MEMBUCKET_SCALEFORM;
|
|
mvMove::sm_MemoryBucket = MEMBUCKET_ANIMATION;
|
|
}
|
|
|
|
#if __XENON && !__OPTIMIZED
|
|
extern "C" BOOL D3D__DisableConstantOverwriteCheck;
|
|
#endif
|
|
|
|
#if BACKTRACE_ENABLED
|
|
|
|
// Adapted from RDR2's CDebug::GetBuildConfigName()
|
|
const char* GetBuildConfigName()
|
|
{
|
|
#if __EDITOR == 1 || __TOOL == 1 || __EXPORTER == 1
|
|
return "Custom";
|
|
#elif __DEV == 1 && __OPTIMIZED == 0 && __BANK == 1 && __ASSERT == 1 && __FINAL == 0 && __MASTER == 0 && __PROFILE == 0
|
|
return "Debug";
|
|
#elif __DEV == 1 && __OPTIMIZED == 1 && __BANK == 1 && __ASSERT == 1 && __FINAL == 0 && __MASTER == 0 && __PROFILE == 0
|
|
return "Beta";
|
|
#elif __DEV == 0 && __OPTIMIZED == 1 && __BANK == 1 && __ASSERT == 0 && __FINAL == 0 && __MASTER == 0 && __PROFILE == 0
|
|
return "BankRelease";
|
|
#elif __DEV == 0 && __OPTIMIZED == 1 && __BANK == 0 && __ASSERT == 0 && __FINAL == 0 && __MASTER == 0 && __PROFILE == 1
|
|
return "Profile";
|
|
#elif __DEV == 0 && __OPTIMIZED == 1 && __BANK == 0 && __ASSERT == 0 && __FINAL == 0 && __MASTER == 0 && __PROFILE == 0
|
|
return "Release";
|
|
#elif __DEV == 0 && __OPTIMIZED == 1 && __BANK == 0 && __ASSERT == 0 && __FINAL == 1 && __MASTER == 0 && __PROFILE == 0
|
|
return "Final";
|
|
#elif __DEV == 0 && __OPTIMIZED == 1 && __BANK == 0 && __ASSERT == 0 && __FINAL == 1 && __MASTER == 1 && __PROFILE == 0
|
|
return "Master";
|
|
#else
|
|
return "Custom";
|
|
#endif
|
|
}
|
|
|
|
void SetBacktraceVersionInfo()
|
|
{
|
|
sysException::SetAnnotation("build_type", GetBuildConfigName());
|
|
sysException::SetAnnotation("build_version", CDebug::GetVersionNumber());
|
|
|
|
// Split the raw version into components and set each as a separate annotation
|
|
const char* rawVersion = CDebug::GetRawVersionNumber();
|
|
int versionComponents[4];
|
|
int componentCount = sscanf(rawVersion, "%d.%d.%d.%d", &versionComponents[0], &versionComponents[1], &versionComponents[2], &versionComponents[3]);
|
|
|
|
static const char* const keyNames[] = { "build_version_a", "build_version_b", "build_version_c", "build_version_d" };
|
|
for (int i = 0; i < componentCount; i++)
|
|
{
|
|
sysException::SetAnnotation(keyNames[i], versionComponents[i]);
|
|
}
|
|
|
|
#if RSG_PC
|
|
char osVersion[64] = { 0 };
|
|
CSystemInfo::GetShortWindowsVersion(osVersion, sizeof(osVersion));
|
|
sysException::SetAnnotation("os_version", osVersion);
|
|
#endif
|
|
|
|
}
|
|
#endif // BACKTRACE_ENABLED
|
|
|
|
// This is called from the render thread, sychronously, to finish initialisation that needs to happen on that thread.
|
|
void CSystem::RenderThreadInit()
|
|
{
|
|
#if RSG_PC && NV_SUPPORT
|
|
NvAPI_Status status = NVAPI_ERROR;
|
|
status = NvAPI_Initialize();
|
|
|
|
if (status != NVAPI_OK)
|
|
{
|
|
grcWarningf("Failed to Initialize NVidia API Lib");
|
|
}
|
|
#endif
|
|
|
|
GetRageSetup()->BeginGfx(InWindow());
|
|
|
|
#if !RSG_PC
|
|
// Frame lock value needs to be set after grcDevice::Init is called. Don't
|
|
// call this for PC though, as it messes with settings loaded from xml right
|
|
// now. May need to re-address this in the future though.
|
|
GRCDEVICE.SetFrameLock(DEFAULT_FRAME_LOCK, false);
|
|
#endif
|
|
|
|
#if __XENON
|
|
static u16 adjustmentCurve[256] = {
|
|
0,768,1472,2240,2944,3584,4160,4672,5120,5568,5952,6336,6720,7104,7424,7744,8064,8320,8640,8896,9152,9408,9664,9920,10176,
|
|
10496,10752,11008,11264,11520,11776,12032,12288,12544,12800,13056,13312,13568,13824,14080,14336,14592,14848,15104,15360,15552,
|
|
15808,16064,16320,16576,16832,17088,17344,17600,17856,18112,18368,18624,18816,19072,19328,19584,19840,20096,20352,20608,20864,
|
|
21056,21312,21568,21824,22080,22336,22592,22784,23040,23296,23552,23808,24064,24320,24512,24768,25024,25280,25536,25792,25984,
|
|
26240,26496,26752,27008,27200,27456,27712,27968,28224,28416,28672,28928,29184,29440,29632,29888,30144,30400,30592,30848,31104,
|
|
31360,31552,31808,32064,32320,32576,32768,33024,33280,33536,33728,33984,34240,34432,34688,34944,35200,35392,35648,35904,36160,
|
|
36352,36608,36864,37120,37312,37568,37824,38016,38272,38528,38784,38976,39232,39488,39680,39936,40192,40384,40640,40896,41152,
|
|
41344,41600,41856,42048,42304,42560,42752,43008,43264,43456,43712,43968,44160,44416,44672,44864,45120,45376,45568,45824,46080,
|
|
46272,46528,46784,46976,47232,47488,47680,47936,48192,48384,48640,48896,49088,49344,49536,49792,50048,50240,50496,50752,50944,
|
|
51200,51456,51648,51904,52096,52352,52608,52800,53056,53312,53504,53760,53952,54208,54464,54656,54912,55168,55360,55616,55808,
|
|
56064,56320,56512,56768,56960,57216,57472,57664,57920,58112,58368,58624,58816,59072,59264,59520,59776,59968,60224,60416,60672,
|
|
60864,61120,61376,61568,61824,62016,62272,62528,62720,62976,63168,63424,63616,63872,64128,64320,64576,64768,65024,65216,65472 };
|
|
|
|
D3DGAMMARAMP ramp;
|
|
for (u32 i = 0; i < 256; i++)
|
|
{
|
|
ramp.red[i] = adjustmentCurve[i];
|
|
ramp.green[i] = adjustmentCurve[i];
|
|
ramp.blue[i] = adjustmentCurve[i];
|
|
}
|
|
GRCDEVICE.GetCurrent()->SetGammaRamp(0, 0, &ramp);
|
|
#endif
|
|
|
|
GetRageSetup()->CreateDefaultFactories();
|
|
|
|
#if RSG_PC
|
|
GRCDEVICE.InitializeStereo();
|
|
#endif
|
|
|
|
#if DEVICE_EQAA
|
|
eqaa::Init();
|
|
#endif
|
|
#if RSG_ORBIS
|
|
grcRenderTargetGNM::InitMipShader();
|
|
#endif
|
|
|
|
// Look up the shader variable constants
|
|
CShaderLib::PreInit();
|
|
|
|
#if !__NO_OUTPUT
|
|
#if RSG_PC
|
|
CShaderLib::SetStereoTexture();
|
|
#endif
|
|
RenderBuildInformation();
|
|
#endif // !__NO_OUTPUT
|
|
|
|
#if BACKTRACE_ENABLED
|
|
SetBacktraceVersionInfo();
|
|
#endif
|
|
|
|
grcTexture::InitFastMipMapper();
|
|
|
|
CSprite2d::Init(INIT_CORE); // depends on GetRageSetup()->CreateDefaultFactories
|
|
|
|
CStreaming::InitStreamingEngine(); // Must be called before we initialize gDrawListMgr
|
|
|
|
gDrawListMgr = rage_new CDrawListMgr();
|
|
DRAWLISTMGR->Initialise();
|
|
|
|
OcclusionQueries::Init();
|
|
|
|
// initialise renderthread and drawlist mgr
|
|
CGtaRenderThreadGameInterface::InitClass();
|
|
|
|
#if defined(VIDEO_RECORDING_ENABLED) && VIDEO_RECORDING_ENABLED
|
|
VideoRecording::RenderThreadInit();
|
|
#endif
|
|
}
|
|
//
|
|
// name: CSystem::Init
|
|
// description: Initialise system level classes
|
|
bool CSystem::Init(const char* pAppName)
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
|
|
|
|
#if __XENON
|
|
SetThreadPriority(GetCurrentThread(), PRIO_HIGHEST);
|
|
#endif
|
|
#if __XENON && !__OPTIMIZED
|
|
//D3D__DisableConstantOverwriteCheck = TRUE; -- Should be safe now
|
|
#endif
|
|
|
|
// allowed only during Render Thread, plus this is default state of model cullback anyway:
|
|
// grmModel::SetModelCullback( grmModel::ModelVisibleWithAABB );
|
|
|
|
//@@: location CSYSTEM_INIT_INIT_MEMORY_BUCKETS
|
|
InitMemoryBuckets();
|
|
|
|
SetThisThreadId(SYS_THREAD_UPDATE);
|
|
SetThisThreadId(SYS_THREAD_RENDER);
|
|
gb_mainThread = true;
|
|
|
|
pgDictionaryBase::SetListOwnerThread(g_CurrentThreadId);
|
|
|
|
//Set the maximum number of archives/packs that can be mounted by the game.
|
|
rage::fiDevice::SetMaxMounts(MAX_ARCHIVES_MOUNTED);
|
|
|
|
//Set the maximum number of extra mounts (DLC packs) that can be mounted by the game.
|
|
rage::fiDevice::SetMaxExtraMounts(MAX_EXTRA_MOUNTS);
|
|
|
|
// The parser needs to be initialized before fwConfigManager.
|
|
INIT_PARSER; // no dependencies
|
|
|
|
// Even though Init() might not do anything, we call it to do a Eager Instantiation
|
|
// (see http://www.codeproject.com/Articles/96942/Singleton-Design-Pattern-and-Thread-Safety).
|
|
// However, we cannot use the DCLP approach as its not actually thread safe,
|
|
// see http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf for a detailed explanation.
|
|
sysUserList::GetInstance().Init();
|
|
g_SysService.InitClass();
|
|
|
|
ORBIS_ONLY( g_rlNp.InitServiceDelegate(); )
|
|
|
|
CStreaming::InitStreamingVisualize();
|
|
CFileMgr::Initialise();
|
|
|
|
// AppContent relies on CFileMgr init
|
|
#if RSG_DURANGO
|
|
// The TitleID is read from the AppXManifest using rlXblTitleId::GetXboxLiveConfigurationTitleId().
|
|
// The Japanese title is hard coded below. The game compares the title IDs at runtime in sysAppContent::Init.
|
|
// If a match is found between the Japanese title ID and the runtime title ID, we know we're using the Japanese build.
|
|
sysAppContent::SetTitleId(rlXblTitleId::GetXboxLiveConfigurationTitleId());
|
|
sysAppContent::SetJapaneseTitleId(0x3E961D5B); // from the XDP GTAV Japanese config. Change for other titles.
|
|
#endif
|
|
sysAppContent::Init();
|
|
|
|
#if !__FINAL
|
|
const char* gameConfigPath;
|
|
if(PARAM_altGameConfig.Get(gameConfigPath))
|
|
{
|
|
if(Verifyf(ASSET.Exists(gameConfigPath,""),"Specified altGameConfig file was not found. Falling back to GTAV gameconfig"))
|
|
fwConfigManagerImpl<CGameConfig>::InitClass(gameConfigPath);
|
|
else
|
|
fwConfigManagerImpl<CGameConfig>::InitClass(GAMECFG_FILENAME);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
fwConfigManagerImpl<CGameConfig>::InitClass(GAMECFG_FILENAME);
|
|
}
|
|
|
|
fwInstanceBuffer::InitClass();
|
|
|
|
// Apply override from configuration file.
|
|
sysIpcPriority streamerThreadPriority = PRIO_STREAMER_THREAD;
|
|
|
|
// number of handles used by streamer has to be a power of two
|
|
const s32 cpuId = __XENON || RSG_DURANGO ? 1 : 0;
|
|
pgStreamer::InitClass(cpuId, streamerThreadPriority);
|
|
|
|
// If we're using SysTrayRFS, we should reduce the thread priority for the reader - SysTrayRFS has considerable
|
|
// CPU overhead and interferes with the render thread.
|
|
#if __PPU && !__FINAL && 0
|
|
if (!sysBootManager::IsBootedFromDisc())
|
|
{
|
|
// Are we using SysTrayRFS?
|
|
const fiDevice *device = fiDevice::GetDevice("common:/data")->GetLowLevelDevice();
|
|
|
|
if (device == &fiDeviceRemote::GetInstance())
|
|
{
|
|
Warningf("Using SysTrayRFS - decreasing DVD Reader thread priority to normal");
|
|
|
|
pgStreamer::SetReaderThreadPriority(pgStreamer::OPTICAL, PRIO_BELOW_NORMAL);
|
|
}
|
|
}
|
|
#endif // __PPU && !__FINAL
|
|
|
|
InitAfterConfigLoad();
|
|
|
|
// enable HDR
|
|
#if __D3D // || __PPU // we don't want grctfA16B16G16R16F front buffer on PSN
|
|
PARAM_hdr.Set("1");
|
|
#endif
|
|
|
|
// enable floating point zbuffer on 360
|
|
#if __XENON
|
|
PARAM_fpz.Set("1");
|
|
#endif
|
|
|
|
// HACK for B*1536627, "[PT] Crash During Father/Son. game crashes whilst driving near the golf course."
|
|
//
|
|
// Silently ignoring errors in non-final builds, then crashing in final builds
|
|
// is just stupid. Ok, it's not completely silently ignored, but it is just a
|
|
// grcErrorf, which is basically the same thing. Need to make the error much
|
|
// louder so that they all get fixed before we start testing final builds.
|
|
//
|
|
// #if !__D3D11 && __FINAL
|
|
// // Simply die on unloaded shaders.
|
|
// grcEffect::SetEnableFallback(false);
|
|
// #endif
|
|
|
|
#if __XENON && 1 //force device size to be 1280x720 and let the aspect ratio and video scaler sort out the rest
|
|
if(!PARAM_width.Get())
|
|
PARAM_width.Set("1280");
|
|
if(!PARAM_height.Get())
|
|
PARAM_height.Set("720");
|
|
#endif
|
|
|
|
#if RSG_ORBIS || RSG_DURANGO
|
|
if(!PARAM_width.Get())
|
|
PARAM_width.Set("1920");
|
|
if(!PARAM_height.Get())
|
|
PARAM_height.Set("1080");
|
|
if(!PARAM_multiSample.Get())
|
|
PARAM_multiSample.Set("4");
|
|
if(!PARAM_multiFragment.Get())
|
|
PARAM_multiFragment.Set("1");
|
|
#endif
|
|
|
|
#if __PPU
|
|
PARAM_MSAA.Set("MSAA_NONE");
|
|
if(!PARAM_nodepth.Get())
|
|
PARAM_nodepth.Set("1");
|
|
if(!PARAM_force720.Get())
|
|
PARAM_force720.Set("1");
|
|
#endif // __PPU
|
|
#if FORCE_FRAME_LIMIT
|
|
PARAM_frameLimit.Get(gFrameLimit);
|
|
#endif
|
|
|
|
#if RENDERDOC_ENABLED
|
|
RenderDocManager::Init();
|
|
#endif
|
|
|
|
grcDevice::InitSingleton();
|
|
|
|
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
|
|
// Load PC settings
|
|
CSettingsManager& settingsManager = CSettingsManager::GetInstance();
|
|
settingsManager.Initialize();
|
|
const Settings& settings = settingsManager.GetSettings();
|
|
|
|
GRCDEVICE.SetSize(settings.m_video.m_ScreenWidth, settings.m_video.m_ScreenHeight);
|
|
GRCDEVICE.InitGlobalWindow();
|
|
#if RSG_PC
|
|
grcEffect::SetShaderQuality(settings.m_graphics.m_ShaderQuality);
|
|
#endif // RSG_PC
|
|
#endif
|
|
|
|
#if !RSG_PC
|
|
VideoResManager::Init();
|
|
|
|
if(!CHudTools::GetWideScreen())
|
|
GRCDEVICE.SetLetterBox(false);
|
|
#endif
|
|
|
|
#if __WIN32PC && __BANK
|
|
// Our "native" windows are incompatible with render thread owning the D3D device. Use RAG or local widgets.
|
|
bkWidget::DisableWindows();
|
|
#endif
|
|
|
|
#if VIDEO_RECORDING_ENABLED && RSG_DURANGO
|
|
|
|
#if defined(USE_MMF_XMEM_OVERRIDE_INSTANCE) && USE_MMF_XMEM_OVERRIDE_INSTANCE
|
|
|
|
#if defined(USE_MMF_DECODE_HOOK_ONLY) && USE_MMF_DECODE_HOOK_ONLY
|
|
|
|
MEDIA_MEMORY_WRAPPER.Init( sysMemManager::GetInstance().GetReplayAllocator() );
|
|
|
|
#else
|
|
|
|
const CConfigMediaTranscoding& mediaTranscodingConfig = CGameConfig::Get().GetConfigMediaTranscoding();
|
|
|
|
// Initialize our memory blocks for media
|
|
int const c_smallMemSize = mediaTranscodingConfig.m_TranscodingSmallObjectBuffer;
|
|
int const c_smallMaxPointers = mediaTranscodingConfig.m_TranscodingSmallObjectMaxPointers;
|
|
int const c_memSize = mediaTranscodingConfig.m_TranscodingBuffer;
|
|
int const c_maxPointers = mediaTranscodingConfig.m_TranscodingMaxPointers;
|
|
if( Verifyf( c_smallMemSize > 0 && c_memSize > 0 && c_smallMaxPointers > 0 && c_maxPointers > 0,
|
|
"CConfigMediaTranscoding - Invalid values for Media Transcoding memory - %d small objects (MAX), %d small object bytes, %d objects (MAX), %d objects size",
|
|
c_smallMaxPointers, c_smallMemSize, c_maxPointers, c_memSize ) )
|
|
{
|
|
MEDIA_MEMORY_WRAPPER.Init( c_smallMemSize * 1024, (size_t)c_smallMaxPointers, c_memSize * 1024, (size_t)c_maxPointers, sysMemManager::GetInstance().GetReplayAllocator() );
|
|
}
|
|
|
|
#endif // defined(USE_MMF_DECODE_HOOK_ONLY) && USE_MMF_DECODE_HOOK_ONLY
|
|
|
|
rage::MediaTranscodingMemorySystem::SetXMemInstance( &MEDIA_MEMORY_WRAPPER );
|
|
sysMemSetXMemHooks( eXALLOCAllocatorId_Video, rage::MediaTranscodingMemorySystem::sysMemXMemAllocHook, rage::MediaTranscodingMemorySystem::sysMemXMemFreeHook);
|
|
|
|
#endif // defined(USE_MMF_XMEM_OVERRIDE_INSTANCE) && USE_MMF_XMEM_OVERRIDE_INSTANCE
|
|
|
|
#endif // VIDEO_RECORDING_ENABLED && RSG_DURANGO && USE_MMF_XMEM_ALLOC_HOOK
|
|
|
|
grcSetupInstance = rage_new grmSetup;
|
|
|
|
GRCDEVICE.SetDefaultEffectName("common:/shaders/im");
|
|
#if DEVICE_EQAA
|
|
eqaa::SetEffectName("common:/shaders/ClearCS");
|
|
#endif
|
|
|
|
GetRageSetup()->Init( CFileMgr::GetRootDirectory(), pAppName);
|
|
|
|
#if __BANK
|
|
settingsManager.CreateWidgets();
|
|
#endif
|
|
|
|
INIT_BUDGETDISPLAY;
|
|
|
|
grcEffect::SetDefaultPath("common:/shaders");
|
|
#if __XENON
|
|
// DW - just a guess at num segments so far. 0 for segment sizes yields default of 32
|
|
// We're talking Kb here. SetRingBufferParameters actually does a a shift by 10
|
|
GRCDEVICE.SetRingBufferParameters(64,7168,64,true);
|
|
#endif
|
|
|
|
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_RENDER);
|
|
|
|
gRenderThreadInterface.Init(PRIO_RENDER_THREAD,RenderThreadInit);
|
|
|
|
CSystem::ClearThisThreadId(SYS_THREAD_RENDER); // this is no longer the render thread
|
|
#if __BANK && RSG_PC
|
|
grcResourceCache::GetInstance().InitWidgets();
|
|
#endif // __BANK
|
|
|
|
}
|
|
|
|
#if RSG_PC
|
|
VideoResManager::Init();
|
|
|
|
if(!CHudTools::GetWideScreen())
|
|
GRCDEVICE.SetLetterBox(false);
|
|
|
|
GRCDEVICE.InitFocusQueryThread();
|
|
#endif
|
|
|
|
USE_MEMBUCKET(MEMBUCKET_DEFAULT);
|
|
|
|
fwTimer::Init(); // no dependencies
|
|
CControlMgr::Init(INIT_CORE);// no dependencies
|
|
|
|
#if ENABLE_AUTOMATED_TESTS
|
|
AutomatedTest::Init();
|
|
#endif // ENABLE_AUTOMATED_TESTS
|
|
|
|
// if both left and right shoulder pads are pressed then clear the disk cache
|
|
CControlMgr::Update();
|
|
if(CControlMgr::GetPlayerPad() && CControlMgr::GetPlayerPad()->GetLeftShoulder1() && CControlMgr::GetPlayerPad()->GetRightShoulder1())
|
|
{
|
|
OUTPUT_ONLY(printf("Clearing HDD cache\n"));
|
|
PARAM_clearhddcache.Set("1");
|
|
PARAM_ignoreprofile.Set("1");
|
|
}
|
|
|
|
SetWindowsSystemParameters();// no dependencies
|
|
|
|
// create default task scheduler
|
|
// Determine the priority, from the default value or an override in the configuration file.
|
|
sysIpcPriority sysTaskPri = CGameConfig::Get().GetThreadPriority(ATSTRINGHASH("systask", 0x0461fa38d), SYS_DEFAULT_TASK_PRIORITY);
|
|
|
|
# if __DEV
|
|
const unsigned stackSize = 0x18000;
|
|
# else
|
|
const unsigned stackSize = 0x10000;
|
|
# endif
|
|
const unsigned scratchSize = 0x8000;
|
|
|
|
u32 cpuMask = SYS_DEFAULT_TASK_THREAD_MASK;
|
|
#if RSG_PC
|
|
u32 numTaskSchedulers = SYS_DEPENDENCY_TASKACTIVENUMWORKERS;
|
|
if (PARAM_numTaskSchedulers.Get(numTaskSchedulers))
|
|
{
|
|
numTaskSchedulers = (numTaskSchedulers > 1) ? numTaskSchedulers : 1;
|
|
}
|
|
|
|
cpuMask = (1 << numTaskSchedulers) - 1;
|
|
#endif // RSG_PC
|
|
|
|
sysTaskManager::AddScheduler("gtaSched", stackSize, scratchSize, sysTaskPri, cpuMask,2);
|
|
|
|
#if __BANK
|
|
g_PickerManager.InitClass(rage_new CGtaPickerInterface());
|
|
#endif // __BANK
|
|
|
|
// Set the main thread's priority and core affinity.
|
|
const CThreadSetup* pThreadSetup = CGameConfig::Get().GetThreadSetup(ATSTRINGHASH("Update", 0x0b6a7a93e));
|
|
if(pThreadSetup)
|
|
{
|
|
sysIpcSetThreadPriority(sysIpcGetThreadId(), pThreadSetup->GetPriority(sysIpcGetCurrentThreadPriority()));
|
|
#if RSG_DURANGO || RSG_ORBIS
|
|
sysIpcSetThreadProcessorMask(sysIpcGetThreadId(), pThreadSetup->GetCpuAffinityMask( (1<<0) ));
|
|
#endif
|
|
}
|
|
|
|
#if RSG_PC
|
|
if(CSettingsManager::GetInstance().IsLowQualitySystem())
|
|
{
|
|
// AMD min spec video card + 4-core CPU. Extremely render thread
|
|
// bound in this case because of single-threaded driver, we hard-code
|
|
// a swap of main thread and render thread priorities in this case.
|
|
const CThreadSetup* pUpdateThreadSetup = CGameConfig::Get().GetThreadSetup(ATSTRINGHASH("Update", 0x0b6a7a93e));
|
|
const CThreadSetup* pRenderThreadSetup = CGameConfig::Get().GetThreadSetup(ATSTRINGHASH("Render", 0x8EE0C0F));
|
|
if(pUpdateThreadSetup && pRenderThreadSetup)
|
|
{
|
|
// Set Update thread prio to render thread prio.
|
|
sysIpcSetThreadPriority(sysIpcGetThreadId(), pRenderThreadSetup->GetPriority(sysIpcGetCurrentThreadPriority()));
|
|
|
|
// Set Render thread prio to update thread prio.
|
|
sysIpcSetThreadPriority(gRenderThreadInterface.GetRenderThreadId(), pUpdateThreadSetup->GetPriority(sysIpcGetCurrentThreadPriority()));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Now is a great time to let the command line override existing thread priorities, and add the main thread.
|
|
#if THREAD_REGISTRY
|
|
sysThreadRegistry::RegisterThread(sysIpcGetThreadId(), sysIpcGetCurrentThreadPriority(), "Main Thread", "update", true);
|
|
sysThreadRegistry::AdjustPriosBasedOnParams();
|
|
#endif // THREAD_REGISTRY
|
|
|
|
InitDLCCommands();
|
|
|
|
#if RSG_ORBIS && !__FINAL
|
|
if( PARAM_enableGpuTraceCapture.Get() )
|
|
{
|
|
grcGpuTraceGNM::InitClass();
|
|
|
|
SceRazorGpuThreadTraceParams params;
|
|
grcGpuTraceGNM::InitThreadTraceParams(¶ms, grcGpuTraceGNM::grcTraceFrequencyLow);
|
|
|
|
SceRazorGpuErrorCode ret = 0;
|
|
uint32_t *streamingCounters = params.streamingCounters;
|
|
|
|
ret |= sceRazorGpuCreateStreamingCounter(streamingCounters++, sce::Gnm::kCbPerfCounterDrawnBusy, SCE_RAZOR_GPU_BROADCAST_ALL);
|
|
ret |= sceRazorGpuCreateStreamingCounter(streamingCounters++, sce::Gnm::kCbPerfCounterDrawnPixel, SCE_RAZOR_GPU_BROADCAST_ALL);
|
|
|
|
int numCounters = streamingCounters - params.streamingCounters;
|
|
Assert(ret == SCE_OK);
|
|
|
|
grcGpuTraceGNM::InitThreadTrace(¶ms, numCounters);
|
|
}
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
|
|
return true;
|
|
}
|
|
|
|
// name: CSystem::RegisterDrawListCommands
|
|
// description: Register all custom draw list commands managed by CSystem
|
|
void CSystem::InitDLCCommands()
|
|
{
|
|
DLC_REGISTER_EXTERNAL(dlCmdBeginRender);
|
|
DLC_REGISTER_EXTERNAL(dlCmdEndRender);
|
|
|
|
// TODO: When this function gets moved to framework, please update UpdateTask functions in clothManager.cpp and ropeManager.cpp to call it so we don't have to copy-paste code around
|
|
// Svetli
|
|
#if RSG_PC &&__D3D11
|
|
// DX11 TODO:- Find a place within rage or the framework where this can be called so it`s not game specific.
|
|
// This means dlCmdGrcDeviceUpdateBuffer::AddBufferUpdateCommandToDrawList() is called whenever a vertex/index buffer
|
|
// is altered on this thread. The render thread then passes the new contents to the GPU by executing a DL command.
|
|
grcBufferD3D11::SetInsertUpdateCommandIntoDrawListFunc(dlCmdGrcDeviceUpdateBuffer::AddBufferUpdate);
|
|
// Occasionally a buffer is updated and deleted in the same frame. This mechanism avoids operating on a deleted buffer.
|
|
grcBufferD3D11::SetCancelPendingUpdateGPUCopy(dlCmdGrcDeviceUpdateBuffer::CancelBufferUpdate);
|
|
grcBufferD3D11::SetAllocTempMemory(dlCmdGrcDeviceUpdateBuffer::AllocTempMemory);
|
|
|
|
// Similar, only for textures.
|
|
grcTextureD3D11::SetInsertUpdateCommandIntoDrawListFunc(dlCmdGrcDeviceUpdateBuffer::AddTextureUpdate);
|
|
grcTextureD3D11::SetCancelPendingUpdateGPUCopy(dlCmdGrcDeviceUpdateBuffer::CancelBufferUpdate);
|
|
grcTextureD3D11::SetAllocTempMemory(dlCmdGrcDeviceUpdateBuffer::AllocTempMemory);
|
|
#endif // RSG_PC && __D3D11
|
|
}
|
|
|
|
#if RSG_ORBIS &!__FINAL
|
|
void CSystem::StartGPUTraceCapture()
|
|
{
|
|
Assert(CSystem::IsThisThreadId(SYS_THREAD_UPDATE));
|
|
|
|
g_requestedTraceCapture = true;
|
|
}
|
|
#endif // RSG_ORBIS &!__FINAL
|
|
|
|
|
|
#if !__NO_OUTPUT
|
|
void CSystem::CenteredPrint(float yPos, const char *string)
|
|
{
|
|
int width = grcFont::GetCurrent().GetStringWidth(string, istrlen(string));
|
|
|
|
grcFont::GetCurrent().Draw((float) (GRCDEVICE.GetWidth() - width) / 2.0f, yPos, string);
|
|
}
|
|
|
|
void CSystem::RenderBuildInformation()
|
|
{
|
|
if (!CSystem::BeginRender())
|
|
{
|
|
return;
|
|
}
|
|
|
|
{
|
|
GRC_ALLOC_SCOPE_AUTO_PUSH_POP()
|
|
|
|
#if __PS3
|
|
grcTextureFactory::GetInstance().BindDefaultRenderTargets();
|
|
#elif RSG_DURANGO && _XDK_VER >= 10542
|
|
// Feb XDK unbinds RT and depth/stencil on present
|
|
grcTextureFactory::GetInstance().LockRenderTarget(0, grcTextureFactory::GetInstance().GetBackBuffer(), grcTextureFactory::GetInstance().GetBackBufferDepth());
|
|
#endif
|
|
|
|
const grcViewport* pVp = grcViewport::GetDefaultScreen();
|
|
grcViewport::SetCurrent(pVp);
|
|
|
|
grcStateBlock::SetBlendState(grcStateBlock::BS_Normal);
|
|
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
|
|
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
|
|
|
|
grcLightState::SetEnabled(false);
|
|
grcWorldIdentity();
|
|
|
|
#if RSG_ORBIS || RSG_DURANGO || RSG_PC
|
|
GRCDEVICE.Clear( true, Color32(0,0,32,255), false, 1.0f, false, 0 );
|
|
#elif __PS3
|
|
GRCDEVICE.ClearRect(0, 0, GRCDEVICE.GetWidth(), GRCDEVICE.GetHeight(), true, Color32(0,0,32,255),false,1.0f,false,0);
|
|
#else //__PS3
|
|
GRCDEVICE.ClearRect(0, 0, GRCDEVICE.GetWidth(), GRCDEVICE.GetHeight(), 0.0f, Color32(0,0,32,255));
|
|
#endif //__PS3
|
|
|
|
// Force a flush of these shader variables to make sure they're being set
|
|
CShaderLib::SetGlobalAlpha(0.0f);
|
|
CShaderLib::SetGlobalEmissiveScale(0.0f);
|
|
|
|
CShaderLib::SetGlobalAlpha(1.0f);
|
|
CShaderLib::SetGlobalEmissiveScale(1.0f);
|
|
|
|
#if __XENON
|
|
GRCDEVICE.SetColorExpBiasNow(0);
|
|
#endif // __XENON
|
|
|
|
PUSH_DEFAULT_SCREEN();
|
|
grcFont::GetCurrent().SetInternalColor(Color32(0xffffffff));
|
|
grcFont::GetCurrent().SetInternalScale(1.5f);
|
|
|
|
float fontHeight = (float) grcFont::GetCurrent().GetHeight();
|
|
|
|
// "Animate" the title.
|
|
u32 animCycle = (sysTimer::GetSystemMsTime() / 1000) & 3;
|
|
const char *suffix = "...";
|
|
const char *suffix2 = " ";
|
|
char title[64];
|
|
formatf(title, "Now loading Grand Theft Auto V%s%s", &suffix[3 - animCycle], &suffix2[animCycle]);
|
|
|
|
CenteredPrint(100.0f, title);
|
|
|
|
CenteredPrint(130.0f, RSG_PLATFORM " " RSG_CONFIGURATION);
|
|
|
|
const char* cVersionNumber = CDebug::GetVersionNumber();
|
|
if( cVersionNumber[0] != 0 )
|
|
{
|
|
formatf(title, "v%s", cVersionNumber);
|
|
CenteredPrint(145.0f, title);
|
|
}
|
|
|
|
const char *localHost = fiDeviceTcpIp::GetLocalHost();
|
|
formatf(title, "Workstation IP: %s", localHost);
|
|
CenteredPrint(170.0f, title);
|
|
|
|
CenteredPrint(210.0f, "Command line arguments:");
|
|
|
|
const float yTop = 230.0f;
|
|
float yPos = yTop;
|
|
|
|
int argCount = sysParam::GetArgCount();
|
|
for (int x=1; x<argCount; x++)
|
|
{
|
|
const char *arg = sysParam::GetArg(x);
|
|
// Skip disabled arguments.
|
|
if (arg[1] == 'X')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CenteredPrint(yPos, arg);
|
|
yPos += fontHeight;
|
|
}
|
|
|
|
POP_DEFAULT_SCREEN();
|
|
|
|
#if RSG_DURANGO && _XDK_VER >= 10542
|
|
// Feb XDK unbinds RT and depth/stencil on present
|
|
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
|
|
#endif
|
|
grcFont::GetCurrent().SetInternalScale(1.0f);
|
|
|
|
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
|
|
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
|
|
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
|
|
}
|
|
CSystem::EndRender();
|
|
}
|
|
#endif // !__NO_OUTPUT
|
|
|
|
void CSystem::InitAfterConfigLoad()
|
|
{
|
|
const fwConfigManager& mgr = fwConfigManager::GetInstance();
|
|
|
|
fwArchetypeManager::SetMaxArchetypes(mgr.GetSizeOfPool(ATSTRINGHASH("fwArchetypePooledMap", 0x76bc4f20), CONFIGURED_FROM_FILE));
|
|
|
|
// Determine the value of MAXNOOFPEDS and VEHICLE_POOL_SIZE, from the
|
|
// configuration file.
|
|
CPoolHelpers::SetPedPoolSize(mgr.GetSizeOfPool(ATSTRINGHASH("Peds", 0x8da12117), CONFIGURED_FROM_FILE));
|
|
CPoolHelpers::SetVehiclePoolSize(mgr.GetSizeOfPool(ATSTRINGHASH("Vehicles", 0x74b31be3), CONFIGURED_FROM_FILE));
|
|
CVehiclePopulation::ms_maxNumberOfCarsInUse = VEHICLE_POOL_SIZE;
|
|
}
|
|
|
|
//
|
|
// name: CSystem::Shutdown
|
|
// description: Shutdown system level classes
|
|
void CSystem::Shutdown()
|
|
{
|
|
#if defined(VIDEO_RECORDING_ENABLED) && VIDEO_RECORDING_ENABLED
|
|
VideoRecording::RenderThreadCleanup();
|
|
#endif
|
|
|
|
g_SysService.ShutdownClass();
|
|
sysUserList::GetInstance().Shutdown();
|
|
sysAppContent::Shutdown();
|
|
|
|
SHUTDOWN_PARSER;
|
|
|
|
CShaderLib::Shutdown();
|
|
CControlMgr::Shutdown(SHUTDOWN_CORE);
|
|
|
|
#if __BANK
|
|
g_PickerManager.ShutdownClass();
|
|
#endif // __BANK
|
|
|
|
pgStreamer::ShutdownClass(); // Used to be done within strStreamingEngine::Shutdown().
|
|
|
|
grmSetup* setup = GetRageSetup();
|
|
if(setup)
|
|
{
|
|
setup->DestroyFactories();
|
|
// setup->EndGfx();
|
|
setup->Shutdown();
|
|
delete GetRageSetup();
|
|
grcSetupInstance = NULL;
|
|
}
|
|
|
|
#if VIDEO_RECORDING_ENABLED && RSG_DURANGO && USE_MMF_XMEM_OVERRIDE_INSTANCE
|
|
|
|
sysMemSetXMemHooks( eXALLOCAllocatorId_Video, XMemAllocDefault, XMemFreeDefault);
|
|
rage::MediaTranscodingMemorySystem::SetXMemInstance( NULL );
|
|
MEDIA_MEMORY_WRAPPER.Shutdown();
|
|
|
|
#endif // VIDEO_RECORDING_ENABLED && RSG_DURANGO && USE_MMF_XMEM_ALLOC_HOOK
|
|
|
|
fwInstanceBuffer::ShutdownClass();
|
|
|
|
fwConfigManager::ShutdownClass();
|
|
|
|
#if RENDERDOC_ENABLED
|
|
RenderDocManager::Shutdown();
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// name: CSystem::BeginUpdate
|
|
// description: Called at the beginning of the update
|
|
void CSystem::BeginUpdate()
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
|
|
// DW / JG - because the widget code can call viewport sphere visibility code via the streaming cleanup
|
|
// of create car, I have decided to put this here so that all widget code by default will assume access
|
|
// to viewports is the GAME viewport.
|
|
CViewport *pVp = gVpMan.GetGameViewport();
|
|
if (pVp)
|
|
gVpMan.PushViewport(pVp);
|
|
|
|
// Give the reservation back when non-gameplay menu is active (this is a Microsoft requirement)
|
|
DURANGO_ONLY( GRCDEVICE.SetNuiGPUReservation(CPauseMenu::IsActive()) );
|
|
|
|
GetRageSetup()->BeginUpdate();
|
|
|
|
if (pVp)
|
|
gVpMan.PopViewport();
|
|
|
|
fwTimer::Update();
|
|
|
|
g_SysService.UpdateClass();
|
|
|
|
#if __XENON && __ASSERT
|
|
MEMORYSTATUS ms;
|
|
GlobalMemoryStatus(&ms);
|
|
size_t remain = ms.dwAvailPhys >> 10;
|
|
Assertf(remain > 100, "Free title memory below safe value (100k) : %dk", remain); // e.g. MP voice chat requires 80k of title free mem...
|
|
#endif //__XENON && __ASSERT
|
|
|
|
#if __PS3
|
|
static u32 frameCount = 0;
|
|
frameCount = (frameCount+1)%2000;
|
|
if (frameCount == 0)
|
|
{
|
|
if (snIsDebuggerRunning() != 0)
|
|
{
|
|
Displayf("debugger detected");
|
|
ms_bDebuggerDetected = true;
|
|
CNetworkTelemetry::AppendDebuggerDetect(1);
|
|
}
|
|
}
|
|
#endif //__PS3
|
|
}
|
|
|
|
//
|
|
// name: CSystem::EndUpdate
|
|
// description: Called at the end of the update
|
|
void CSystem::EndUpdate()
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
|
|
GetRageSetup()->EndUpdate(fwTimer::IsGamePaused()?0.0f:fwTimer::GetTimeStepInMilliseconds());
|
|
|
|
//grcDebugDraw::AddDebugOutput("None: %d Nonresident: %d", grcTexture::None->GetRefCount(), grcTexture::Nonresident->GetRefCount());
|
|
// Add-on to rage's changelist #130399:
|
|
//grcTexture::None->SetRefCount(32768);
|
|
//grcTexture::Nonresident->SetRefCount(32768);
|
|
|
|
fwInstanceBuffer::NextFrame();
|
|
}
|
|
|
|
//
|
|
// name: CSystem::BeginRender
|
|
// description: Called at the beginning of the render
|
|
bool CSystem::BeginRender()
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
|
|
if (!GetRageSetup()->BeginDraw(false))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#if __BANK && __XENON
|
|
StartRingBufferMemUsage();
|
|
#endif
|
|
|
|
#if RSG_ORBIS && !__FINAL
|
|
if( PARAM_enableGpuTraceCapture.Get() )
|
|
{
|
|
if( g_traceCaptureState == 0 )
|
|
{
|
|
grcGpuTraceGNM::Start();
|
|
g_traceCaptureState++;
|
|
}
|
|
}
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
|
|
#if __D3D11 && RSG_PC
|
|
grcTextureD3D11::SetInsertUpdateCommandIntoDrawListFunc(dlCmdGrcDeviceUpdateBuffer::AddTextureUpdate);
|
|
grcTextureD3D11::SetCancelPendingUpdateGPUCopy(dlCmdGrcDeviceUpdateBuffer::CancelBufferUpdate);
|
|
#endif //__D3D11 && RSG_PC
|
|
|
|
VIDEO_PLAYBACK_ONLY( VideoPlayback::UpdatePreRender() );
|
|
VIDEO_PLAYBACK_ONLY( VideoPlaybackThumbnailManager::UpdateThumbnailFrames() );
|
|
|
|
#if __D3D11 && RSG_PC
|
|
grcTextureD3D11::SetInsertUpdateCommandIntoDrawListFunc(NULL);
|
|
grcTextureD3D11::SetCancelPendingUpdateGPUCopy(NULL);
|
|
#endif
|
|
|
|
CScaleformMgr::BeginFrame();
|
|
|
|
# if RSG_PC && __D3D11
|
|
DECALMGR.PrimaryRenderThreadBeginFrameCallback();
|
|
# endif
|
|
|
|
return true;
|
|
}
|
|
|
|
// drawlist version of begin render
|
|
void CSystem::AddDrawList_BeginRender()
|
|
{
|
|
gDrawListMgr->BeginDrawListCreation();
|
|
|
|
DLC(dlCmdNewDrawList, (DL_BEGIN_DRAW));
|
|
#if RSG_PC && __D3D11
|
|
dlCmdGrcDeviceUpdateBuffer::OnBeginRender();
|
|
#endif // RSG_PC && __D3D11
|
|
|
|
#if DEBUG_DRAW
|
|
grcDebugDraw::Update();
|
|
#endif // DEBUG_DRAW
|
|
|
|
DLC_Add(CRenderTargets::ResetRenderThreadInfo);
|
|
g_timeCycle.SetupRenderThreadFrameInfo();
|
|
Lights::SetupRenderthreadFrameInfo();
|
|
CRenderPhaseCascadeShadowsInterface::ResetRenderThreadInfo();
|
|
|
|
CVisualEffects::SetupRenderThreadFrameInfo();
|
|
g_ptFxManager.BeginFrame();
|
|
|
|
DLC(CSetDrawableLODCalcPos, (camInterface::GetPos()));
|
|
DLC(dlCmdBeginRender, ());
|
|
// if (g_draw_cached_entities)
|
|
// DLC(CCreateRenderListGroupDC, ());
|
|
CParaboloidShadow::UpdateActiveCachesfromStatic();
|
|
#if SHADOW_ENABLE_ASYNC_CLEAR
|
|
DLC_Add(CRenderPhaseCascadeShadowsInterface::ClearShadowMapsAsync);
|
|
#endif
|
|
gDrawListMgr->EndCurrentDrawList();
|
|
}
|
|
|
|
|
|
// Zeno frame limiter
|
|
inline void FrameLimiter()
|
|
{
|
|
#if FORCE_FRAME_LIMIT
|
|
PF_PUSH_TIMEBAR("Frame Limit");
|
|
// PC should frame-limits here any time it's in full-screen mode; windowed mode will do a manual WaitForVBlank at a lower level in grcDevice::EndFrame
|
|
if ( ((gFrameLimit > 0) || RSG_PC) DEV_ONLY(|| fwTimer::GetForceMinimumFrameRate() || fwTimer::GetForceMaximumFrameRate()) )
|
|
{
|
|
// frame limiter. Game runs at max speed of some many frames per second. This has to be at the end of this function
|
|
float frameTime = gFrameTimer.GetTime();
|
|
#if RSG_PC
|
|
const float fRefreshRate = static_cast<float>( grcDevice::GetRefreshRate() );
|
|
const float fVSync = static_cast<float>( CSettingsManager::GetInstance().GetSettings().m_video.m_VSync );
|
|
|
|
// If v-sync is disabled (fVSync==0) or we get an invalid refresh rate then use 1/256 which was the previously hardcoded minFrameTime for PC
|
|
float minFrameTime = (fVSync > 0.0f) && (fRefreshRate > 0.0f) ? (fVSync / fRefreshRate) : (1.0f / 256.0f);
|
|
#else
|
|
float minFrameTime = gFrameLimit/60.0f;
|
|
#endif
|
|
|
|
// Let us out of the busy wait early enough to meet up with the v-sync. This is necessary since
|
|
// we still have a bit of work to do after the busy wait before we call Present in GetRageSetup()->EndDraw()
|
|
const float slopTime = minFrameTime * 0.05f;
|
|
|
|
#if !__FINAL && !RSG_PC
|
|
// debug to let us force a slow and/or uneven frame rate
|
|
if(fwTimer::GetForceMaximumFrameRate())
|
|
minFrameTime = fwTimer::GetMinimumFrameTime();
|
|
if(fwTimer::GetForceMinimumFrameRate())
|
|
minFrameTime = fwTimer::GetMaximumFrameTime();
|
|
else if(fwTimer::GetForceUnevenFrameRate() && fwTimer::GetSystemFrameCount()&1)
|
|
minFrameTime = fwTimer::GetMaximumFrameTime();
|
|
#endif
|
|
|
|
while ((frameTime+slopTime) < minFrameTime)
|
|
{
|
|
// Sleep for half the difference
|
|
int zeno = int((minFrameTime-frameTime)*1000)/2;
|
|
sysIpcSleep(zeno);
|
|
|
|
frameTime = gFrameTimer.GetTime();
|
|
}
|
|
|
|
// frame timer has to be at the top of this function
|
|
gFrameTimer.Reset();
|
|
}
|
|
PF_POP_TIMEBAR();
|
|
#endif // USE_FRAME_LIMIT
|
|
}
|
|
|
|
|
|
//
|
|
// name: CSystem::EndRender
|
|
// description: Called at the end of the render
|
|
void CSystem::EndRender()
|
|
{
|
|
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
|
|
|
|
// reset default vp mapping to Screen() as expected by stuff in grcSetup::EndDraw() (e.g. RAG mouse cursor):
|
|
CSprite2d::ResetDefaultScreenVP();
|
|
|
|
CScaleformMgr::EndFrame();
|
|
|
|
#if __BANK && __XENON
|
|
EndRingBufferMemUsage();
|
|
#endif
|
|
|
|
#if FRAME_LIMIT_BEFORE_PRESENT
|
|
#if RSG_DURANGO
|
|
if (CLoadingScreens::GetCurrentContext() != LOADINGSCREEN_CONTEXT_INTRO_MOVIE)
|
|
#endif
|
|
FrameLimiter();
|
|
#endif
|
|
|
|
|
|
#if !__FINAL
|
|
PUSH_DEFAULT_SCREEN();
|
|
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
|
|
STREAM_TICKER_ONLY( StrTicker::Draw(60.0f,300.0f) );
|
|
POP_DEFAULT_SCREEN();
|
|
#endif
|
|
|
|
|
|
PF_PUSH_TIMEBAR_DETAIL("grmSetup EndDraw");
|
|
GetRageSetup()->EndDraw();
|
|
PF_POP_TIMEBAR_DETAIL();
|
|
|
|
#if FRAME_LIMIT_AFTER_PRESENT
|
|
FrameLimiter();
|
|
#endif
|
|
|
|
#if __PPU
|
|
// only this thread should pick up the base signal - all over threads should hang *only* on detection of g_IsExiting, which is set below
|
|
if (GetRageSetup()->WantExit())
|
|
{
|
|
printf("*** User quit or disc eject\n");
|
|
printf("*** Calling exit...\n");
|
|
g_IsExiting = true;
|
|
g_movieMgr.Shutdown(SHUTDOWN_CORE);
|
|
sysIpcSleep(1000); // Hacky, but give the worker threads enough time to see the flag before the OS starts tearing things down.
|
|
// And wait for the trophy thread, 'cos that takes longer
|
|
g_rlNp.GetTrophy().Shutdown();
|
|
_Exit(0);
|
|
}
|
|
#endif
|
|
|
|
#if RSG_ORBIS && !__FINAL
|
|
if( PARAM_enableGpuTraceCapture.Get() )
|
|
{
|
|
switch( g_traceCaptureState )
|
|
{
|
|
case 1:
|
|
grcGpuTraceGNM::Stop();
|
|
g_traceCaptureState++;
|
|
break;
|
|
case 2:
|
|
{
|
|
static int traceCapturecount = 0;
|
|
char capturename[128];
|
|
sprintf(capturename,"capture_%d",traceCapturecount++);
|
|
grcGpuTraceGNM::Save(capturename);
|
|
g_traceCaptureState++;
|
|
}
|
|
break;
|
|
case 3:
|
|
grcGpuTraceGNM::Reset();
|
|
g_traceCaptureState++;
|
|
break;
|
|
default:
|
|
/* NoOp */
|
|
break;
|
|
}
|
|
}
|
|
#endif // RSG_ORBIS && !__FINAL
|
|
}
|
|
|
|
void CSystem::AddDrawList_EndRender(){
|
|
#if RSG_PC && __D3D11
|
|
dlCmdGrcDeviceUpdateBuffer::OnEndRender();
|
|
#endif // RSG_PC && __D3D11
|
|
DLC( dlCmdNewDrawList, (DL_END_DRAW));
|
|
DLC( dlCmdInsertEndFence, ());
|
|
DLC( dlCmdEndRender, ());
|
|
g_timeCycle.ClearRenderFrameInfo();
|
|
Lights::ClearRenderthreadFrameInfo();
|
|
CVisualEffects::ClearRenderThreadFrameInfo();
|
|
gDrawListMgr->EndCurrentDrawList();
|
|
gDrawListMgr->EndDrawListCreation();
|
|
}
|
|
|
|
//
|
|
// name: CSystem::WantToExit
|
|
// description: Returns if there is a reason to exit
|
|
bool CSystem::WantToExit()
|
|
{
|
|
bool bWantToExit;
|
|
#if __WIN32PC
|
|
bWantToExit = GetRageSetup()->WantExit();
|
|
#else
|
|
bWantToExit = false; // INTENTIONALLY not hooked up to user quit any longer: GetRageSetup()->WantExit();
|
|
#endif
|
|
|
|
#if !__FINAL
|
|
bWantToExit = bWantToExit || SmokeTests::HasSmokeTestFinished();
|
|
#endif
|
|
|
|
#if RSG_PC && __DEV
|
|
bWantToExit |= CSettingsManager::ResetTestsCompleted();
|
|
#endif
|
|
// if (!bWantToExit)
|
|
// bWantToExit = (CFrontEnd::GetState() == FRONTEND_STATE_EXITAPP); // to do - new pause menu doesnt have this state...
|
|
#if RSG_PC
|
|
bWantToExit = bWantToExit || CPauseMenu::GetGameWantsToExitToWindows();
|
|
#endif
|
|
|
|
return bWantToExit;
|
|
|
|
// return GetRageSetup()->WantExit();
|
|
}
|
|
|
|
bool CSystem::WantToRestart()
|
|
{
|
|
#if RSG_PC
|
|
return CPauseMenu::GetGameWantsToRestart();
|
|
#else
|
|
return false;
|
|
#endif // RSG_PC
|
|
}
|
|
|
|
bool CSystem::IsDisplayingSystemUI()
|
|
{
|
|
return (CLiveManager::IsSystemUiShowing());
|
|
}
|
|
|
|
// set the current thread id for this thread
|
|
void CSystem::SetThisThreadId(eThreadId currThread) {
|
|
|
|
Assert(currThread != SYS_THREAD_INVALID);
|
|
sysThreadType::AddCurrentThreadType(currThread);
|
|
}
|
|
|
|
void CSystem::ClearThisThreadId(eThreadId currThread) {
|
|
Assert(currThread != SYS_THREAD_INVALID);
|
|
|
|
sysThreadType::ClearCurrentThreadType(currThread);
|
|
|
|
Assert(sysThreadType::GetCurrentThreadType() != SYS_THREAD_INVALID);
|
|
}
|
|
|
|
bool CSystem::InWindow()
|
|
{
|
|
#if __WIN32PC
|
|
bool inWindow = true;
|
|
|
|
#if !__FINAL
|
|
if (PARAM_fullscreen.Get())
|
|
inWindow = false;
|
|
else if (PARAM_windowed.Get())
|
|
inWindow = true;
|
|
#else
|
|
inWindow = false;
|
|
if (PARAM_windowed.Get())
|
|
inWindow = true;
|
|
#endif
|
|
|
|
return inWindow;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
#if (1 == __BANK) && (1 == __XENON)
|
|
|
|
//------------------------------------------
|
|
// name: RingBuffer stats system.
|
|
// description: Give usage of the ringbuffer a usage greater or equal than the ring buffer size
|
|
// is not always a bad thing : If the GPU and the CPU sync is going fine, part of
|
|
// the buffer can be reused during the same frame.
|
|
//
|
|
// NOTE: this moved from viewportManager.cpp, since we need it as close to the beginin and end of the frame as possible in the render thread
|
|
//
|
|
#if __XENON
|
|
static u32 RingBufferStart = 0xFFFFFFFF;
|
|
static u32 RingBufferEnd = 0x0;
|
|
#endif // __XENON
|
|
|
|
static u32 Global_RingBufferUsage_Min = 0xFFFFFFFF;
|
|
static u32 Global_RingBufferUsage_Max = 0x0;
|
|
static u64 Global_RingBufferUsage_Accum = 0x0;
|
|
static u32 Global_RingBufferUsage_Hit = 0x0;
|
|
|
|
static u32 Recent_RingBufferUsage_Min = 0xFFFFFFFF;
|
|
static u32 Recent_RingBufferUsage_Max = 0x0;
|
|
static u32 Recent_RingBufferUsage_Accum = 0x0;
|
|
static u32 Recent_RingBufferUsage_Hit = 0x0;
|
|
|
|
static bool Global_Reset = false;
|
|
static bool Render_RingBuffer_Stats = false;
|
|
static u32 Recent_ResetHitCount = 30*3;
|
|
|
|
static u32 CurrentFrame_RingStart;
|
|
static u32 CurrentFrame_RingLimitStart;
|
|
|
|
|
|
void CSystem::SetupRingBufferWidgets(bkBank& bank)
|
|
{
|
|
bank.PushGroup("RingBuffer",false);
|
|
bank.AddToggle("Render stats",&Render_RingBuffer_Stats);
|
|
bank.AddToggle("Reset stats",&Global_Reset);
|
|
bank.AddSlider("Reset recent stats frame count",&Recent_ResetHitCount,1,3500,1);
|
|
bank.PopGroup();
|
|
}
|
|
|
|
#if __XENON
|
|
const u32 CalcRingUsage(const u32 ringStart, const u32 ringEnd)
|
|
{
|
|
if( ringEnd < ringStart )
|
|
{
|
|
// Looped : Not counted, there's something funny in the normal usage..
|
|
return (RingBufferEnd - ringStart) + (ringEnd - RingBufferStart);
|
|
//return 0xFFFFFFFF;
|
|
}
|
|
|
|
return ringEnd - ringStart;
|
|
}
|
|
#elif __PPU
|
|
const u32 CalcRingUsage()
|
|
{
|
|
return g_commandBufferUsage;
|
|
}
|
|
#endif // __XENON || __PPU
|
|
|
|
inline u32 CalcRingSize(void)
|
|
{
|
|
#if __XENON
|
|
return RingBufferEnd - RingBufferStart;
|
|
#elif __PPU
|
|
return g_bufferSize;
|
|
#endif
|
|
}
|
|
|
|
void DisplayRingStats(void)
|
|
{
|
|
static int StartX = 100;
|
|
static int StartY = 10;
|
|
|
|
int y = StartY;
|
|
int x = StartX;
|
|
|
|
const float ringSize = (float)(CalcRingSize());
|
|
|
|
char debugText[50];
|
|
|
|
#if __XENON
|
|
sprintf(debugText,"Ring Size : %4dKb (%p - %p)",(s32)(ringSize/1024.0f),RingBufferStart,RingBufferEnd);
|
|
#else
|
|
sprintf(debugText,"Ring Size : %4dKb",(s32)(ringSize/1024.0f));
|
|
#endif
|
|
grcDebugDraw::PrintToScreenCoors(debugText,StartX,y);
|
|
y++;
|
|
|
|
int savedY = y;
|
|
sprintf(debugText,"Since Reset");
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
sprintf(debugText,"Min: %4dKb (%d%%%%)",(s32)(Global_RingBufferUsage_Min/1024.0f),(s32)((100*Global_RingBufferUsage_Min)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
sprintf(debugText,"Max: %4dKb (%d%%%%)",(s32)(Global_RingBufferUsage_Max/1024.0f),(s32)((100*Global_RingBufferUsage_Max)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
float avgUsage = ((float)Global_RingBufferUsage_Accum)/((float)Global_RingBufferUsage_Hit);
|
|
sprintf(debugText,"Avg: %4dKb (%d%%%%)",(s32)(avgUsage/1024.0f),(s32)((100*avgUsage)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
|
|
x += 16;
|
|
y = savedY;
|
|
sprintf(debugText,"Over %d frames",Recent_ResetHitCount);
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
sprintf(debugText,"Min: %4dKb (%d%%%%)",(s32)(Recent_RingBufferUsage_Min/1024.0f),(s32)((100*Recent_RingBufferUsage_Min)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
sprintf(debugText,"Max: %4dKb (%d%%%%)",(s32)(Recent_RingBufferUsage_Max/1024.0f),(s32)((100*Recent_RingBufferUsage_Max)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
|
|
avgUsage = ((float)Recent_RingBufferUsage_Accum)/((float)Recent_RingBufferUsage_Hit);
|
|
sprintf(debugText,"Avg: %4dKb (%d%%%%)",(s32)(avgUsage/1024.0f),(s32)((100*avgUsage)/ringSize));
|
|
grcDebugDraw::PrintToScreenCoors(debugText,x,y);
|
|
y++;
|
|
}
|
|
|
|
static void StartRingBufferMemUsage()
|
|
{
|
|
if( Render_RingBuffer_Stats)
|
|
{
|
|
DisplayRingStats();
|
|
}
|
|
|
|
CurrentFrame_RingStart = (u32)GRCDEVICE.GetCurrent()->m_pRing;
|
|
CurrentFrame_RingLimitStart = (u32)GRCDEVICE.GetCurrent()->m_pRingLimit;
|
|
}
|
|
static void EndRingBufferMemUsage()
|
|
{
|
|
bool resetUsage = false;
|
|
|
|
if( Recent_RingBufferUsage_Hit >= Recent_ResetHitCount )
|
|
{
|
|
resetUsage = true;
|
|
}
|
|
|
|
#if __XENON
|
|
const u32 ringEnd = (u32)GRCDEVICE.GetCurrent()->m_pRing;
|
|
const u32 ringLimitEnd = (u32)GRCDEVICE.GetCurrent()->m_pRingLimit;
|
|
if( CurrentFrame_RingStart < RingBufferStart )
|
|
{
|
|
RingBufferStart = CurrentFrame_RingStart;
|
|
resetUsage = true;
|
|
}
|
|
|
|
if( ringEnd < RingBufferStart )
|
|
{
|
|
RingBufferStart = ringEnd;
|
|
resetUsage = true;
|
|
}
|
|
|
|
if( CurrentFrame_RingLimitStart > RingBufferEnd )
|
|
{
|
|
RingBufferEnd = CurrentFrame_RingLimitStart;
|
|
resetUsage = true;
|
|
}
|
|
|
|
if( ringLimitEnd > RingBufferEnd )
|
|
{
|
|
RingBufferEnd = ringLimitEnd;
|
|
resetUsage = true;
|
|
}
|
|
#endif // __XENON
|
|
|
|
if( resetUsage )
|
|
{
|
|
Recent_RingBufferUsage_Min = 0xFFFFFFFF;
|
|
Recent_RingBufferUsage_Max = 0x0;
|
|
Recent_RingBufferUsage_Accum = 0x0;
|
|
Recent_RingBufferUsage_Hit = 0x0;
|
|
}
|
|
if( Global_Reset )
|
|
{
|
|
Global_RingBufferUsage_Min = 0xFFFFFFFF;
|
|
Global_RingBufferUsage_Max = 0x0;
|
|
Global_RingBufferUsage_Accum = 0x0;
|
|
Global_RingBufferUsage_Hit = 0x0;
|
|
|
|
Global_Reset = false;
|
|
}
|
|
|
|
#if __XENON
|
|
const u32 ringUsage = CalcRingUsage(CurrentFrame_RingStart,ringEnd);
|
|
#else // __XENON
|
|
const u32 ringUsage = CalcRingUsage();
|
|
#endif // __XENON
|
|
if( ringUsage != 0xFFFFFFFF )
|
|
{
|
|
if( ringUsage < Recent_RingBufferUsage_Min )
|
|
{
|
|
Recent_RingBufferUsage_Min = ringUsage;
|
|
}
|
|
|
|
if( ringUsage > Recent_RingBufferUsage_Max )
|
|
{
|
|
Recent_RingBufferUsage_Max = ringUsage;
|
|
}
|
|
|
|
if( ringUsage < Global_RingBufferUsage_Min )
|
|
{
|
|
Global_RingBufferUsage_Min = ringUsage;
|
|
}
|
|
|
|
if( ringUsage > Global_RingBufferUsage_Max )
|
|
{
|
|
Global_RingBufferUsage_Max = ringUsage;
|
|
}
|
|
|
|
Recent_RingBufferUsage_Accum += ringUsage;
|
|
Recent_RingBufferUsage_Hit++;
|
|
|
|
Global_RingBufferUsage_Accum += ringUsage;
|
|
Global_RingBufferUsage_Hit++;
|
|
}
|
|
}
|
|
|
|
#endif // (1 == __XENON) && (1 == __BANK)
|
|
|