Red code legacy MemoryManager, StreamEngine, ResourceManager, ImageHandler, AsyncPakManager, and more (#758)
Remove from CryCommon and CrySystem: - MemoryManager and all related classes/files - StreamEngine, ResourceManager, ImageHandler, and AsyncPakManager - Various other related interfaces/files/classes etc. that are all now unused
This commit is contained in:
@@ -1,516 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Manage async pak files
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "AsyncPakManager.h"
|
||||
#include "System.h"
|
||||
#include "IStreamEngine.h"
|
||||
#include <AzFramework/Archive/Archive.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include "ResourceManager.h"
|
||||
|
||||
#define MEGA_BYTE 1024* 1024
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string& CAsyncPakManager::SAsyncPak::GetStatus(string& status) const
|
||||
{
|
||||
switch (eState)
|
||||
{
|
||||
case STATE_UNLOADED:
|
||||
status = "Unloaded";
|
||||
break;
|
||||
case STATE_REQUESTED:
|
||||
status = "Requested";
|
||||
break;
|
||||
case STATE_REQUESTUNLOAD:
|
||||
status = "RequestUnload";
|
||||
break;
|
||||
case STATE_LOADED:
|
||||
status = "Loaded";
|
||||
break;
|
||||
default:
|
||||
status = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CAsyncPakManager::CAsyncPakManager()
|
||||
{
|
||||
m_nTotalOpenLayerPakSize = 0;
|
||||
m_bRequestLayerUpdate = false;
|
||||
}
|
||||
|
||||
CAsyncPakManager::~CAsyncPakManager()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::Clear()
|
||||
{
|
||||
//float startTime = gEnv->pTimer->GetAsyncCurTime();
|
||||
|
||||
for (TPakMap::iterator it = m_paks.begin();
|
||||
it != m_paks.end(); ++it)
|
||||
{
|
||||
SAsyncPak& layerPak = it->second;
|
||||
if (layerPak.bStreaming)
|
||||
{
|
||||
// wait until finished
|
||||
layerPak.pReadStream->Abort();
|
||||
}
|
||||
|
||||
ReleaseData(&layerPak);
|
||||
}
|
||||
m_paks.clear();
|
||||
m_bRequestLayerUpdate = false;
|
||||
|
||||
assert(m_nTotalOpenLayerPakSize == 0);
|
||||
m_nTotalOpenLayerPakSize = 0;
|
||||
|
||||
//printf("CAsyncPakManager::Clear() %0.4f secs\n", gEnv->pTimer->GetAsyncCurTime() - startTime);
|
||||
}
|
||||
|
||||
void CAsyncPakManager::UnloadLevelLoadPaks()
|
||||
{
|
||||
for (TPakMap::iterator it = m_paks.begin();
|
||||
it != m_paks.end(); ++it)
|
||||
{
|
||||
SAsyncPak& layerPak = it->second;
|
||||
|
||||
if (layerPak.eLifeTime == SAsyncPak::LIFETIME_LOAD_ONLY)
|
||||
{
|
||||
if (layerPak.bStreaming)
|
||||
{
|
||||
// wait until finished
|
||||
layerPak.pReadStream->Abort();
|
||||
}
|
||||
|
||||
ReleaseData(&layerPak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::ParseLayerPaks(const string& levelCachePath)
|
||||
{
|
||||
string layerPath = levelCachePath + "/"; // "/layers/";
|
||||
string search = layerPath + "*";
|
||||
auto pPak = gEnv->pCryPak;
|
||||
|
||||
|
||||
// allow this find first to actually touch the file system
|
||||
AZ::IO::ArchiveFileIterator fileIterator= pPak->FindFirst(search.c_str(), 0, true);
|
||||
|
||||
if (fileIterator)
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((fileIterator.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory || fileIterator.m_filename == "." || fileIterator.m_filename == "..")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string pakName(fileIterator.m_filename.data(), fileIterator.m_filename.size());
|
||||
size_t findPos = pakName.find_last_of('.');
|
||||
if (findPos == string::npos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string extension = pakName.substr(findPos + 1, pakName.size());
|
||||
if (extension != "pak")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SAsyncPak layerPak;
|
||||
layerPak.layername = pakName.substr(0, findPos);
|
||||
layerPak.filename = layerPath + pakName;
|
||||
layerPak.nSize = pPak->FGetSize(layerPak.filename.c_str(), true); // allow to go to disc for this access
|
||||
layerPak.bClosePakOnRelease = true;
|
||||
|
||||
m_paks[layerPak.layername] = layerPak;
|
||||
} while (fileIterator = pPak->FindNext(fileIterator));
|
||||
|
||||
pPak->FindClose(fileIterator);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::StartStreaming(SAsyncPak* pLayerPak)
|
||||
{
|
||||
StreamReadParams params;
|
||||
params.dwUserData = (DWORD_PTR) pLayerPak;
|
||||
params.nSize = 0;
|
||||
params.pBuffer = NULL;
|
||||
params.nFlags = IStreamEngine::FLAGS_FILE_ON_DISK;
|
||||
params.ePriority = estpIdle;
|
||||
|
||||
pLayerPak->pReadStream = gEnv->pSystem->GetStreamEngine()->StartRead(eStreamTaskTypePak, pLayerPak->filename.c_str(), this, ¶ms);
|
||||
|
||||
if (pLayerPak->pReadStream)
|
||||
{
|
||||
pLayerPak->bStreaming = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pLayerPak->eState = SAsyncPak::STATE_UNLOADED;
|
||||
pLayerPak->pData.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CAsyncPakManager::ReleaseData(SAsyncPak* pLayerPak)
|
||||
{
|
||||
if (pLayerPak->eState == SAsyncPak::STATE_LOADED)
|
||||
{
|
||||
if (pLayerPak->bClosePakOnRelease)
|
||||
{
|
||||
gEnv->pCryPak->ClosePack(pLayerPak->filename.c_str(), 0);
|
||||
//printf("Unload pak from mem: %s\n", pLayerPak->filename.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_Unload);
|
||||
//printf("Close pak: %s\n", pLayerPak->filename.c_str());
|
||||
}
|
||||
|
||||
m_nTotalOpenLayerPakSize -= pLayerPak->nSize;
|
||||
}
|
||||
|
||||
if (pLayerPak->pData)
|
||||
{
|
||||
assert(pLayerPak->pData->use_count() == 1);
|
||||
}
|
||||
|
||||
assert((!pLayerPak->pData) || (pLayerPak->pData && pLayerPak->pData->use_count() == 1));
|
||||
pLayerPak->pData.reset();
|
||||
pLayerPak->eState = SAsyncPak::STATE_UNLOADED;
|
||||
|
||||
m_bRequestLayerUpdate = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CAsyncPakManager::LoadLayerPak(const char* sLayerName)
|
||||
{
|
||||
// only load layer paks from valid files
|
||||
TPakMap::iterator findResult = m_paks.find(sLayerName);
|
||||
if (findResult != m_paks.end())
|
||||
{
|
||||
return LoadPak(findResult->second);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CAsyncPakManager::LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly)
|
||||
{
|
||||
//check if pak reference exists
|
||||
TPakMap::iterator findResult = m_paks.find(pPath);
|
||||
if (findResult != m_paks.end())
|
||||
{
|
||||
return LoadPak(findResult->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
char szFullPathBuf[AZ::IO::IArchive::MaxPath];
|
||||
const char* szFullPath = gEnv->pCryPak->AdjustFileName(pPath, szFullPathBuf, AZ_ARRAY_SIZE(szFullPathBuf), AZ::IO::IArchive::FOPEN_HINT_QUIET | AZ::IO::IArchive::FLAGS_PATH_REAL);
|
||||
|
||||
// Check if the pak file actually exists before trying to load
|
||||
if (!gEnv->pCryPak->IsFileExist(szFullPath, AZ::IO::IArchive::eFileLocation_Any))
|
||||
{
|
||||
// Cached file does not exist
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Level cache pak file %s does not exist", szFullPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
SAsyncPak layerPak;
|
||||
layerPak.layername = pPath;
|
||||
layerPak.filename = szFullPathBuf;
|
||||
layerPak.nSize = 0;
|
||||
layerPak.eLifeTime = bLevelLoadOnly ? SAsyncPak::LIFETIME_LOAD_ONLY : SAsyncPak::LIFETIME_LEVEL_COMPLETE;
|
||||
|
||||
m_paks[layerPak.layername] = layerPak;
|
||||
|
||||
return LoadPak(m_paks[layerPak.layername]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAsyncPakManager::LoadPak(SAsyncPak& layerPak)
|
||||
{
|
||||
layerPak.nRequestCount++;
|
||||
if (layerPak.eState == SAsyncPak::STATE_LOADED || layerPak.bStreaming ||
|
||||
layerPak.eState == SAsyncPak::STATE_REQUESTED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
layerPak.eState = SAsyncPak::STATE_REQUESTED;
|
||||
|
||||
//printf("Streaming level pak: %s\n", layerPak.layername.c_str());
|
||||
|
||||
StartStreaming(&layerPak);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::UnloadLayerPak(const char* sLayerName)
|
||||
{
|
||||
TPakMap::iterator findResult = m_paks.find(sLayerName);
|
||||
if (findResult == m_paks.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SAsyncPak& layerPak = findResult->second;
|
||||
layerPak.nRequestCount--;
|
||||
assert(layerPak.nRequestCount >= 0);
|
||||
if (layerPak.nRequestCount > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (layerPak.bStreaming)
|
||||
{
|
||||
if (layerPak.pReadStream)
|
||||
{
|
||||
layerPak.pReadStream->Abort();
|
||||
}
|
||||
layerPak.eState = SAsyncPak::STATE_REQUESTUNLOAD;
|
||||
return;
|
||||
}
|
||||
|
||||
if (layerPak.eState == SAsyncPak::STATE_LOADED)
|
||||
{
|
||||
ReleaseData(&layerPak);
|
||||
m_bRequestLayerUpdate = true;
|
||||
}
|
||||
|
||||
if (layerPak.eState == SAsyncPak::STATE_REQUESTED)
|
||||
{
|
||||
layerPak.eState = SAsyncPak::STATE_UNLOADED;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::GetLayerPakStats(
|
||||
SLayerPakStats& stats, bool bCollectAllStats) const
|
||||
{
|
||||
stats.m_MaxSize = (g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE);
|
||||
stats.m_UsedSize = m_nTotalOpenLayerPakSize;
|
||||
|
||||
for (TPakMap::const_iterator it = m_paks.begin(); it != m_paks.end(); ++it)
|
||||
{
|
||||
const SAsyncPak& layerPak = it->second;
|
||||
if (bCollectAllStats || layerPak.eState != SAsyncPak::STATE_UNLOADED)
|
||||
{
|
||||
SLayerPakStats::SEntry entry;
|
||||
entry.name = it->first;
|
||||
entry.nSize = layerPak.nSize;
|
||||
entry.bStreaming = layerPak.bStreaming;
|
||||
layerPak.GetStatus(entry.status);
|
||||
|
||||
stats.m_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::StreamAsyncOnComplete(
|
||||
IReadStream* pStream, unsigned nError)
|
||||
{
|
||||
if (nError != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SAsyncPak* pLayerPak = (SAsyncPak*) pStream->GetUserData();
|
||||
|
||||
//Check is pak is already open, if so, just assign mem
|
||||
if (gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_GPU, pLayerPak->pData))
|
||||
{
|
||||
pLayerPak->bPakAlreadyOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool usePrefabSystemForLevels = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
usePrefabSystemForLevels,
|
||||
&AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
|
||||
|
||||
if (usePrefabSystemForLevels)
|
||||
{
|
||||
gEnv->pCryPak->OpenPack(
|
||||
"@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// ugly hack - depending on the pak file pak may need special root info / open flags
|
||||
//
|
||||
if (pLayerPak->layername.find("level.pak") != string::npos)
|
||||
{
|
||||
gEnv->pCryPak->OpenPack(
|
||||
{pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32, NULL);
|
||||
}
|
||||
else if (pLayerPak->layername.find("levelshadercache.pak") != string::npos)
|
||||
{
|
||||
gEnv->pCryPak->OpenPack(
|
||||
"@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_PATH_REAL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gEnv->pCryPak->OpenPack(
|
||||
"@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_GPU, pLayerPak->pData);
|
||||
}
|
||||
|
||||
pLayerPak->eState = SAsyncPak::STATE_LOADED;
|
||||
|
||||
//printf("Finished streaming level pak: %s\n", pLayerPak->layername.c_str());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::StreamOnComplete(
|
||||
IReadStream* pStream, unsigned nError)
|
||||
{
|
||||
SAsyncPak* pLayerPak = (SAsyncPak*) pStream->GetUserData();
|
||||
|
||||
if (nError != 0)
|
||||
{
|
||||
ReleaseData(pLayerPak);
|
||||
}
|
||||
|
||||
pLayerPak->bStreaming = false;
|
||||
pLayerPak->pReadStream = NULL;
|
||||
|
||||
m_bRequestLayerUpdate = true;
|
||||
}
|
||||
|
||||
void* CAsyncPakManager::StreamOnNeedStorage(IReadStream* pStream, unsigned nSize, bool& bAbortOnFailToAlloc)
|
||||
{
|
||||
SAsyncPak* pAsyncPak = (SAsyncPak*)pStream->GetUserData();
|
||||
|
||||
pAsyncPak->nSize = nSize;
|
||||
|
||||
if ((m_nTotalOpenLayerPakSize + nSize) > (size_t)(g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE))
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Not enough space to load in memory layer pak %s (Current: %" PRISIZE_T " Required: %d)",
|
||||
pAsyncPak->filename.c_str(), m_nTotalOpenLayerPakSize, nSize);
|
||||
|
||||
//printf("Not enough space to load in memory layer pak %s (Current: %d Required: %d)\n", pAsyncPak->filename.c_str(), m_nTotalOpenLayerPakSize, nSize);
|
||||
|
||||
pAsyncPak->eState = SAsyncPak::STATE_UNLOADED;
|
||||
pAsyncPak->bStreaming = false;
|
||||
pAsyncPak->pReadStream = NULL;
|
||||
|
||||
bAbortOnFailToAlloc = true;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nSize)
|
||||
{
|
||||
auto pCryPak = static_cast<AZ::IO::Archive*>(gEnv->pCryPak);
|
||||
|
||||
// allocate the data
|
||||
const char* szUsage = "In Memory Zip File";
|
||||
pAsyncPak->pData = pCryPak->PoolAllocMemoryBlock(nSize, szUsage, alignof(uint8_t));
|
||||
|
||||
m_nTotalOpenLayerPakSize += nSize;
|
||||
|
||||
return pAsyncPak->pData->m_address.get();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CAsyncPakManager::Update()
|
||||
{
|
||||
if (!m_bRequestLayerUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_bRequestLayerUpdate = false;
|
||||
|
||||
for (TPakMap::iterator it = m_paks.begin();
|
||||
it != m_paks.end(); ++it)
|
||||
{
|
||||
SAsyncPak& layerPak = it->second;
|
||||
if (!layerPak.bStreaming)
|
||||
{
|
||||
if (layerPak.eState == SAsyncPak::STATE_REQUESTUNLOAD)
|
||||
{
|
||||
// done streaming and not interested in it anymore, then release it again
|
||||
ReleaseData(&layerPak);
|
||||
}
|
||||
else if (layerPak.eState == SAsyncPak::STATE_REQUESTED &&
|
||||
(m_nTotalOpenLayerPakSize + layerPak.nSize <= ((size_t)g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE)))
|
||||
{
|
||||
// do we have enough memory now to start streaming the pak
|
||||
StartStreaming(&layerPak);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Abort streaming jobs and prevent any more requests
|
||||
// Paks which are loaded remain, they will be cleaned up as usual
|
||||
void CAsyncPakManager::CancelPendingJobs()
|
||||
{
|
||||
for (TPakMap::iterator it = m_paks.begin(); it != m_paks.end(); ++it)
|
||||
{
|
||||
SAsyncPak& layerPak = it->second;
|
||||
|
||||
if (layerPak.bStreaming)
|
||||
{
|
||||
layerPak.pReadStream->Abort();
|
||||
ReleaseData(&layerPak);
|
||||
|
||||
//printf("Pak %s Aborted\n", layerPak.filename.c_str());
|
||||
}
|
||||
else if (layerPak.eState == SAsyncPak::STATE_REQUESTED)
|
||||
{
|
||||
layerPak.eState = SAsyncPak::STATE_UNLOADED;
|
||||
ReleaseData(&layerPak);
|
||||
|
||||
//printf("Pak %s Cancelled\n", layerPak.filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Manage async pak files
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
|
||||
#include <IResourceManager.h>
|
||||
#include <IStreamEngine.h>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
struct MemoryBlock;
|
||||
}
|
||||
|
||||
class CAsyncPakManager
|
||||
: public IStreamCallback
|
||||
{
|
||||
protected:
|
||||
|
||||
struct SAsyncPak
|
||||
{
|
||||
enum EState
|
||||
{
|
||||
STATE_UNLOADED,
|
||||
STATE_REQUESTED,
|
||||
STATE_REQUESTUNLOAD,
|
||||
STATE_LOADED,
|
||||
};
|
||||
|
||||
enum ELifeTime
|
||||
{
|
||||
LIFETIME_LOAD_ONLY,
|
||||
LIFETIME_LEVEL_COMPLETE,
|
||||
LIFETIME_PERMANENT
|
||||
};
|
||||
|
||||
SAsyncPak()
|
||||
: nRequestCount(0)
|
||||
, eState(STATE_UNLOADED)
|
||||
, eLifeTime(LIFETIME_LOAD_ONLY)
|
||||
, nSize(0)
|
||||
, pData(0)
|
||||
, bStreaming(false)
|
||||
, bPakAlreadyOpen(false)
|
||||
, bClosePakOnRelease(false)
|
||||
, pReadStream(0) {}
|
||||
|
||||
string& GetStatus(string&) const;
|
||||
|
||||
string layername;
|
||||
string filename;
|
||||
size_t nSize;
|
||||
AZStd::intrusive_ptr<AZ::IO::MemoryBlock> pData;
|
||||
EState eState;
|
||||
ELifeTime eLifeTime;
|
||||
bool bStreaming;
|
||||
bool bPakAlreadyOpen;
|
||||
bool bClosePakOnRelease;
|
||||
int nRequestCount;
|
||||
IReadStreamPtr pReadStream;
|
||||
};
|
||||
typedef std::map<string, SAsyncPak> TPakMap;
|
||||
|
||||
public:
|
||||
|
||||
CAsyncPakManager();
|
||||
~CAsyncPakManager();
|
||||
|
||||
void ParseLayerPaks(const string& levelCachePath);
|
||||
|
||||
bool LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly);
|
||||
void UnloadLevelLoadPaks();
|
||||
bool LoadLayerPak(const char* sLayerName);
|
||||
void UnloadLayerPak(const char* sLayerName);
|
||||
void CancelPendingJobs();
|
||||
|
||||
void GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const;
|
||||
|
||||
void Clear();
|
||||
void Update();
|
||||
|
||||
protected:
|
||||
|
||||
bool LoadPak(SAsyncPak& layerPak);
|
||||
|
||||
void StartStreaming(SAsyncPak* pLayerPak);
|
||||
void ReleaseData(SAsyncPak* pLayerPak);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IStreamCallback interface implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void StreamAsyncOnComplete (IReadStream* pStream, unsigned nError);
|
||||
virtual void StreamOnComplete (IReadStream* pStream, unsigned nError);
|
||||
virtual void* StreamOnNeedStorage(IReadStream* pStream, unsigned nSize, bool& bAbortOnFailToAlloc);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TPakMap m_paks;
|
||||
size_t m_nTotalOpenLayerPakSize;
|
||||
bool m_bRequestLayerUpdate;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H
|
||||
@@ -1,114 +0,0 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_CRITICAL_ERROR, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 260
|
||||
BOTTOMMARGIN, 223
|
||||
END
|
||||
|
||||
IDD_EXCEPTION, DIALOG
|
||||
BEGIN
|
||||
END
|
||||
|
||||
IDD_CONFIRM_SAVE_LEVEL, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 239
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 96
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_CRITICAL_ERROR DIALOGEX 0, 0, 267, 230
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
|
||||
CAPTION "Critical Exception"
|
||||
FONT 8, "MS Sans Serif", 0, 0, 0x0
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "&Abort",IDB_EXIT,100,207,58,14
|
||||
EDITTEXT IDC_CALLSTACK,10,95,245,102,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | WS_HSCROLL
|
||||
EDITTEXT IDC_EXCEPTION_CODE,10,25,50,12,ES_AUTOHSCROLL | ES_READONLY
|
||||
LTEXT "Call Stack Trace",IDC_STATIC,13,85,54,8
|
||||
LTEXT "Code",IDC_STATIC,10,15,18,8
|
||||
LTEXT "Address:",IDC_STATIC,66,15,28,8
|
||||
EDITTEXT IDC_EXCEPTION_ADDRESS,65,25,75,12,ES_AUTOHSCROLL | ES_READONLY
|
||||
LTEXT "Description",IDC_STATIC,10,40,36,8
|
||||
GROUPBOX "Exception Info",IDC_STATIC,5,5,255,200
|
||||
EDITTEXT IDC_EXCEPTION_MODULE,145,25,110,12,ES_AUTOHSCROLL | ES_READONLY
|
||||
LTEXT "Module",IDC_STATIC,145,15,24,8
|
||||
EDITTEXT IDC_EXCEPTION_DESC,10,50,245,30,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY
|
||||
PUSHBUTTON "&Ignore",IDB_IGNORE,160,207,59,14,WS_DISABLED
|
||||
END
|
||||
|
||||
IDD_EXCEPTION DIALOG 0, 0, 138, 52
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Exception"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Exception Intercepted\r\nRetrieving Info...",IDC_STATIC,33,18,71,19
|
||||
END
|
||||
|
||||
IDD_CONFIRM_SAVE_LEVEL DIALOGEX 0, 0, 280, 123
|
||||
STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
|
||||
EXSTYLE WS_EX_TOPMOST
|
||||
CAPTION "Engine, Game or Editor Crash"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
PUSHBUTTON "Save",IDB_CONFIRM_SAVE,4,96,68,20
|
||||
PUSHBUTTON "Cancel",IDB_DONT_SAVE,206,96,68,20
|
||||
LTEXT "Open 3D Engine has encountered an error and needs to close.\n\nA backup has been saved to the '_savebackup' subfolder.\n\nIf you are unable to save your file, you can recover by copying the contents of the _savebackup folder over the broken files.",IDC_STATIC,60,8,210,61
|
||||
LTEXT "Attempt save?",IDC_STATIC,60,72,180,21
|
||||
CONTROL 128,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,8,8,48,40
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDB_CRASH_FACE BITMAP "crash_face.bmp"
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "CustomMemoryHeap.h"
|
||||
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#undef AZ_RESTRICTED_SECTION
|
||||
#define CUSTOMMEMORYHEAP_CPP_SECTION_1 1
|
||||
#define CUSTOMMEMORYHEAP_CPP_SECTION_2 2
|
||||
#define CUSTOMMEMORYHEAP_CPP_SECTION_3 3
|
||||
#endif
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp)
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCustomMemoryHeapBlock::CCustomMemoryHeapBlock(CCustomMemoryHeap* pHeap)
|
||||
: m_pHeap(pHeap)
|
||||
, m_pData(0)
|
||||
, m_nSize(0)
|
||||
, m_nGPUHandle(0)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCustomMemoryHeapBlock::~CCustomMemoryHeapBlock()
|
||||
{
|
||||
m_pHeap->DeallocateBlock(this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CCustomMemoryHeapBlock::GetData()
|
||||
{
|
||||
return m_pData;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCustomMemoryHeapBlock::CopyMemoryRegion(void* pOutputBuffer, size_t nOffset, size_t nSize)
|
||||
{
|
||||
assert(nOffset + nSize <= m_nSize);
|
||||
if (nOffset + nSize <= m_nSize)
|
||||
{
|
||||
memcpy(pOutputBuffer, (uint8*)m_pData + nOffset, nSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
CryFatalError("Bad CopyMemoryRegion range");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ICustomMemoryBlock* CCustomMemoryHeap::AllocateBlock(size_t const nAllocateSize, char const* const sUsage, size_t const nAlignment /* = 16 */)
|
||||
{
|
||||
CCustomMemoryHeapBlock* pBlock = new CCustomMemoryHeapBlock(this);
|
||||
pBlock->m_sUsage = sUsage;
|
||||
pBlock->m_nSize = nAllocateSize;
|
||||
|
||||
switch (m_eAllocPolicy)
|
||||
{
|
||||
case IMemoryManager::eapDefaultAllocator:
|
||||
{
|
||||
size_t allocated = 0;
|
||||
pBlock->m_pData = CryMalloc(nAllocateSize, allocated, nAlignment);
|
||||
break;
|
||||
}
|
||||
case IMemoryManager::eapPageMapped:
|
||||
pBlock->m_pData = CryMemory::AllocPages(nAllocateSize);
|
||||
break;
|
||||
case IMemoryManager::eapCustomAlignment:
|
||||
#if defined(DEBUG)
|
||||
if (nAlignment == 0)
|
||||
{
|
||||
CryFatalError("CCustomMemoryHeap: trying to allocate memory via eapCustomAlignment with an alignment of zero!");
|
||||
}
|
||||
#endif
|
||||
pBlock->m_pData = CryModuleMemalign(nAllocateSize, nAlignment);
|
||||
break;
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_2
|
||||
#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp)
|
||||
#endif
|
||||
default:
|
||||
CryFatalError("CCustomMemoryHeap: unknown allocation policy during AllocateBlock!");
|
||||
break;
|
||||
}
|
||||
|
||||
CryInterlockedAdd(&m_nAllocatedSize, nAllocateSize);
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
void CCustomMemoryHeap::DeallocateBlock(CCustomMemoryHeapBlock* pBlock)
|
||||
{
|
||||
switch (m_eAllocPolicy)
|
||||
{
|
||||
case IMemoryManager::eapDefaultAllocator:
|
||||
CryFree(pBlock->m_pData, 0);
|
||||
break;
|
||||
case IMemoryManager::eapPageMapped:
|
||||
CryMemory::FreePages(pBlock->m_pData, pBlock->GetSize());
|
||||
break;
|
||||
case IMemoryManager::eapCustomAlignment:
|
||||
CryModuleMemalignFree(pBlock->m_pData);
|
||||
break;
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_3
|
||||
#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp)
|
||||
#endif
|
||||
default:
|
||||
CryFatalError("CCustomMemoryHeap: unknown allocation policy during DeallocateBlock!");
|
||||
break;
|
||||
}
|
||||
|
||||
int nAllocateSize = (int)pBlock->m_nSize;
|
||||
CryInterlockedAdd(&m_nAllocatedSize, -nAllocateSize);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCustomMemoryHeap::GetMemoryUsage(ICrySizer* pSizer)
|
||||
{
|
||||
pSizer->AddObject(this, m_nAllocatedSize);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
size_t CCustomMemoryHeap::GetAllocated()
|
||||
{
|
||||
return m_nAllocatedSize;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCustomMemoryHeap::CCustomMemoryHeap(IMemoryManager::EAllocPolicy const eAllocPolicy)
|
||||
{
|
||||
m_nAllocatedSize = 0;
|
||||
m_eAllocPolicy = eAllocPolicy;
|
||||
m_nTraceHeapHandle = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCustomMemoryHeap::~CCustomMemoryHeap()
|
||||
{
|
||||
}
|
||||
@@ -62,46 +62,6 @@ AZ_POP_DISABLE_WARNING
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct CSystemEventListner_System
|
||||
: public ISystemEventListener
|
||||
{
|
||||
public:
|
||||
virtual void OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESYSTEM_EVENT_LEVEL_LOAD_START:
|
||||
case ESYSTEM_EVENT_LEVEL_LOAD_END:
|
||||
{
|
||||
CryCleanup();
|
||||
break;
|
||||
}
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_POST_UNLOAD:
|
||||
{
|
||||
CryCleanup();
|
||||
STLALLOCATOR_CLEANUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static CSystemEventListner_System g_system_event_listener_system;
|
||||
|
||||
static AZ::EnvironmentVariable<IMemoryManager*> s_cryMemoryManager;
|
||||
|
||||
|
||||
// Force the CryMemoryManager into the AZ::Environment for exposure to other DLLs
|
||||
void ExportCryMemoryManager()
|
||||
{
|
||||
IMemoryManager* cryMemoryManager = nullptr;
|
||||
CryGetIMemoryManagerInterface((void**)&cryMemoryManager);
|
||||
AZ_Assert(cryMemoryManager, "Unable to resolve CryMemoryManager");
|
||||
s_cryMemoryManager = AZ::Environment::CreateVariable<IMemoryManager*>("CryIMemoryManagerInterface", cryMemoryManager);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupParams)
|
||||
@@ -113,8 +73,6 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar
|
||||
// Environment should have been attached via InjectEnvironment
|
||||
AZ_Assert(AZ::Environment::IsReady(), "Environment is not attached, must be attached before CreateSystemInterface can be called");
|
||||
|
||||
ExportCryMemoryManager();
|
||||
|
||||
pSystem = new CSystem(startupParams.pSharedEnvironment);
|
||||
ModuleInitISystem(pSystem, "CrySystem");
|
||||
|
||||
@@ -146,8 +104,6 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar
|
||||
return 0;
|
||||
}
|
||||
|
||||
pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_system);
|
||||
|
||||
return pSystem;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
|
||||
#include "GeneralMemoryHeap.h"
|
||||
|
||||
#include <AzCore/Memory/AllocatorBase.h>
|
||||
#include <AzCore/Memory/HphaSchema.h>
|
||||
|
||||
class GeneralMemoryHeapAllocator
|
||||
: public AZ::SimpleSchemaAllocator<AZ::HphaSchema>
|
||||
{
|
||||
using Base = AZ::SimpleSchemaAllocator<AZ::HphaSchema>;
|
||||
public:
|
||||
static const size_t DEFAULT_ALIGNMENT = sizeof(void*);
|
||||
|
||||
GeneralMemoryHeapAllocator(const char* desc)
|
||||
: Base("GeneralMemoryHeapAllocator", desc)
|
||||
{
|
||||
}
|
||||
|
||||
void Reserve(size_t size)
|
||||
{
|
||||
// Allocate a block, then free it, forcing it into the page tree/cache
|
||||
void* block = m_schema->Allocate(size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, "GeneralMemoryHeapAllocator Reserve", __FILE__, __LINE__);
|
||||
m_schema->DeAllocate(block);
|
||||
}
|
||||
};
|
||||
|
||||
CGeneralMemoryHeap::CGeneralMemoryHeap([[maybe_unused]] UINT_PTR base, [[maybe_unused]] size_t upperLimit, size_t reserveSize, const char* sUsage)
|
||||
: m_refCount(0)
|
||||
, m_block(nullptr)
|
||||
, m_blockSize(0)
|
||||
{
|
||||
AZ::HphaSchema::Descriptor desc;
|
||||
desc.m_subAllocator = &AZ::AllocatorInstance<AZ::LegacyAllocator>::Get();
|
||||
m_allocator.reset(new AZ::AllocatorWrapper<GeneralMemoryHeapAllocator>);
|
||||
m_allocator->Create(desc, sUsage);
|
||||
if (reserveSize)
|
||||
{
|
||||
(*m_allocator)->Reserve(reserveSize);
|
||||
}
|
||||
}
|
||||
|
||||
CGeneralMemoryHeap::CGeneralMemoryHeap(void* base, size_t size, const char* sUsage)
|
||||
: m_refCount(0)
|
||||
, m_block(base)
|
||||
, m_blockSize(size)
|
||||
{
|
||||
AZ::HphaSchema::Descriptor desc;
|
||||
desc.m_fixedMemoryBlock = base;
|
||||
desc.m_fixedMemoryBlockByteSize = size;
|
||||
desc.m_fixedMemoryBlockAlignment = GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT;
|
||||
m_allocator.reset(new AZ::AllocatorWrapper<GeneralMemoryHeapAllocator>);
|
||||
m_allocator->Create(desc, sUsage);
|
||||
}
|
||||
|
||||
CGeneralMemoryHeap::~CGeneralMemoryHeap()
|
||||
{
|
||||
}
|
||||
|
||||
bool CGeneralMemoryHeap::Cleanup()
|
||||
{
|
||||
(*m_allocator)->GarbageCollect();
|
||||
return true;
|
||||
}
|
||||
|
||||
int CGeneralMemoryHeap::AddRef()
|
||||
{
|
||||
return m_refCount.fetch_add(1);
|
||||
}
|
||||
|
||||
int CGeneralMemoryHeap::Release()
|
||||
{
|
||||
int nRef = m_refCount.fetch_sub(1);
|
||||
|
||||
if (nRef <= 1)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
return nRef;
|
||||
}
|
||||
|
||||
void CGeneralMemoryHeap::RecordAlloc(void* ptr, size_t size)
|
||||
{
|
||||
if (m_block == nullptr)
|
||||
{
|
||||
m_allocs.emplace(ptr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void CGeneralMemoryHeap::RecordFree(void* ptr, size_t size)
|
||||
{
|
||||
if (m_block == nullptr)
|
||||
{
|
||||
m_allocs.erase(Alloc(ptr, size));
|
||||
}
|
||||
}
|
||||
|
||||
bool CGeneralMemoryHeap::IsInAddressRange(void* ptr) const
|
||||
{
|
||||
if (m_block)
|
||||
{
|
||||
return (static_cast<char*>(ptr) - static_cast<char*>(m_block)) <= m_blockSize;
|
||||
}
|
||||
auto it = m_allocs.find(Alloc(ptr));
|
||||
return it != m_allocs.end();
|
||||
}
|
||||
|
||||
void* CGeneralMemoryHeap::Calloc(size_t numElements, size_t size, const char* sUsage)
|
||||
{
|
||||
void* ptr = (*m_allocator)->Allocate(numElements * size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, sUsage, __FILE__, __LINE__);
|
||||
memset(ptr, 0, numElements * size);
|
||||
RecordAlloc(ptr, numElements * size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* CGeneralMemoryHeap::Malloc(size_t size, const char* sUsage)
|
||||
{
|
||||
void* ptr = (*m_allocator)->Allocate(size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, sUsage, __FILE__, __LINE__);
|
||||
RecordAlloc(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t CGeneralMemoryHeap::Free(void* ptr)
|
||||
{
|
||||
// The client code using these heaps tend to use a guesswork algorithm to freeing
|
||||
// which involves handing the pointer to every known heap until it frees, so
|
||||
// it's necessary to validate that the ptr belongs to this heap before attempting to free
|
||||
if (IsInAddressRange(ptr))
|
||||
{
|
||||
size_t size = (*m_allocator)->AllocationSize(ptr);
|
||||
RecordFree(ptr, size);
|
||||
(*m_allocator)->DeAllocate(ptr);
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* CGeneralMemoryHeap::Realloc(void* ptr, size_t size, const char* /*sUsage*/)
|
||||
{
|
||||
RecordFree(ptr, (*m_allocator)->AllocationSize(ptr));
|
||||
void* newPtr = (*m_allocator)->ReAllocate(ptr, size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT);
|
||||
RecordAlloc(newPtr, size);
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
void* CGeneralMemoryHeap::ReallocAlign(void* ptr, size_t size, size_t alignment, const char* /*sUsage*/)
|
||||
{
|
||||
RecordFree(ptr, (*m_allocator)->AllocationSize(ptr));
|
||||
void* newPtr = (*m_allocator)->ReAllocate(ptr, size, alignment);
|
||||
RecordAlloc(newPtr, size);
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
void* CGeneralMemoryHeap::Memalign(size_t boundary, size_t size, const char* sUsage)
|
||||
{
|
||||
void* ptr = (*m_allocator)->Allocate(size, boundary, 0, sUsage, __FILE__, __LINE__);
|
||||
RecordAlloc(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t CGeneralMemoryHeap::UsableSize(void* ptr) const
|
||||
{
|
||||
// The client code using these heaps tend to use a guesswork algorithm to determine
|
||||
// which heap owns the pointer. Calls to UsableSize() are a part of this guesswork.
|
||||
// The overrun detector doesn't play nicely on AllocationSize() lookups for pointers that
|
||||
// don't belong to the heap, so validate that we're in the correct address range before trying
|
||||
// to look up the size.
|
||||
return IsInAddressRange(ptr) ? (*m_allocator)->AllocationSize(ptr) : 0;
|
||||
}
|
||||
|
||||
AZ::IAllocator* CGeneralMemoryHeap::GetAllocator() const
|
||||
{
|
||||
return m_allocator->Get();
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "IMemory.h"
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
|
||||
class GeneralMemoryHeapAllocator;
|
||||
|
||||
class CGeneralMemoryHeap
|
||||
: public IGeneralMemoryHeap
|
||||
{
|
||||
struct Alloc
|
||||
{
|
||||
void* m_base;
|
||||
size_t m_size;
|
||||
|
||||
Alloc(void* base = nullptr, size_t size = 0)
|
||||
: m_base(base)
|
||||
, m_size(size)
|
||||
{}
|
||||
|
||||
bool operator==(const Alloc& rhs) const
|
||||
{
|
||||
// size doesn't matter
|
||||
return m_base == rhs.m_base;
|
||||
}
|
||||
|
||||
bool operator<(const Alloc& rhs) const
|
||||
{
|
||||
// this will cause allocs to be sorted by address
|
||||
return m_base < rhs.m_base;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
// Create a heap that will map/unmap pages in the range [baseAddress, baseAddress + upperLimit).
|
||||
CGeneralMemoryHeap(UINT_PTR baseAddress, size_t upperLimit, size_t reserveSize, const char* sUsage);
|
||||
|
||||
// Create a heap that will assumes all memory in the range [base, base + size) is already mapped.
|
||||
CGeneralMemoryHeap(void* base, size_t size, const char* sUsage);
|
||||
|
||||
~CGeneralMemoryHeap();
|
||||
|
||||
public: // IGeneralMemoryHeap Members
|
||||
bool Cleanup();
|
||||
|
||||
int AddRef();
|
||||
int Release();
|
||||
|
||||
bool IsInAddressRange(void* ptr) const;
|
||||
|
||||
void* Calloc(size_t nmemb, size_t size, const char* sUsage = NULL);
|
||||
void* Malloc(size_t sz, const char* sUsage = NULL);
|
||||
size_t Free(void* ptr);
|
||||
void* Realloc(void* ptr, size_t sz, const char* sUsage = NULL);
|
||||
void* ReallocAlign(void* ptr, size_t size, size_t alignment, const char* sUsage = NULL);
|
||||
void* Memalign(size_t boundary, size_t size, const char* sUsage = NULL);
|
||||
size_t UsableSize(void* ptr) const;
|
||||
|
||||
AZ::IAllocator* GetAllocator() const override;
|
||||
|
||||
private:
|
||||
CGeneralMemoryHeap(const CGeneralMemoryHeap&) = delete;
|
||||
CGeneralMemoryHeap& operator = (const CGeneralMemoryHeap&) = delete;
|
||||
|
||||
void RecordAlloc(void* ptr, size_t size);
|
||||
void RecordFree(void* ptr, size_t size);
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<AZ::AllocatorWrapper<GeneralMemoryHeapAllocator>> m_allocator;
|
||||
AZStd::atomic_int m_refCount;
|
||||
void* m_block;
|
||||
size_t m_blockSize;
|
||||
AZStd::set<Alloc, AZStd::less<Alloc>, AZ::AZStdAlloc<AZ::LegacyAllocator>> m_allocs;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H
|
||||
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include "ImageHandler.h"
|
||||
#include <numeric>
|
||||
#include "ScopeGuard.h"
|
||||
#include "Algorithm.h"
|
||||
#include "System.h"
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#include AZ_RESTRICTED_FILE(ImageHandler_cpp)
|
||||
#endif
|
||||
|
||||
#if !(defined(ANDROID) || defined(IOS) || defined(LINUX)) && AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO // Rally US1050 - Compile libtiff for Android and IOS
|
||||
#include <tiffio.h>
|
||||
|
||||
static_assert(sizeof(thandle_t) >= sizeof(AZ::IO::HandleType), "Platform defines thandle_t to be smaller than required");
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
class Image
|
||||
: public IImageHandler::IImage
|
||||
{
|
||||
public:
|
||||
Image(std::vector<unsigned char>&& data, int width, int height)
|
||||
{
|
||||
CRY_ASSERT(data.size() == width * height * ImageHandler::c_BytesPerPixel);
|
||||
m_data = std::move(data);
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
}
|
||||
private:
|
||||
virtual const std::vector<unsigned char>& GetData() const override { return m_data; }
|
||||
virtual int GetWidth() const override { return m_width; }
|
||||
virtual int GetHeight() const override { return m_height; }
|
||||
|
||||
unsigned int m_width;
|
||||
unsigned int m_height;
|
||||
std::vector<unsigned char> m_data;
|
||||
};
|
||||
#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO
|
||||
struct TiffIO
|
||||
{
|
||||
static tsize_t Read(thandle_t handle, tdata_t buffer, tsize_t size)
|
||||
{
|
||||
AZ::u64 bytesRead = 0;
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Read(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)), buffer, size, false, &bytesRead);
|
||||
return static_cast<tsize_t>(bytesRead);
|
||||
};
|
||||
|
||||
static tsize_t Write(thandle_t handle, tdata_t buffer, tsize_t size)
|
||||
{
|
||||
AZ::u64 sizeWritten;
|
||||
if (AZ::IO::FileIOBase::GetDirectInstance()->Write(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)), buffer, size, &sizeWritten))
|
||||
{
|
||||
return static_cast<tsize_t>(sizeWritten);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static int Close(thandle_t handle)
|
||||
{
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Close(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)));
|
||||
return 0;
|
||||
};
|
||||
|
||||
static toff_t Seek(thandle_t handle, toff_t pos, int mode)
|
||||
{
|
||||
if (AZ::IO::FileIOBase::GetDirectInstance()->Seek(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)), static_cast<uint64_t>(pos), AZ::IO::GetSeekTypeFromFSeekMode(mode)))
|
||||
{
|
||||
if (mode == SEEK_SET)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::u64 offsetFromBegin;
|
||||
if (AZ::IO::FileIOBase::GetDirectInstance()->Tell(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)), offsetFromBegin))
|
||||
{
|
||||
return static_cast<tsize_t>(offsetFromBegin);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
static toff_t Size(thandle_t handle)
|
||||
{
|
||||
AZ::u64 fileSize = 0;
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Size(static_cast<AZ::IO::HandleType>(reinterpret_cast<AZ::u64>(handle)), fileSize);
|
||||
return static_cast<tsize_t>(fileSize);
|
||||
};
|
||||
|
||||
static int Map(thandle_t, tdata_t*, toff_t*)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void Unmap(thandle_t, tdata_t, toff_t)
|
||||
{
|
||||
return;
|
||||
};
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<IImageHandler::IImage> ImageHandler::CreateImage(std::vector<unsigned char>&& data, int width, int height) const
|
||||
{
|
||||
return std::make_unique<Image>(std::move(data), width, height);
|
||||
}
|
||||
|
||||
std::unique_ptr<IImageHandler::IImage> ImageHandler::LoadImage([[maybe_unused]] const char* filename) const
|
||||
{
|
||||
#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO
|
||||
|
||||
AZ::IO::HandleType fileHandle;
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode("rb"), fileHandle);
|
||||
|
||||
if (fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to open image file %s", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto tifHandle = std17::unique_resource_checked(TIFFClientOpen(filename, "rb", reinterpret_cast<thandle_t>(static_cast<AZ::u64>(fileHandle)), TiffIO::Read, TiffIO::Write, TiffIO::Seek, TiffIO::Close, &TiffIO::Size, TiffIO::Map, TiffIO::Unmap), (TIFF*)nullptr, TIFFClose);
|
||||
if (!tifHandle)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to load image %s", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
TIFFGetField(tifHandle, TIFFTAG_IMAGEWIDTH, &width);
|
||||
TIFFGetField(tifHandle, TIFFTAG_IMAGELENGTH, &height);
|
||||
std::vector<unsigned char> data(4 * width * height);
|
||||
if (!TIFFReadRGBAImageOriented(tifHandle, width, height, reinterpret_cast<uint32*>(data.data()), ORIENTATION_TOPLEFT))
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to load image %s", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//strip alpha
|
||||
int every4th = 0;
|
||||
data.erase(std::remove_if(begin(data), end(data), [&](unsigned char)
|
||||
{
|
||||
return (every4th++ & 3) == 3;
|
||||
}), end(data));
|
||||
|
||||
return std::make_unique<Image>(std::move(data), width, height);
|
||||
#else
|
||||
CRY_ASSERT(0); // UNIMPLEMENTED
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ImageHandler::SaveImage([[maybe_unused]] IImageHandler::IImage* image, [[maybe_unused]] const char* filename) const
|
||||
{
|
||||
#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO
|
||||
|
||||
AZ::IO::HandleType fileHandle;
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode("wb"), fileHandle);
|
||||
|
||||
if (fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to open image file for write %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto tifHandle = std17::unique_resource_checked(TIFFClientOpen(filename, "wb", reinterpret_cast<thandle_t>(static_cast<AZ::u64>(fileHandle)), TiffIO::Read, TiffIO::Write, TiffIO::Seek, TiffIO::Close, &TiffIO::Size, TiffIO::Map, TiffIO::Unmap), (TIFF*)nullptr, TIFFClose);
|
||||
if (!tifHandle)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to save image %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
TIFFSetField(tifHandle, TIFFTAG_IMAGEWIDTH, image->GetWidth());
|
||||
TIFFSetField(tifHandle, TIFFTAG_IMAGELENGTH, image->GetHeight());
|
||||
TIFFSetField(tifHandle, TIFFTAG_SAMPLESPERPIXEL, c_BytesPerPixel);
|
||||
TIFFSetField(tifHandle, TIFFTAG_BITSPERSAMPLE, 8);
|
||||
TIFFSetField(tifHandle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||
TIFFSetField(tifHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(tifHandle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
||||
TIFFSetField(tifHandle, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
|
||||
|
||||
tsize_t bytesPerLine = c_BytesPerPixel * image->GetWidth();
|
||||
std::vector<unsigned char> lineBuffer;
|
||||
if (TIFFScanlineSize(tifHandle) != bytesPerLine)
|
||||
{
|
||||
lineBuffer.resize(bytesPerLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
lineBuffer.resize(TIFFScanlineSize(tifHandle));
|
||||
}
|
||||
TIFFSetField(tifHandle, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tifHandle, image->GetWidth() * c_BytesPerPixel));
|
||||
auto srcData = image->GetData().data();
|
||||
|
||||
for (uint32 row = 0; row < image->GetHeight(); row++)
|
||||
{
|
||||
memcpy(lineBuffer.data(), &srcData[row * bytesPerLine], bytesPerLine);
|
||||
if (TIFFWriteScanline(tifHandle, lineBuffer.data(), row, 0) < 0)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Failed to write part of image %s", filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
CRY_ASSERT(0); // UNIMPLEMENTED
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<IImageHandler::IImage> ImageHandler::CreateDiffImage(IImageHandler::IImage* image1, IImageHandler::IImage* image2) const
|
||||
{
|
||||
if (!image1 || !image2)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, null arguments");
|
||||
return nullptr;
|
||||
}
|
||||
if (image1->GetWidth() != image2->GetWidth() || image1->GetHeight() != image2->GetHeight())
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, 2 images were not the same size");
|
||||
return nullptr;
|
||||
}
|
||||
CRY_ASSERT(image1->GetData().size() == image1->GetWidth() * image1->GetHeight() * ImageHandler::c_BytesPerPixel);
|
||||
CRY_ASSERT(image2->GetData().size() == image2->GetWidth() * image2->GetHeight() * ImageHandler::c_BytesPerPixel);
|
||||
|
||||
std::vector<unsigned char> resultRGBData;
|
||||
|
||||
auto iter1 = image1->GetData().data();
|
||||
auto iter2 = image2->GetData().data();
|
||||
for (int i = 0; i < image1->GetWidth() * image1->GetHeight() * c_BytesPerPixel; ++i)
|
||||
{
|
||||
resultRGBData.push_back(static_cast<unsigned char>(abs(static_cast<int>(iter1[i]) - static_cast<int>(iter2[i]))));
|
||||
}
|
||||
|
||||
return std::make_unique<Image>(std::move(resultRGBData), image1->GetWidth(), image1->GetHeight());
|
||||
}
|
||||
|
||||
float ImageHandler::CalculatePSNR(IImageHandler::IImage* diffIimage) const
|
||||
{
|
||||
if (!diffIimage)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, null arguments");
|
||||
return 0;
|
||||
}
|
||||
CRY_ASSERT(diffIimage->GetData().size() == diffIimage->GetWidth() * diffIimage->GetHeight() * ImageHandler::c_BytesPerPixel);
|
||||
|
||||
auto mse = std17::accumulate(diffIimage->GetData(), 0.0, [](double result, unsigned char value) -> double { return result += (double)value * (double)value; });
|
||||
mse /= (c_BytesPerPixel * diffIimage->GetWidth() * diffIimage->GetHeight());
|
||||
|
||||
if (mse <= 0)
|
||||
{
|
||||
return std::numeric_limits<float>::max();
|
||||
}
|
||||
|
||||
// see http://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio for a derivation of this formula and source for magic numbers
|
||||
return static_cast<float>(20 * log10(255) - 10 * log10(mse));
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H
|
||||
|
||||
#include "IImageHandler.h"
|
||||
|
||||
class ImageHandler
|
||||
: public IImageHandler
|
||||
{
|
||||
public:
|
||||
static const int c_BytesPerPixel = 3; //This only deals with RGB data for now, no alpha
|
||||
private:
|
||||
virtual std::unique_ptr<IImageHandler::IImage> CreateImage(std::vector<unsigned char>&& rgbData, int width, int height) const override;
|
||||
virtual std::unique_ptr<IImageHandler::IImage> LoadImage(const char* filename) const override;
|
||||
virtual bool SaveImage(IImageHandler::IImage* image, const char* filename) const override;
|
||||
virtual std::unique_ptr<IImageHandler::IImage> CreateDiffImage(IImageHandler::IImage* image1, IImageHandler::IImage* image2) const override;
|
||||
virtual float CalculatePSNR(IImageHandler::IImage* diffIimage) const override;
|
||||
};
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "LevelSystem.h"
|
||||
#include <IAudioSystem.h>
|
||||
#include "IMovieSystem.h"
|
||||
#include <IResourceManager.h>
|
||||
#include <ILocalizationManager.h>
|
||||
#include "CryPath.h"
|
||||
#include <Pak/CryPakUtils.h>
|
||||
@@ -778,9 +777,6 @@ void CLevelSystem::PrepareNextLevel(const char* levelName)
|
||||
// switched to level heap, so now imm start the loading screen (renderer will be reinitialized in the levelheap)
|
||||
gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN, 0, 0);
|
||||
gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PREPARE);
|
||||
|
||||
// Inform resource manager about loading of the new level.
|
||||
GetISystem()->GetIResourceManager()->PrepareLevel(pLevelInfo->GetPath(), pLevelInfo->GetName());
|
||||
}
|
||||
|
||||
for (AZStd::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
|
||||
@@ -987,8 +983,6 @@ void CLevelSystem::UnloadLevel()
|
||||
|
||||
m_lastLevelName.clear();
|
||||
|
||||
GetISystem()->GetIResourceManager()->UnloadLevel();
|
||||
|
||||
SAFE_RELEASE(m_pCurrentLevel);
|
||||
|
||||
// Force Lua garbage collection (may no longer be needed now the legacy renderer has been removed).
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "SpawnableLevelSystem.h"
|
||||
#include <IAudioSystem.h>
|
||||
#include "IMovieSystem.h"
|
||||
#include <IResourceManager.h>
|
||||
|
||||
#include <LoadScreenBus.h>
|
||||
|
||||
@@ -566,8 +565,6 @@ namespace LegacyLevelSystem
|
||||
|
||||
m_lastLevelName.clear();
|
||||
|
||||
GetISystem()->GetIResourceManager()->UnloadLevel();
|
||||
|
||||
// Force Lua garbage collection (may no longer be needed now the legacy renderer has been removed).
|
||||
// Normally the GC step is triggered at the end of this method (by the ESYSTEM_EVENT_LEVEL_POST_UNLOAD event).
|
||||
EBUS_EVENT(AZ::ScriptSystemRequestBus, GarbageCollect);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
//this should not be included here
|
||||
#include <IConsole.h>
|
||||
#include <ISystem.h>
|
||||
#include <IStreamEngine.h>
|
||||
#include "System.h"
|
||||
#include "CryPath.h" // PathUtil::ReplaceExtension()
|
||||
#include <Pak/CryPakUtils.h>
|
||||
@@ -1439,22 +1438,6 @@ void CLog::UpdateLoadingScreen(const char* szFormat, ...)
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (CryGetCurrentThreadId() == m_nMainThreadId)
|
||||
{
|
||||
#ifndef LINUX
|
||||
// Take this opportunity to update streaming engine.
|
||||
if (IStreamEngine* pStreamEngine = GetISystem()->GetStreamEngine())
|
||||
{
|
||||
const float curTime = m_pSystem->GetITimer()->GetAsyncCurTime();
|
||||
if (curTime - m_fLastLoadingUpdateTime > .1f) // not frequent than once in 100ms
|
||||
{
|
||||
m_fLastLoadingUpdateTime = curTime;
|
||||
pStreamEngine->Update();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "MTSafeAllocator.h"
|
||||
#include <IConsole.h>
|
||||
|
||||
extern CMTSafeHeap* g_pPakHeap;
|
||||
|
||||
// Uncomment this define to enable time tracing of the MTSAFE heap
|
||||
#define MTSAFE_PROFILE 1
|
||||
//#undef MTSAFE_PROFILE
|
||||
|
||||
namespace
|
||||
{
|
||||
class CSimpleTimer
|
||||
{
|
||||
LARGE_INTEGER& m_result;
|
||||
LARGE_INTEGER m_start;
|
||||
public:
|
||||
|
||||
CSimpleTimer(LARGE_INTEGER& li)
|
||||
: m_result(li)
|
||||
{ QueryPerformanceCounter(&m_start); }
|
||||
|
||||
~CSimpleTimer()
|
||||
{
|
||||
LARGE_INTEGER end;
|
||||
QueryPerformanceCounter(&end);
|
||||
m_result.QuadPart = end.QuadPart - m_start.QuadPart;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CMTSafeHeap::CMTSafeHeap()
|
||||
: m_LiveTempAllocations()
|
||||
, m_TotalAllocations()
|
||||
, m_TempAllocationsFailed()
|
||||
, m_TempAllocationsTime()
|
||||
{
|
||||
size_t allocated = 0;
|
||||
m_pGeneralHeapStorage = (char*)CryMalloc(MTSAFE_GENERAL_HEAP_SIZE, allocated, MTSAFE_DEFAULT_ALIGNMENT);
|
||||
m_pGeneralHeapStorageEnd = m_pGeneralHeapStorage + MTSAFE_GENERAL_HEAP_SIZE;
|
||||
m_pGeneralHeap = CryGetIMemoryManager()->CreateGeneralMemoryHeap(m_pGeneralHeapStorage, MTSAFE_GENERAL_HEAP_SIZE, "MTSafeHeap");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CMTSafeHeap::~CMTSafeHeap()
|
||||
{
|
||||
SAFE_RELEASE(m_pGeneralHeap);
|
||||
CryFree(m_pGeneralHeapStorage, MTSAFE_DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
size_t CMTSafeHeap::PersistentAllocSize(size_t nSize)
|
||||
{
|
||||
return nSize;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CMTSafeHeap::PersistentAlloc(size_t nSize)
|
||||
{
|
||||
size_t allocated = 0;
|
||||
return CryMalloc(nSize, allocated, MTSAFE_DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMTSafeHeap::FreePersistent(void* p)
|
||||
{
|
||||
CryFree(p, MTSAFE_DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CMTSafeHeap::TempAlloc(size_t nSize, const char* szDbgSource, bool& bFallBackToMalloc, uint32 align)
|
||||
{
|
||||
# if MTSAFE_PROFILE
|
||||
CSimpleTimer timer(m_TempAllocationsTime);
|
||||
# endif
|
||||
|
||||
void* ptr = NULL;
|
||||
if (align)
|
||||
{
|
||||
ptr = m_pGeneralHeap->Memalign(align, nSize, szDbgSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = m_pGeneralHeap->Malloc(nSize, szDbgSource);
|
||||
}
|
||||
|
||||
//explicit alignment not supported beyond this point, safer to return NULL
|
||||
if (ptr || !bFallBackToMalloc)
|
||||
{
|
||||
bFallBackToMalloc = false;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bFallBackToMalloc = true;
|
||||
|
||||
# if MTSAFE_PROFILE
|
||||
CryInterlockedAdd((volatile int*)&m_TempAllocationsFailed, (int)nSize);
|
||||
# endif
|
||||
|
||||
return CryModuleMemalign(nSize, align > 0 ? align : MTSAFE_DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMTSafeHeap::FreeTemporary(void* p)
|
||||
{
|
||||
# if MTSAFE_PROFILE
|
||||
CSimpleTimer timer(m_TempAllocationsTime);
|
||||
# endif
|
||||
|
||||
if (m_pGeneralHeap->IsInAddressRange(p))
|
||||
{
|
||||
m_pGeneralHeap->Free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to free
|
||||
CryModuleMemalignFree(p);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CMTSafeHeap::StaticAlloc([[maybe_unused]] void* pOpaque, unsigned nItems, unsigned nSize)
|
||||
{
|
||||
return g_pPakHeap->TempAlloc(nItems * nSize, "StaticAlloc");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMTSafeHeap::StaticFree ([[maybe_unused]] void* pOpaque, void* pAddress)
|
||||
{
|
||||
g_pPakHeap->FreeTemporary(pAddress);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMTSafeHeap::GetMemoryUsage(ICrySizer* pSizer)
|
||||
{
|
||||
SIZER_COMPONENT_NAME(pSizer, "FileSystem Pool");
|
||||
}
|
||||
|
||||
void CMTSafeHeap::PrintStats()
|
||||
{
|
||||
# if MTSAFE_PROFILE
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
const double rFreq = 1. / static_cast<double>(freq.QuadPart);
|
||||
|
||||
CryLogAlways("mtsafe temporary pool failed for %" PRISIZE_T " bytes, time spent in allocations %3.08f seconds",
|
||||
m_TempAllocationsFailed, static_cast<double>(m_TempAllocationsTime.QuadPart) * rFreq);
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined(LINUX)
|
||||
# include "Linux_Win32Wrapper.h"
|
||||
#endif
|
||||
#include <ISystem.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#include AZ_RESTRICTED_FILE(MTSafeAllocator_h)
|
||||
#endif
|
||||
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
||||
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#elif defined(MOBILE) // IOS/Android
|
||||
# define MTSAFE_DEFAULT_ALIGNMENT 8
|
||||
# define MTSAFE_GENERAL_HEAP_SIZE ((1U << 20) + (1U << 19))
|
||||
#elif defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(MAC)
|
||||
# define MTSAFE_GENERAL_HEAP_SIZE (12U << 20)
|
||||
# define MTSAFE_DEFAULT_ALIGNMENT 8
|
||||
#else
|
||||
# error Unknown target platform
|
||||
#endif
|
||||
|
||||
class CMTSafeHeap
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
CMTSafeHeap();
|
||||
|
||||
// Destructor
|
||||
~CMTSafeHeap();
|
||||
|
||||
// Performs a persisistent (in other words, non-temporary) allocation.
|
||||
void* PersistentAlloc(size_t nSize);
|
||||
|
||||
// Retrieves system memory allocation size for any call to PersistentAlloc.
|
||||
// Required to not count virtual memory usage inside CrySizer
|
||||
size_t PersistentAllocSize(size_t nSize);
|
||||
|
||||
// Frees memory allocation
|
||||
void FreePersistent(void* p);
|
||||
|
||||
// Perform a allocation that is considered temporary and will be handled by
|
||||
// the pool itself.
|
||||
// Note: It is important that these temporary allocations are actually
|
||||
// temporary and do not persist for a long persiod of time.
|
||||
void* TempAlloc (size_t nSize, const char* szDbgSource, uint32 align = 0)
|
||||
{
|
||||
bool bFallbackToMalloc = true;
|
||||
return TempAlloc(nSize, szDbgSource, bFallbackToMalloc, align);
|
||||
}
|
||||
|
||||
void* TempAlloc (size_t nSize, const char* szDbgSource, bool& bFallBackToMalloc, uint32 align = 0);
|
||||
|
||||
bool IsInGeneralHeap(const void* p)
|
||||
{
|
||||
return m_pGeneralHeapStorage <= p && p < m_pGeneralHeapStorageEnd;
|
||||
}
|
||||
|
||||
// Free a temporary allocaton.
|
||||
void FreeTemporary(void* p);
|
||||
|
||||
// The number of live allocations allocation within the temporary pool
|
||||
size_t NumAllocations() const { return m_LiveTempAllocations; }
|
||||
|
||||
// The memory usage of the mtsafe allocator
|
||||
void GetMemoryUsage(ICrySizer* pSizer);
|
||||
|
||||
// zlib-compatible stubs
|
||||
static void* StaticAlloc (void* pOpaque, unsigned nItems, unsigned nSize);
|
||||
static void StaticFree (void* pOpaque, void* pAddress);
|
||||
|
||||
// Dump some statistics to the cry log
|
||||
void PrintStats();
|
||||
|
||||
|
||||
private:
|
||||
friend class CSystem;
|
||||
|
||||
IGeneralMemoryHeap* m_pGeneralHeap;
|
||||
char* m_pGeneralHeapStorage;
|
||||
char* m_pGeneralHeapStorageEnd;
|
||||
|
||||
// The number of temporary allocations currently active within the pool
|
||||
size_t m_LiveTempAllocations;
|
||||
|
||||
// The total number of allocations performed in the pool
|
||||
size_t m_TotalAllocations;
|
||||
|
||||
// The total bytes that weren't temporarily allocated
|
||||
size_t m_TempAllocationsFailed;
|
||||
// The total number of temporary allocations that fell back to global system memory
|
||||
LARGE_INTEGER m_TempAllocationsTime;
|
||||
};
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "MemoryAddressRange.h"
|
||||
#include "System.h"
|
||||
|
||||
#if defined(APPLE) || defined(LINUX)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
CMemoryAddressRange::CMemoryAddressRange(char* pBaseAddress, size_t nPageSize, size_t nPageCount, [[maybe_unused]] const char* sName)
|
||||
: m_pBaseAddress(pBaseAddress)
|
||||
, m_nPageSize(nPageSize)
|
||||
, m_nPageCount(nPageCount)
|
||||
{
|
||||
}
|
||||
|
||||
void CMemoryAddressRange::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
char* CMemoryAddressRange::GetBaseAddress() const
|
||||
{
|
||||
return m_pBaseAddress;
|
||||
}
|
||||
|
||||
size_t CMemoryAddressRange::GetPageCount() const
|
||||
{
|
||||
return m_nPageCount;
|
||||
}
|
||||
|
||||
size_t CMemoryAddressRange::GetPageSize() const
|
||||
{
|
||||
return m_nPageSize;
|
||||
}
|
||||
|
||||
#if AZ_LEGACY_CRYSYSTEM_TRAIT_MEMADDRESSRANGE_WINDOWS_STYLE
|
||||
|
||||
void* CMemoryAddressRange::ReserveSpace(size_t capacity)
|
||||
{
|
||||
return VirtualAlloc(NULL, capacity, MEM_RESERVE, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
size_t CMemoryAddressRange::GetSystemPageSize()
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
}
|
||||
|
||||
CMemoryAddressRange::CMemoryAddressRange(size_t capacity, [[maybe_unused]] const char* name)
|
||||
{
|
||||
m_nPageSize = GetSystemPageSize();
|
||||
|
||||
size_t algnCap = Align(capacity, m_nPageSize);
|
||||
m_pBaseAddress = (char*)ReserveSpace(algnCap);
|
||||
m_nPageCount = algnCap / m_nPageSize;
|
||||
}
|
||||
|
||||
CMemoryAddressRange::~CMemoryAddressRange()
|
||||
{
|
||||
VirtualFree(m_pBaseAddress, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void* CMemoryAddressRange::MapPage(size_t pageIdx)
|
||||
{
|
||||
void* pRet = VirtualAlloc(m_pBaseAddress + pageIdx * m_nPageSize, m_nPageSize, MEM_COMMIT, PAGE_READWRITE);
|
||||
return pRet;
|
||||
}
|
||||
|
||||
void CMemoryAddressRange::UnmapPage(size_t pageIdx)
|
||||
{
|
||||
char* pBase = m_pBaseAddress + pageIdx * m_nPageSize;
|
||||
|
||||
// Disable warning about only decommitting pages, and not releasing them
|
||||
VirtualFree(pBase, m_nPageSize, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
#elif defined(AZ_RESTRICTED_PLATFORM)
|
||||
#include AZ_RESTRICTED_FILE(MemoryAddressRange_cpp)
|
||||
#elif defined(APPLE) || defined(LINUX)
|
||||
|
||||
void* CMemoryAddressRange::ReserveSpace(size_t capacity)
|
||||
{
|
||||
return mmap(0, capacity, PROT_NONE, MAP_ANON | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
|
||||
size_t CMemoryAddressRange::GetSystemPageSize()
|
||||
{
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
CMemoryAddressRange::CMemoryAddressRange(size_t capacity, const char* name)
|
||||
{
|
||||
m_nPageSize = GetSystemPageSize();
|
||||
|
||||
m_allocatedSpace = Align(capacity, m_nPageSize);
|
||||
m_pBaseAddress = (char*)ReserveSpace(m_allocatedSpace);
|
||||
assert(m_pBaseAddress != MAP_FAILED);
|
||||
m_nPageCount = m_allocatedSpace / m_nPageSize;
|
||||
}
|
||||
|
||||
CMemoryAddressRange::~CMemoryAddressRange()
|
||||
{
|
||||
int ret = munmap(m_pBaseAddress, m_allocatedSpace);
|
||||
(void) ret;
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
void* CMemoryAddressRange::MapPage(size_t pageIdx)
|
||||
{
|
||||
// There is no equivalent to this function with mmap, this
|
||||
// happens automatically in the OS. We just return the
|
||||
// correct address.
|
||||
void* pRet = NULL;
|
||||
if (0 == mprotect(m_pBaseAddress + (pageIdx * m_nPageSize), m_nPageSize, PROT_READ | PROT_WRITE))
|
||||
{
|
||||
pRet = m_pBaseAddress + (pageIdx * m_nPageSize);
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
void CMemoryAddressRange::UnmapPage(size_t pageIdx)
|
||||
{
|
||||
char* pBase = m_pBaseAddress + pageIdx * m_nPageSize;
|
||||
int ret = mprotect(pBase, m_nPageSize, PROT_NONE);
|
||||
(void) ret;
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "IMemory.h"
|
||||
|
||||
class CMemoryAddressRange
|
||||
: public IMemoryAddressRange
|
||||
{
|
||||
public:
|
||||
static void* ReserveSpace(size_t sz);
|
||||
static size_t GetSystemPageSize();
|
||||
|
||||
public:
|
||||
CMemoryAddressRange(char* pBaseAddress, size_t nPageSize, size_t nPageCount, const char* sName);
|
||||
CMemoryAddressRange(size_t capacity, const char* name);
|
||||
~CMemoryAddressRange();
|
||||
|
||||
ILINE bool IsInRange(void* p) const
|
||||
{
|
||||
return m_pBaseAddress <= p && p < (m_pBaseAddress + m_nPageSize * m_nPageCount);
|
||||
}
|
||||
|
||||
public:
|
||||
void Release();
|
||||
|
||||
char* GetBaseAddress() const;
|
||||
size_t GetPageCount() const;
|
||||
size_t GetPageSize() const;
|
||||
|
||||
void* MapPage(size_t pageIdx);
|
||||
void UnmapPage(size_t pageIdx);
|
||||
|
||||
private:
|
||||
CMemoryAddressRange(const CMemoryAddressRange&);
|
||||
CMemoryAddressRange& operator = (const CMemoryAddressRange&);
|
||||
|
||||
private:
|
||||
char* m_pBaseAddress;
|
||||
size_t m_nPageSize;
|
||||
size_t m_nPageCount;
|
||||
#if defined(APPLE) || defined(LINUX)
|
||||
size_t m_allocatedSpace; // Required to unmap latter on
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "platform.h"
|
||||
#include "CustomMemoryHeap.h"
|
||||
#include "GeneralMemoryHeap.h"
|
||||
#include "PageMappingHeap.h"
|
||||
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#undef AZ_RESTRICTED_SECTION
|
||||
#define MEMORYMANAGER_CPP_SECTION_1 1
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(APPLE)
|
||||
#include <mach/mach.h> // task_info
|
||||
#endif
|
||||
|
||||
#if defined(APPLE) || defined(LINUX)
|
||||
#include <sys/types.h> // required by mman.h
|
||||
#include <sys/mman.h> //mmap - virtual memory manager
|
||||
#endif
|
||||
|
||||
#ifdef MEMMAN_STATIC
|
||||
CCryMemoryManager g_memoryManager;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCryMemoryManager* CCryMemoryManager::GetInstance()
|
||||
{
|
||||
#ifdef MEMMAN_STATIC
|
||||
return &g_memoryManager;
|
||||
#else
|
||||
static CCryMemoryManager memman;
|
||||
return &memman;
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CCryMemoryManager::GetProcessMemInfo(SProcessMemInfo& minfo)
|
||||
{
|
||||
ZeroStruct(minfo);
|
||||
#if defined(WIN32)
|
||||
|
||||
MEMORYSTATUSEX mem;
|
||||
mem.dwLength = sizeof(mem);
|
||||
GlobalMemoryStatusEx (&mem);
|
||||
|
||||
minfo.TotalPhysicalMemory = mem.ullTotalPhys;
|
||||
minfo.FreePhysicalMemory = mem.ullAvailPhys;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
typedef BOOL (WINAPI * GetProcessMemoryInfoProc)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD);
|
||||
|
||||
PROCESS_MEMORY_COUNTERS pc;
|
||||
ZeroStruct(pc);
|
||||
pc.cb = sizeof(pc);
|
||||
static HMODULE hPSAPI = LoadLibraryA("psapi.dll");
|
||||
if (hPSAPI)
|
||||
{
|
||||
static GetProcessMemoryInfoProc pGetProcessMemoryInfo = (GetProcessMemoryInfoProc)GetProcAddress(hPSAPI, "GetProcessMemoryInfo");
|
||||
if (pGetProcessMemoryInfo)
|
||||
{
|
||||
if (pGetProcessMemoryInfo(GetCurrentProcess(), &pc, sizeof(pc)))
|
||||
{
|
||||
minfo.PageFaultCount = pc.PageFaultCount;
|
||||
minfo.PeakWorkingSetSize = pc.PeakWorkingSetSize;
|
||||
minfo.WorkingSetSize = pc.WorkingSetSize;
|
||||
minfo.QuotaPeakPagedPoolUsage = pc.QuotaPeakPagedPoolUsage;
|
||||
minfo.QuotaPagedPoolUsage = pc.QuotaPagedPoolUsage;
|
||||
minfo.QuotaPeakNonPagedPoolUsage = pc.QuotaPeakNonPagedPoolUsage;
|
||||
minfo.QuotaNonPagedPoolUsage = pc.QuotaNonPagedPoolUsage;
|
||||
minfo.PagefileUsage = pc.PagefileUsage;
|
||||
minfo.PeakPagefileUsage = pc.PeakPagefileUsage;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION MEMORYMANAGER_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE(MemoryManager_cpp)
|
||||
#endif
|
||||
|
||||
bool retVal = true;
|
||||
|
||||
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
||||
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
||||
#elif defined(LINUX)
|
||||
|
||||
MEMORYSTATUS MemoryStatus;
|
||||
GlobalMemoryStatus(&MemoryStatus);
|
||||
minfo.PagefileUsage = minfo.PeakPagefileUsage = MemoryStatus.dwTotalPhys - MemoryStatus.dwAvailPhys;
|
||||
|
||||
minfo.FreePhysicalMemory = MemoryStatus.dwAvailPhys;
|
||||
minfo.TotalPhysicalMemory = MemoryStatus.dwTotalPhys;
|
||||
|
||||
#if defined(ANDROID)
|
||||
// On Android, mallinfo() is an EXTREMELY time consuming operation. Nearly 80% CPU time will be spent
|
||||
// on this operation once -memreplay is given. Since WorkingSetSize is only used for statistics and
|
||||
// debugging purpose, it's simply ignored.
|
||||
minfo.WorkingSetSize = 0;
|
||||
#else
|
||||
struct mallinfo meminfo = mallinfo();
|
||||
minfo.WorkingSetSize = meminfo.usmblks + meminfo.uordblks;
|
||||
#endif
|
||||
|
||||
#elif defined(APPLE)
|
||||
|
||||
MEMORYSTATUS MemoryStatus;
|
||||
GlobalMemoryStatus(&MemoryStatus);
|
||||
minfo.PagefileUsage = minfo.PeakPagefileUsage = MemoryStatus.dwTotalPhys - MemoryStatus.dwAvailPhys;
|
||||
|
||||
minfo.FreePhysicalMemory = MemoryStatus.dwAvailPhys;
|
||||
minfo.TotalPhysicalMemory = MemoryStatus.dwTotalPhys;
|
||||
|
||||
// Retrieve WorkingSetSize from task_info
|
||||
task_basic_info kTaskInfo;
|
||||
mach_msg_type_number_t uInfoCount(sizeof(kTaskInfo) / sizeof(natural_t));
|
||||
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&kTaskInfo, &uInfoCount) != 0)
|
||||
{
|
||||
gEnv->pLog->LogError("task_info failed\n");
|
||||
return false;
|
||||
}
|
||||
minfo.WorkingSetSize = kTaskInfo.resident_size;
|
||||
|
||||
#else
|
||||
|
||||
retVal = false;
|
||||
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCryMemoryManager::HeapHandle CCryMemoryManager::TraceDefineHeap([[maybe_unused]] const char* heapName, [[maybe_unused]] size_t size, [[maybe_unused]] const void* pBase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryMemoryManager::TraceHeapAlloc([[maybe_unused]] HeapHandle heap, [[maybe_unused]] void* mem, [[maybe_unused]] size_t size, [[maybe_unused]] size_t blockSize, [[maybe_unused]] const char* sUsage, [[maybe_unused]] const char* sNameHint)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryMemoryManager::TraceHeapFree([[maybe_unused]] HeapHandle heap, [[maybe_unused]] void* mem, [[maybe_unused]] size_t blockSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryMemoryManager::TraceHeapSetColor([[maybe_unused]] uint32 color)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryMemoryManager::TraceHeapSetLabel([[maybe_unused]] const char* sLabel)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
uint32 CCryMemoryManager::TraceHeapGetColor()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ICustomMemoryHeap* const CCryMemoryManager::CreateCustomMemoryHeapInstance(IMemoryManager::EAllocPolicy const eAllocPolicy)
|
||||
{
|
||||
return new CCustomMemoryHeap(eAllocPolicy);
|
||||
}
|
||||
|
||||
IGeneralMemoryHeap* CCryMemoryManager::CreateGeneralExpandingMemoryHeap(size_t upperLimit, size_t reserveSize, const char* sUsage)
|
||||
{
|
||||
return new CGeneralMemoryHeap(static_cast<UINT_PTR>(0), upperLimit, reserveSize, sUsage);
|
||||
}
|
||||
|
||||
IGeneralMemoryHeap* CCryMemoryManager::CreateGeneralMemoryHeap(void* base, size_t sz, const char* sUsage)
|
||||
{
|
||||
return new CGeneralMemoryHeap(base, sz, sUsage);
|
||||
}
|
||||
|
||||
IMemoryAddressRange* CCryMemoryManager::ReserveAddressRange(size_t capacity, const char* sName)
|
||||
{
|
||||
return new CMemoryAddressRange(capacity, sName);
|
||||
}
|
||||
|
||||
IPageMappingHeap* CCryMemoryManager::CreatePageMappingHeap(size_t addressSpace, const char* sName)
|
||||
{
|
||||
return new CPageMappingHeap(addressSpace, sName);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
CRYMEMORYMANAGER_API void CryGetIMemoryManagerInterface(void** pIMemoryManager)
|
||||
{
|
||||
// Static instance of the memory manager
|
||||
*pIMemoryManager = CCryMemoryManager::GetInstance();
|
||||
}
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include "ISystem.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Class that implements IMemoryManager interface.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#ifndef MEMMAN_STATIC
|
||||
class CCryMemoryManager
|
||||
: public IMemoryManager
|
||||
{
|
||||
public:
|
||||
// Singleton
|
||||
static CCryMemoryManager* GetInstance();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual bool GetProcessMemInfo(SProcessMemInfo& minfo);
|
||||
|
||||
virtual HeapHandle TraceDefineHeap(const char* heapName, size_t size, const void* pBase);
|
||||
virtual void TraceHeapAlloc(HeapHandle heap, void* mem, size_t size, size_t blockSize, const char* sUsage, const char* sNameHint = 0);
|
||||
virtual void TraceHeapFree(HeapHandle heap, void* mem, size_t blockSize);
|
||||
virtual void TraceHeapSetColor(uint32 color);
|
||||
virtual uint32 TraceHeapGetColor();
|
||||
virtual void TraceHeapSetLabel(const char* sLabel);
|
||||
|
||||
virtual ICustomMemoryHeap* const CreateCustomMemoryHeapInstance(IMemoryManager::EAllocPolicy const eAllocPolicy);
|
||||
virtual IGeneralMemoryHeap* CreateGeneralExpandingMemoryHeap(size_t upperLimit, size_t reserveSize, const char* sUsage);
|
||||
virtual IGeneralMemoryHeap* CreateGeneralMemoryHeap(void* base, size_t sz, const char* sUsage);
|
||||
|
||||
virtual IMemoryAddressRange* ReserveAddressRange(size_t capacity, const char* sName);
|
||||
virtual IPageMappingHeap* CreatePageMappingHeap(size_t addressSpace, const char* sName);
|
||||
};
|
||||
#else
|
||||
typedef IMemoryManager CCryMemoryManager;
|
||||
#endif
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "PageMappingHeap.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Func>
|
||||
inline void FindZeroRanges(const uint32* str, size_t strLen, Func& yield)
|
||||
{
|
||||
size_t carry = 0;
|
||||
size_t bitIdx = 0;
|
||||
|
||||
for (size_t wordIdx = 0; wordIdx < strLen; ++wordIdx)
|
||||
{
|
||||
size_t wordBitIdx = 0;
|
||||
int64 word = str[wordIdx];
|
||||
|
||||
// Set up sign extension to insert bits that are the last bit, inverted.
|
||||
|
||||
if (!(word & 0x80000000))
|
||||
{
|
||||
reinterpret_cast<uint64&>(word) |= 0xffffffff00000000ULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
size_t wordZeroRunLen = countTrailingZeroes(word);
|
||||
|
||||
wordBitIdx += wordZeroRunLen;
|
||||
carry += wordZeroRunLen;
|
||||
|
||||
if (wordBitIdx == 32)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
yield(bitIdx, carry);
|
||||
word >>= wordZeroRunLen;
|
||||
bitIdx += carry;
|
||||
carry = 0;
|
||||
|
||||
size_t wordOneRunLen = countTrailingZeroes(~word);
|
||||
bitIdx += wordOneRunLen;
|
||||
wordBitIdx += wordOneRunLen;
|
||||
|
||||
if (wordBitIdx == 32)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
word >>= wordOneRunLen;
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
if (carry)
|
||||
{
|
||||
yield(bitIdx, carry);
|
||||
}
|
||||
}
|
||||
|
||||
struct DLMMapFindBest
|
||||
{
|
||||
DLMMapFindBest(size_t size)
|
||||
: requiredLength(size)
|
||||
, bestPosition(-1)
|
||||
, bestFragmentLength(INT_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator () (size_t position, size_t length)
|
||||
{
|
||||
if (length == requiredLength)
|
||||
{
|
||||
bestPosition = position;
|
||||
bestFragmentLength = 0;
|
||||
return false;
|
||||
}
|
||||
else if (length > requiredLength)
|
||||
{
|
||||
size_t fragment = length - requiredLength;
|
||||
if (fragment < bestFragmentLength)
|
||||
{
|
||||
bestPosition = position;
|
||||
bestFragmentLength = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t requiredLength;
|
||||
ptrdiff_t bestPosition;
|
||||
size_t bestFragmentLength;
|
||||
};
|
||||
|
||||
struct FindLargest
|
||||
{
|
||||
FindLargest()
|
||||
: largest(0)
|
||||
{
|
||||
}
|
||||
bool operator () (size_t, size_t length)
|
||||
{
|
||||
largest = max(largest, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t largest;
|
||||
};
|
||||
}
|
||||
|
||||
CPageMappingHeap::CPageMappingHeap(char* pAddressSpace, size_t nNumPages, size_t nPageSize, const char* sName)
|
||||
: m_addrRange(pAddressSpace, nPageSize, nNumPages, sName)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CPageMappingHeap::CPageMappingHeap(size_t addressSpace, const char* sName)
|
||||
: m_addrRange(addressSpace, sName)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CPageMappingHeap::~CPageMappingHeap()
|
||||
{
|
||||
}
|
||||
|
||||
void CPageMappingHeap::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
size_t CPageMappingHeap::GetGranularity() const
|
||||
{
|
||||
return m_addrRange.GetPageSize();
|
||||
}
|
||||
|
||||
bool CPageMappingHeap::IsInAddressRange(void* ptr) const
|
||||
{
|
||||
return m_addrRange.IsInRange(ptr);
|
||||
}
|
||||
|
||||
size_t CPageMappingHeap::FindLargestFreeBlockSize() const
|
||||
{
|
||||
CryAutoLock<CryCriticalSectionNonRecursive> lock(m_lock);
|
||||
|
||||
const size_t pageSize = m_addrRange.GetPageSize();
|
||||
|
||||
FindLargest findLargest;
|
||||
FindZeroRanges(&m_pageBitmap[0], m_pageBitmap.size(), findLargest);
|
||||
|
||||
return findLargest.largest * pageSize;
|
||||
}
|
||||
|
||||
void* CPageMappingHeap::Map(size_t length)
|
||||
{
|
||||
CryAutoLock<CryCriticalSectionNonRecursive> lock(m_lock);
|
||||
|
||||
const size_t pageBitmapElemBitSize = (sizeof(uint32) * 8);
|
||||
const size_t pageSize = m_addrRange.GetPageSize();
|
||||
const size_t numPages = m_addrRange.GetPageCount();
|
||||
|
||||
if (length % pageSize)
|
||||
{
|
||||
__debugbreak();
|
||||
length = (length + (pageSize - 1)) & ~(pageSize - 1);
|
||||
}
|
||||
|
||||
DLMMapFindBest findBest(length / pageSize);
|
||||
FindZeroRanges(&m_pageBitmap[0], m_pageBitmap.size(), findBest);
|
||||
|
||||
if ((findBest.bestPosition == -1) || (findBest.bestPosition >= (int)numPages))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* mapAddress = m_addrRange.GetBaseAddress() + pageSize * findBest.bestPosition;
|
||||
|
||||
for (size_t pageIdx = findBest.bestPosition, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx)
|
||||
{
|
||||
if (!m_addrRange.MapPage(pageIdx))
|
||||
{
|
||||
// Unwind the pages we've already mapped.
|
||||
for (; pageIdx > static_cast<size_t>(findBest.bestPosition); --pageIdx)
|
||||
{
|
||||
m_addrRange.UnmapPage(pageIdx - 1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t pageIdx = findBest.bestPosition, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx)
|
||||
{
|
||||
size_t pageSegment = pageIdx / pageBitmapElemBitSize;
|
||||
uint32 pageMask = 1U << static_cast<uint32>(pageIdx % pageBitmapElemBitSize);
|
||||
|
||||
m_pageBitmap[pageSegment] |= pageMask;
|
||||
}
|
||||
|
||||
return mapAddress;
|
||||
}
|
||||
|
||||
void CPageMappingHeap::Unmap(void* mem, size_t length)
|
||||
{
|
||||
CryAutoLock<CryCriticalSectionNonRecursive> lock(m_lock);
|
||||
const size_t pageSize = m_addrRange.GetPageSize();
|
||||
|
||||
if (length % pageSize)
|
||||
{
|
||||
__debugbreak();
|
||||
length = (length + (pageSize - 1)) & ~(pageSize - 1);
|
||||
}
|
||||
|
||||
char* mapAddress = reinterpret_cast<char*>(mem);
|
||||
for (size_t pageIdx = (mapAddress - m_addrRange.GetBaseAddress()) / pageSize, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx)
|
||||
{
|
||||
m_addrRange.UnmapPage(pageIdx);
|
||||
|
||||
const size_t pageBitmapElemBitSize = (sizeof(uint32) * 8);
|
||||
|
||||
size_t pageSegment = pageIdx / pageBitmapElemBitSize;
|
||||
uint32 pageMask = ~(1U << static_cast<uint32>(pageIdx % pageBitmapElemBitSize));
|
||||
|
||||
m_pageBitmap[pageSegment] &= pageMask;
|
||||
}
|
||||
}
|
||||
|
||||
void CPageMappingHeap::Init()
|
||||
{
|
||||
UINT_PTR start = (UINT_PTR)m_addrRange.GetBaseAddress();
|
||||
UINT_PTR end = start + m_addrRange.GetPageCount() * m_addrRange.GetPageSize();
|
||||
|
||||
size_t addressSpace = end - start;
|
||||
size_t pageSize = m_addrRange.GetPageSize();
|
||||
size_t numPages = (addressSpace + pageSize - 1) / pageSize;
|
||||
m_pageBitmap.resize((numPages + 31) / 32);
|
||||
|
||||
size_t pageCapacity = m_pageBitmap.size() * 32;
|
||||
size_t numUnavailablePages = pageCapacity - numPages;
|
||||
if (numUnavailablePages > 0)
|
||||
{
|
||||
m_pageBitmap.back() = ~((1 << (32 - numUnavailablePages)) - 1);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "MemoryAddressRange.h"
|
||||
|
||||
#include "IMemory.h"
|
||||
|
||||
class CPageMappingHeap
|
||||
: public IPageMappingHeap
|
||||
{
|
||||
public:
|
||||
CPageMappingHeap(char* pAddressSpace, size_t nNumPages, size_t nPageSize, const char* sName);
|
||||
CPageMappingHeap(size_t addressSpace, const char* sName);
|
||||
~CPageMappingHeap();
|
||||
|
||||
public: // IPageMappingHeap Members
|
||||
virtual void Release();
|
||||
|
||||
virtual size_t GetGranularity() const;
|
||||
virtual bool IsInAddressRange(void* ptr) const;
|
||||
|
||||
virtual size_t FindLargestFreeBlockSize() const;
|
||||
|
||||
virtual void* Map(size_t sz);
|
||||
virtual void Unmap(void* ptr, size_t sz);
|
||||
|
||||
private:
|
||||
CPageMappingHeap(const CPageMappingHeap&);
|
||||
CPageMappingHeap& operator = (const CPageMappingHeap&);
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
private:
|
||||
mutable CryCriticalSectionNonRecursive m_lock;
|
||||
CMemoryAddressRange m_addrRange;
|
||||
std::vector<uint32> m_pageBitmap;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H
|
||||
@@ -1,868 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Interface to the Resource Manager
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "System.h"
|
||||
#include "MaterialUtils.h"
|
||||
#include <CryPath.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/IO/FileOperations.h>
|
||||
#include <AzFramework/Archive/Archive.h>
|
||||
#include <AzFramework/Archive/INestedArchive.h>
|
||||
#include <Pak/CryPakUtils.h>
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#undef AZ_RESTRICTED_SECTION
|
||||
#define RESOURCEMANAGER_CPP_SECTION_1 1
|
||||
#define RESOURCEMANAGER_CPP_SECTION_2 2
|
||||
#endif
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE(ResourceManager_cpp)
|
||||
#endif
|
||||
|
||||
#define LEVEL_PAK_FILENAME "level.pak"
|
||||
#define LEVEL_PAK_INMEMORY_MAXSIZE 10 * 1024 * 1024
|
||||
|
||||
#define ENGINE_PAK_FILENAME "engine.pak"
|
||||
#define LEVEL_CACHE_PAK_FILENAME "xml.pak"
|
||||
|
||||
#define GAME_DATA_PAK_FILENAME "gamedata.pak"
|
||||
#define FAST_LOADING_PAKS_SRC_FOLDER "_fastload/"
|
||||
#define FRONTEND_COMMON_PAK_FILENAME_SP "modes/menucommon_sp.pak"
|
||||
#define FRONTEND_COMMON_PAK_FILENAME_MP "modes/menucommon_mp.pak"
|
||||
#define FRONTEND_COMMON_LIST_FILENAME "menucommon"
|
||||
#define LEVEL_CACHE_SRC_FOLDER "_levelcache/"
|
||||
#define LEVEL_CACHE_BIND_ROOT "LevelCache"
|
||||
#define LEVEL_RESOURCE_LIST "resourcelist.txt"
|
||||
#define AUTO_LEVEL_RESOURCE_LIST "auto_resourcelist.txt"
|
||||
#define AUTO_LEVEL_SEQUENCE_RESOURCE_LIST "auto_resources_sequence.txt"
|
||||
#define AUTO_LEVEL_TOTAL_RESOURCE_LIST "auto_resourcelist_total.txt"
|
||||
#define AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST "auto_resources_total_sequence.txt"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IResourceList implementation class.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CLevelResourceList
|
||||
: public AZ::IO::IResourceList
|
||||
{
|
||||
public:
|
||||
CLevelResourceList()
|
||||
{
|
||||
m_pFileBuffer = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_nCurrentLine = 0;
|
||||
};
|
||||
~CLevelResourceList()
|
||||
{
|
||||
Clear();
|
||||
};
|
||||
|
||||
uint32 GetFilenameHash(const char* sResourceFile)
|
||||
{
|
||||
char filename[512];
|
||||
azstrcpy(filename, AZ_ARRAY_SIZE(filename), sResourceFile);
|
||||
MaterialUtils::UnifyMaterialName(filename);
|
||||
|
||||
uint32 code = CCrc32::ComputeLowercase(filename);
|
||||
return code;
|
||||
}
|
||||
|
||||
virtual void Add([[maybe_unused]] AZStd::string_view sResourceFile)
|
||||
{
|
||||
assert(0); // Not implemented.
|
||||
}
|
||||
virtual void Clear()
|
||||
{
|
||||
delete [] m_pFileBuffer;
|
||||
m_pFileBuffer = 0;
|
||||
m_nBufferSize = 0;
|
||||
stl::free_container(m_lines);
|
||||
stl::free_container(m_resources_crc32);
|
||||
m_nCurrentLine = 0;
|
||||
}
|
||||
|
||||
struct ComparePredicate
|
||||
{
|
||||
bool operator()(const char* s1, const char* s2)
|
||||
{
|
||||
return strcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
virtual bool IsExist(AZStd::string_view sResourceFile)
|
||||
{
|
||||
uint32 nHash = GetFilenameHash(sResourceFile.data());
|
||||
if (stl::binary_find(m_resources_crc32.begin(), m_resources_crc32.end(), nHash) != m_resources_crc32.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual bool Load(AZStd::string_view sResourceListFilename)
|
||||
{
|
||||
Clear();
|
||||
CCryFile file;
|
||||
if (file.Open(sResourceListFilename.data(), "rb", AZ::IO::IArchive::FOPEN_ONDISK)) // File access can happen from disk as well.
|
||||
{
|
||||
m_nBufferSize = file.GetLength();
|
||||
if (m_nBufferSize > 0)
|
||||
{
|
||||
m_pFileBuffer = new char[m_nBufferSize];
|
||||
size_t numBytesRead = file.ReadRaw(m_pFileBuffer, file.GetLength());
|
||||
|
||||
if (numBytesRead <= 0 || numBytesRead != file.GetLength())
|
||||
{
|
||||
AZ_Error("ResourceManager", false, "Unable to read data for: %.*s", aznumeric_cast<int>(sResourceListFilename.size()), sResourceListFilename.data());
|
||||
return false;
|
||||
}
|
||||
m_pFileBuffer[m_nBufferSize - 1] = 0;
|
||||
|
||||
char seps[] = "\r\n";
|
||||
|
||||
m_lines.reserve(5000);
|
||||
|
||||
// Parse file, every line in a file represents a resource filename.
|
||||
char* nextToken = nullptr;
|
||||
char* token = azstrtok(m_pFileBuffer, 0, seps, &nextToken);
|
||||
while (token != NULL)
|
||||
{
|
||||
m_lines.push_back(token);
|
||||
token = azstrtok(NULL, 0, seps, &nextToken);
|
||||
}
|
||||
|
||||
m_resources_crc32.resize(m_lines.size());
|
||||
for (int i = 0, numlines = m_lines.size(); i < numlines; i++)
|
||||
{
|
||||
MaterialUtils::UnifyMaterialName(const_cast<char*>(m_lines[i]));
|
||||
m_resources_crc32[i] = CCrc32::ComputeLowercase(m_lines[i]);
|
||||
}
|
||||
std::sort(m_resources_crc32.begin(), m_resources_crc32.end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual const char* GetFirst()
|
||||
{
|
||||
m_nCurrentLine = 0;
|
||||
if (!m_lines.empty())
|
||||
{
|
||||
return m_lines[0];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
virtual const char* GetNext()
|
||||
{
|
||||
m_nCurrentLine++;
|
||||
if (m_nCurrentLine < (int)m_lines.size())
|
||||
{
|
||||
return m_lines[m_nCurrentLine];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GetMemoryStatistics(ICrySizer* pSizer)
|
||||
{
|
||||
pSizer->Add(this, sizeof(*this));
|
||||
pSizer->Add(m_pFileBuffer, m_nBufferSize);
|
||||
pSizer->AddContainer(m_lines);
|
||||
pSizer->AddContainer(m_resources_crc32);
|
||||
}
|
||||
|
||||
public:
|
||||
char* m_pFileBuffer;
|
||||
int m_nBufferSize;
|
||||
typedef std::vector<const char*> Lines;
|
||||
Lines m_lines;
|
||||
int m_nCurrentLine;
|
||||
std::vector<uint32> m_resources_crc32;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CResourceManager::CResourceManager()
|
||||
{
|
||||
m_bRegisteredFileOpenSink = false;
|
||||
m_bOwnResourceList = false;
|
||||
m_bLevelTransitioning = false;
|
||||
|
||||
m_fastLoadPakPaths.reserve(8);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::PrepareLevel(const char* sLevelFolder, const char* sLevelName)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
m_sLevelFolder = sLevelFolder;
|
||||
m_sLevelName = sLevelName;
|
||||
m_bLevelTransitioning = false;
|
||||
m_currentLevelCacheFolder = CryPathString(LEVEL_CACHE_SRC_FOLDER) + sLevelName;
|
||||
|
||||
if (g_cvars.archiveVars.nLoadCache)
|
||||
{
|
||||
bool usePrefabSystemForLevels = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
|
||||
|
||||
// The prefab system doesn't use level.pak
|
||||
if (!usePrefabSystemForLevels)
|
||||
{
|
||||
CryPathString levelpak = PathUtil::Make(sLevelFolder, LEVEL_PAK_FILENAME);
|
||||
size_t nPakFileSize = gEnv->pCryPak->FGetSize(levelpak.c_str());
|
||||
if (nPakFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs.
|
||||
{
|
||||
// Force level.pak from this level in memory.
|
||||
gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
|
||||
}
|
||||
}
|
||||
|
||||
gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
|
||||
|
||||
//
|
||||
// Load _levelCache paks in the order they are stored on the disk - reduce seek time
|
||||
//
|
||||
|
||||
if (gEnv->pConsole->GetCVar("e_StreamCgf") && gEnv->pConsole->GetCVar("e_StreamCgf")->GetIVal() != 0)
|
||||
{
|
||||
LoadLevelCachePak("cga.pak", "", true);
|
||||
LoadLevelCachePak("cgf.pak", "", true);
|
||||
|
||||
if (g_cvars.archiveVars.nStreamCache)
|
||||
{
|
||||
LoadLevelCachePak("cgf_cache.pak", "", false);
|
||||
}
|
||||
}
|
||||
|
||||
LoadLevelCachePak("chr.pak", "", true);
|
||||
|
||||
if (g_cvars.archiveVars.nStreamCache)
|
||||
{
|
||||
LoadLevelCachePak("chr_cache.pak", "", false);
|
||||
}
|
||||
|
||||
LoadLevelCachePak("dds0.pak", "", true);
|
||||
|
||||
if (g_cvars.archiveVars.nStreamCache)
|
||||
{
|
||||
LoadLevelCachePak("dds_cache.pak", "", false);
|
||||
}
|
||||
|
||||
LoadLevelCachePak("skin.pak", "", true);
|
||||
|
||||
if (g_cvars.archiveVars.nStreamCache)
|
||||
{
|
||||
LoadLevelCachePak("skin_cache.pak", "", false);
|
||||
}
|
||||
|
||||
LoadLevelCachePak(LEVEL_CACHE_PAK_FILENAME, "", true);
|
||||
}
|
||||
|
||||
AZStd::intrusive_ptr<CLevelResourceList> pResList = new CLevelResourceList;
|
||||
gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, pResList.get());
|
||||
m_bOwnResourceList = true;
|
||||
|
||||
// Load resourcelist.txt, TODO: make sure there are no duplicates
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList == 0)
|
||||
{
|
||||
string filename = PathUtil::Make(sLevelFolder, AUTO_LEVEL_RESOURCE_LIST);
|
||||
if (!pResList->Load(filename.c_str())) // If we saving resource list do not use auto_resourcelist.txt
|
||||
{
|
||||
// Try resource list created by the editor.
|
||||
filename = PathUtil::Make(sLevelFolder, LEVEL_RESOURCE_LIST);
|
||||
pResList->Load(filename.c_str());
|
||||
}
|
||||
}
|
||||
//LoadFastLoadPaks();
|
||||
|
||||
if (g_cvars.archiveVars.nStreamCache)
|
||||
{
|
||||
m_AsyncPakManager.ParseLayerPaks(GetCurrentLevelCacheFolder());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CResourceManager::LoadFastLoadPaks(bool bToMemory)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveFastloadResourceList != 0)
|
||||
{
|
||||
// Record a file list for _FastLoad/startup.pak
|
||||
m_recordedFiles.clear();
|
||||
gEnv->pCryPak->RegisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
// Load a special _fastload paks
|
||||
int nPakPreloadFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK;
|
||||
if (bToMemory && g_cvars.archiveVars.nLoadCache)
|
||||
{
|
||||
nPakPreloadFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY;
|
||||
}
|
||||
|
||||
const char* const assetsDir = "@assets@";
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_2
|
||||
#include AZ_RESTRICTED_FILE(ResourceManager_cpp)
|
||||
#endif
|
||||
|
||||
gEnv->pCryPak->OpenPacks(assetsDir, AZ::IO::PathString(FAST_LOADING_PAKS_SRC_FOLDER) + "*.pak", nPakPreloadFlags, &m_fastLoadPakPaths);
|
||||
gEnv->pCryPak->OpenPack(assetsDir, "Engine.pak", AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY);
|
||||
return !m_fastLoadPakPaths.empty();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadFastLoadPaks()
|
||||
{
|
||||
for (uint32 i = 0; i < m_fastLoadPakPaths.size(); i++)
|
||||
{
|
||||
// Unload a special _fastload paks
|
||||
gEnv->pCryPak->ClosePack(m_fastLoadPakPaths[i].c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL);
|
||||
}
|
||||
m_fastLoadPakPaths.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadLevel()
|
||||
{
|
||||
gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, NULL);
|
||||
|
||||
if (m_bRegisteredFileOpenSink)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveTotalResourceList)
|
||||
{
|
||||
SaveRecordedResources(true);
|
||||
m_recordedFiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
stl::free_container(m_sLevelFolder);
|
||||
stl::free_container(m_sLevelName);
|
||||
stl::free_container(m_currentLevelCacheFolder);
|
||||
|
||||
// should always be empty, since it is freed at the end of
|
||||
// the level loading process, if it is not
|
||||
// something went wrong and we have a levelheap leak
|
||||
assert(m_openedPaks.capacity() == 0);
|
||||
|
||||
m_pSequenceResourceList = NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZ::IO::IResourceList* CResourceManager::GetLevelResourceList()
|
||||
{
|
||||
auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level);
|
||||
return pResList;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CResourceManager::LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName;
|
||||
|
||||
pakPath.MakeLower();
|
||||
pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
|
||||
// Check if pak is already loaded
|
||||
for (int i = 0; i < (int)m_openedPaks.size(); i++)
|
||||
{
|
||||
if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// check pak file size.
|
||||
size_t nFileSize = gEnv->pCryPak->FGetSize(pakPath.c_str(), true);
|
||||
|
||||
if (nFileSize <= 0)
|
||||
{
|
||||
// Cached file does not exist
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Level cache pak file %s does not exist", pakPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
//set these flags as DLC LevelCache Paks are found via the mod paths,
|
||||
//and the paks can never be inside other paks so we optimise the search
|
||||
uint32 nOpenPakFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK;
|
||||
|
||||
if (nFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs.
|
||||
{
|
||||
if (!(nOpenPakFlags & AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY_CPU))
|
||||
{
|
||||
nOpenPakFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
SOpenedPak op;
|
||||
|
||||
if (gEnv->pCryPak->OpenPack(sBindRoot, { pakPath.c_str(), pakPath.size() }, nOpenPakFlags | AZ::IO::IArchive::FOPEN_HINT_QUIET, NULL, &op.filename))
|
||||
{
|
||||
op.bOnlyDuringLevelLoading = bOnlyDuringLevelLoading;
|
||||
m_openedPaks.push_back(op);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CResourceManager::LoadModeSwitchPak(const char* sPakName, const bool multiplayer)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList)
|
||||
{
|
||||
//Don't load the pak if we're trying to save a resourcelist in order to build it.
|
||||
m_recordedFiles.clear();
|
||||
gEnv->pCryPak->RegisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_cvars.archiveVars.nLoadModePaks)
|
||||
{
|
||||
// Unload SP common pak if switching to multiplayer
|
||||
if (multiplayer)
|
||||
{
|
||||
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
|
||||
}
|
||||
else
|
||||
{
|
||||
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP, FRONTEND_COMMON_LIST_FILENAME "_mp");
|
||||
}
|
||||
//Load the mode switching pak. If this is available and up to date it speeds up this process considerably
|
||||
bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0);
|
||||
bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
|
||||
return (bOpened && bLoaded);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink)
|
||||
{
|
||||
m_sLevelFolder = sResourceListName;
|
||||
SaveRecordedResources();
|
||||
gEnv->pCryPak->UnregisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_cvars.archiveVars.nLoadModePaks)
|
||||
{
|
||||
//Unload the mode switching pak.
|
||||
gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
|
||||
gEnv->pCryPak->ClosePack(sPakName, 0);
|
||||
//Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc, currently SP only
|
||||
if (!multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP);
|
||||
}
|
||||
else if (multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP) == false)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_MP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CResourceManager::LoadMenuCommonPak(const char* sPakName)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveMenuCommonResourceList)
|
||||
{
|
||||
//Don't load the pak if we're trying to save a resourcelist in order to build it.
|
||||
m_recordedFiles.clear();
|
||||
gEnv->pCryPak->RegisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Load the mode switching pak. If this is available and up to date it speeds up this process considerably
|
||||
bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0);
|
||||
bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
|
||||
return (bOpened && bLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadMenuCommonPak(const char* sPakName, const char* sResourceListName)
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveMenuCommonResourceList)
|
||||
{
|
||||
m_sLevelFolder = sResourceListName;
|
||||
SaveRecordedResources();
|
||||
gEnv->pCryPak->UnregisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Unload the mode switching pak.
|
||||
gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
|
||||
gEnv->pCryPak->ClosePack(sPakName, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadLevelCachePak(const char* sPakName)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName;
|
||||
pakPath.MakeLower();
|
||||
pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
|
||||
for (int i = 0; i < (int)m_openedPaks.size(); i++)
|
||||
{
|
||||
if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str()))
|
||||
{
|
||||
gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL);
|
||||
m_openedPaks.erase(m_openedPaks.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_openedPaks.empty())
|
||||
{
|
||||
stl::free_container(m_openedPaks);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::UnloadAllLevelCachePaks(bool bLevelLoadEnd)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
if (!bLevelLoadEnd)
|
||||
{
|
||||
m_AsyncPakManager.Clear();
|
||||
UnloadFastLoadPaks();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AsyncPakManager.UnloadLevelLoadPaks();
|
||||
}
|
||||
|
||||
uint32 nClosePakFlags = AZ::IO::IArchive::FLAGS_PATH_REAL; //AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL;
|
||||
|
||||
for (int i = 0; i < (int)m_openedPaks.size(); i++)
|
||||
{
|
||||
if ((m_openedPaks[i].bOnlyDuringLevelLoading && bLevelLoadEnd) ||
|
||||
!bLevelLoadEnd)
|
||||
{
|
||||
gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), nClosePakFlags);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cvars.archiveVars.nLoadCache)
|
||||
{
|
||||
gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
|
||||
|
||||
bool usePrefabSystemForLevels = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
|
||||
|
||||
if (!usePrefabSystemForLevels)
|
||||
{
|
||||
// Force level.pak out of memory.
|
||||
gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
|
||||
}
|
||||
}
|
||||
if (!bLevelLoadEnd)
|
||||
{
|
||||
stl::free_container(m_openedPaks);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CResourceManager::LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly)
|
||||
{
|
||||
return m_AsyncPakManager.LoadPakToMemAsync(pPath, bLevelLoadOnly);
|
||||
}
|
||||
|
||||
bool CResourceManager::LoadLayerPak(const char* sLayerName)
|
||||
{
|
||||
return m_AsyncPakManager.LoadLayerPak(sLayerName);
|
||||
}
|
||||
|
||||
void CResourceManager::UnloadLayerPak(const char* sLayerName)
|
||||
{
|
||||
m_AsyncPakManager.UnloadLayerPak(sLayerName);
|
||||
}
|
||||
|
||||
void CResourceManager::GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const
|
||||
{
|
||||
m_AsyncPakManager.GetLayerPakStats(stats, bCollectAllStats);
|
||||
}
|
||||
|
||||
void CResourceManager::UnloadAllAsyncPaks()
|
||||
{
|
||||
m_AsyncPakManager.Clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::Update()
|
||||
{
|
||||
m_AsyncPakManager.Update();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::Init()
|
||||
{
|
||||
GetISystem()->GetISystemEventDispatcher()->RegisterListener(this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::Shutdown()
|
||||
{
|
||||
UnloadAllLevelCachePaks(false);
|
||||
if (GetISystem() && GetISystem()->GetISystemEventDispatcher())
|
||||
{
|
||||
GetISystem()->GetISystemEventDispatcher()->RemoveListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CResourceManager::IsStreamingCachePak(const char* filename) const
|
||||
{
|
||||
const char* cachePaks[] = {
|
||||
"dds_cache.pak",
|
||||
"cgf_cache.pak",
|
||||
"skin_cache.pak",
|
||||
"chr_cache.pak"
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(cachePaks) / sizeof(cachePaks[0]); ++i)
|
||||
{
|
||||
if (strstr(filename, cachePaks[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESYSTEM_EVENT_FRONTEND_INITIALISED:
|
||||
{
|
||||
GetISystem()->GetStreamEngine()->PauseStreaming(false, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_GAME_POST_INIT_DONE:
|
||||
{
|
||||
if (g_cvars.archiveVars.nSaveFastloadResourceList != 0)
|
||||
{
|
||||
SaveRecordedResources();
|
||||
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList == 0 && g_cvars.archiveVars.nSaveTotalResourceList == 0)
|
||||
{
|
||||
m_recordedFiles.clear();
|
||||
}
|
||||
}
|
||||
// Unload all paks from memory, after game init.
|
||||
UnloadAllLevelCachePaks(false);
|
||||
gEnv->pCryPak->LoadPaksToMemory(0, false);
|
||||
|
||||
if (g_cvars.archiveVars.nLoadCache)
|
||||
{
|
||||
//Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc
|
||||
if (LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE:
|
||||
{
|
||||
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
|
||||
|
||||
m_bLevelTransitioning = !m_sLevelName.empty();
|
||||
|
||||
m_lastLevelLoadTime.SetValue(0);
|
||||
m_beginLevelLoadTime = gEnv->pTimer->GetAsyncTime();
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList || g_cvars.archiveVars.nSaveTotalResourceList)
|
||||
{
|
||||
if (!g_cvars.archiveVars.nSaveTotalResourceList)
|
||||
{
|
||||
m_recordedFiles.clear();
|
||||
}
|
||||
|
||||
if (!m_bRegisteredFileOpenSink)
|
||||
{
|
||||
gEnv->pCryPak->RegisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel any async pak loading, it will fight with the impending sync IO
|
||||
m_AsyncPakManager.CancelPendingJobs();
|
||||
|
||||
// Pause streaming engine for anything but sound, music, video and flash.
|
||||
uint32 nMask = (1 << eStreamTaskTypeFlash) | (1 << eStreamTaskTypeVideo) | STREAM_TASK_TYPE_AUDIO_ALL; // Unblock specified streams
|
||||
nMask = ~nMask; // Invert mask, bit set means blocking type.
|
||||
GetISystem()->GetStreamEngine()->PauseStreaming(true, nMask);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_LOAD_END:
|
||||
{
|
||||
if (m_bOwnResourceList)
|
||||
{
|
||||
m_bOwnResourceList = false;
|
||||
// Clear resource list, after level loading.
|
||||
auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level);
|
||||
if (pResList)
|
||||
{
|
||||
pResList->Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_UNLOAD:
|
||||
UnloadAllLevelCachePaks(false);
|
||||
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_PRECACHE_START:
|
||||
{
|
||||
// Unpause all streams in streaming engine.
|
||||
GetISystem()->GetStreamEngine()->PauseStreaming(false, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME:
|
||||
{
|
||||
UnloadAllLevelCachePaks(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESYSTEM_EVENT_LEVEL_PRECACHE_END:
|
||||
{
|
||||
CTimeValue t = gEnv->pTimer->GetAsyncTime();
|
||||
m_lastLevelLoadTime = t - m_beginLevelLoadTime;
|
||||
|
||||
if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink)
|
||||
{
|
||||
SaveRecordedResources();
|
||||
|
||||
if (!g_cvars.archiveVars.nSaveTotalResourceList)
|
||||
{
|
||||
gEnv->pCryPak->UnregisterFileAccessSink(this);
|
||||
m_bRegisteredFileOpenSink = false;
|
||||
}
|
||||
}
|
||||
|
||||
UnloadAllLevelCachePaks(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::GetMemoryStatistics(ICrySizer* pSizer)
|
||||
{
|
||||
pSizer->AddContainer(m_openedPaks);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::ReportFileOpen([[maybe_unused]] AZ::IO::HandleType inFileHandle, AZStd::string_view szFullPath)
|
||||
{
|
||||
if (!g_cvars.archiveVars.nSaveLevelResourceList && !g_cvars.archiveVars.nSaveFastloadResourceList && !g_cvars.archiveVars.nSaveMenuCommonResourceList && !g_cvars.archiveVars.nSaveTotalResourceList)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string file = PathUtil::MakeGamePath(string(szFullPath.data(), szFullPath.size()));
|
||||
file.replace('\\', '/');
|
||||
file.MakeLower();
|
||||
{
|
||||
CryAutoCriticalSection lock(recordedFilesLock);
|
||||
m_recordedFiles.push_back(file);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CResourceManager::SaveRecordedResources(bool bTotalList)
|
||||
{
|
||||
CryAutoCriticalSection lock(recordedFilesLock);
|
||||
|
||||
std::set<string> fileset;
|
||||
|
||||
// eliminate duplicate values
|
||||
std::vector<string>::iterator endLocation = std::unique(m_recordedFiles.begin(), m_recordedFiles.end());
|
||||
m_recordedFiles.erase(endLocation, m_recordedFiles.end());
|
||||
|
||||
fileset.insert(m_recordedFiles.begin(), m_recordedFiles.end());
|
||||
|
||||
string sSequenceFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST : AUTO_LEVEL_SEQUENCE_RESOURCE_LIST);
|
||||
{
|
||||
AZ::IO::HandleType fileHandle = fxopen(sSequenceFilename, "wb", true);
|
||||
if (fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
for (std::vector<string>::iterator it = m_recordedFiles.begin(); it != m_recordedFiles.end(); ++it)
|
||||
{
|
||||
const char* str = it->c_str();
|
||||
AZ::IO::Print(fileHandle, "%s\n", str);
|
||||
}
|
||||
gEnv->pFileIO->Close(fileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
string sResourceSetFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_RESOURCE_LIST : AUTO_LEVEL_RESOURCE_LIST);
|
||||
{
|
||||
AZ::IO::HandleType fileHandle = fxopen(sResourceSetFilename, "wb", true);
|
||||
if (fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
for (std::set<string>::iterator it = fileset.begin(); it != fileset.end(); ++it)
|
||||
{
|
||||
const char* str = it->c_str();
|
||||
AZ::IO::Print(fileHandle, "%s\n", str);
|
||||
}
|
||||
gEnv->pFileIO->Close(fileHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTimeValue CResourceManager::GetLastLevelLoadTime() const
|
||||
{
|
||||
return m_lastLevelLoadTime;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Interface to the Resource Manager
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <IResourceManager.h>
|
||||
#include "AsyncPakManager.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IResource manager interface
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CResourceManager
|
||||
: public IResourceManager
|
||||
, public ISystemEventListener
|
||||
, public AZ::IO::IArchiveFileAccessSink
|
||||
{
|
||||
public:
|
||||
CResourceManager();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
bool IsStreamingCachePak(const char* filename) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IResourceManager interface implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PrepareLevel(const char* sLevelFolder, const char* sLevelName);
|
||||
void UnloadLevel();
|
||||
AZ::IO::IResourceList* GetLevelResourceList();
|
||||
bool LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading);
|
||||
void UnloadLevelCachePak(const char* sPakName);
|
||||
bool LoadModeSwitchPak(const char* sPakName, const bool multiplayer);
|
||||
void UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer);
|
||||
bool LoadMenuCommonPak(const char* sPakName);
|
||||
void UnloadMenuCommonPak(const char* sPakName, const char* sResourceListName);
|
||||
bool LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly);
|
||||
void UnloadAllAsyncPaks();
|
||||
bool LoadLayerPak(const char* sLayerName);
|
||||
void UnloadLayerPak(const char* sLayerName);
|
||||
void UnloadAllLevelCachePaks(bool bLevelLoadEnd);
|
||||
void GetMemoryStatistics(ICrySizer* pSizer);
|
||||
bool LoadFastLoadPaks(bool bToMemory);
|
||||
void UnloadFastLoadPaks();
|
||||
CTimeValue GetLastLevelLoadTime() const;
|
||||
void GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ISystemEventListener interface implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IArchiveFileAccessSink interface implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void ReportFileOpen(AZ::IO::HandleType inFileHandle, AZStd::string_view szFullPath);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Per frame update of the resource manager.
|
||||
void Update();
|
||||
|
||||
CryPathString GetCurrentLevelCacheFolder() const { return m_currentLevelCacheFolder; };
|
||||
void SaveRecordedResources(bool bTotalList = false);
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CryPathString m_currentLevelCacheFolder;
|
||||
|
||||
struct SOpenedPak
|
||||
{
|
||||
AZStd::fixed_string<AZ::IO::IArchive::MaxPath> filename;
|
||||
bool bOnlyDuringLevelLoading;
|
||||
};
|
||||
std::vector<SOpenedPak> m_openedPaks;
|
||||
|
||||
CAsyncPakManager m_AsyncPakManager;
|
||||
|
||||
string m_sLevelFolder;
|
||||
string m_sLevelName;
|
||||
bool m_bLevelTransitioning;
|
||||
|
||||
bool m_bRegisteredFileOpenSink;
|
||||
bool m_bOwnResourceList;
|
||||
|
||||
CTimeValue m_beginLevelLoadTime;
|
||||
CTimeValue m_lastLevelLoadTime;
|
||||
|
||||
AZStd::intrusive_ptr<AZ::IO::IResourceList> m_pSequenceResourceList;
|
||||
|
||||
CryCriticalSection recordedFilesLock;
|
||||
std::vector<string> m_recordedFiles;
|
||||
|
||||
AZStd::vector< AZStd::fixed_string<AZ::IO::IArchive::MaxPath> > m_fastLoadPakPaths;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H
|
||||
@@ -1,410 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Engine
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include <ISystem.h>
|
||||
#include <ILog.h>
|
||||
|
||||
#include "AZRequestReadStream.h"
|
||||
#include <AzCore/std/parallel/semaphore.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include "StreamEngine.h"
|
||||
|
||||
AZRequestReadStream* AZRequestReadStream::Allocate(const EStreamTaskType tSource, const char* filename, IStreamCallback* callback,
|
||||
const StreamReadParams* params)
|
||||
{
|
||||
//Once an async method is available to read file sizes this code should be removed:
|
||||
// and the file size should be known before calling this method and pass it as a
|
||||
// parameter to this method.
|
||||
//REMOVE In the Future START.
|
||||
AZ::IO::SizeType fileSize = 0;
|
||||
if (params && params->nSize)
|
||||
{
|
||||
fileSize = params->nSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ::IO::Result res = fileIO->Size(filename, fileSize);
|
||||
if (!res)
|
||||
{
|
||||
AZ_Error("AZRequestReadStream", false, "Failed to read file size of %s", filename);
|
||||
return nullptr;
|
||||
}
|
||||
//REMOVE In the Future END.
|
||||
}
|
||||
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
|
||||
AZRequestReadStream* retReq;
|
||||
retReq = aznew AZRequestReadStream();
|
||||
|
||||
retReq->m_Type = tSource;
|
||||
retReq->m_fileName = filename;
|
||||
retReq->m_callback = callback;
|
||||
retReq->m_fileSize = fileSize;
|
||||
//REMARK: if params->pBuffer is NOT NULL, then retReq->m_buffer
|
||||
//should become params->pBuffer, this is called stream-in-place.
|
||||
//The only reason we are not doing this here is because
|
||||
//some platforms support stream-in-place to WRITE ONLY buffers.
|
||||
//Because there are no guarantees that low level streaming and decompression apis
|
||||
//would treat the output buffer as WRITE ONLY, we still allocate the buffer and memcpy
|
||||
//to params->pBuffer upon the completion callback being called.
|
||||
//Once LY-98089 is complete/fixed, we should be able to safely
|
||||
//set retReq->m_buffer = params->pBuffer and skip the memory allocation.
|
||||
retReq->m_buffer = azmalloc(fileSize, streamer->GetRecommendations().m_memoryAlignment);
|
||||
if (params)
|
||||
{
|
||||
retReq->m_params = *params;
|
||||
}
|
||||
|
||||
return retReq;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZRequestReadStream::AZRequestReadStream() : m_fileName(""), m_fileRequest(nullptr),
|
||||
m_buffer(nullptr), m_Type(eStreamTaskTypeTexture),
|
||||
m_callback(nullptr), m_fileSize(0), m_numBytesRead(0), m_isAsyncCallbackExecuted(false),
|
||||
m_isSyncCallbackExecuted(false), m_isFileRequestComplete(false), m_isError(false), m_isFinished(false),
|
||||
m_IOError(0)
|
||||
{
|
||||
AZStd::atomic_init<int>(&m_refCount, 0);
|
||||
m_params = StreamReadParams();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZRequestReadStream::~AZRequestReadStream()
|
||||
{
|
||||
azfree(m_buffer);
|
||||
}
|
||||
|
||||
// tries to stop reading the stream; this is advisory and may have no effect
|
||||
// all the callbacks will be called after this. If you just destructing object,
|
||||
// dereference this object and it will automatically abort and release all associated resources.
|
||||
void AZRequestReadStream::Abort()
|
||||
{
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
// Increase ref counting to avoid preliminary destruction
|
||||
AZRequestReadStream_AutoPtr refCountLock(this);
|
||||
|
||||
if (m_isFileRequestComplete || m_isError)
|
||||
{
|
||||
// It is possible the file I/O request to be completed by AZ::IO::Streamer,
|
||||
// but if the completion callback is deferred for the main thread then
|
||||
// the stream is not finished. So, only if it is finished then
|
||||
// it is safe to do nothing.
|
||||
if (m_isFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_isError = true;
|
||||
m_IOError = ERROR_USER_ABORT;
|
||||
m_isFileRequestComplete = true;
|
||||
m_numBytesRead = 0;
|
||||
|
||||
if (m_fileRequest)
|
||||
{
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
streamer->QueueRequest(streamer->Cancel(m_fileRequest));
|
||||
}
|
||||
|
||||
// all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
|
||||
m_callback = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AZRequestReadStream::TryAbort()
|
||||
{
|
||||
// Increase ref counting to avoid preliminary destruction
|
||||
AZRequestReadStream_AutoPtr refCountLock(this);
|
||||
|
||||
if (!m_callbackLock.TryLock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_isFileRequestComplete || m_isError)
|
||||
{
|
||||
// It is possible the file I/O request to be completed by AZ::IO::Streamer,
|
||||
// but if the completion callback is deferred for the main thread then
|
||||
// the stream is not finished. So, only if it is finished then
|
||||
// it is safe to do nothing.
|
||||
if (m_isFinished)
|
||||
{
|
||||
m_callbackLock.Unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_isError = true;
|
||||
m_IOError = ERROR_USER_ABORT;
|
||||
m_isFileRequestComplete = true;
|
||||
m_numBytesRead = 0;
|
||||
|
||||
if (m_fileRequest)
|
||||
{
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
streamer->QueueRequest(streamer->Cancel(m_fileRequest));
|
||||
}
|
||||
|
||||
// all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
|
||||
m_callback = nullptr;
|
||||
|
||||
m_callbackLock.Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// tries to raise the priority of the read; this is advisory and may have no effect
|
||||
void AZRequestReadStream::SetPriority(EStreamTaskPriority ePriority)
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
if (m_params.ePriority != ePriority)
|
||||
{
|
||||
m_params.ePriority = ePriority;
|
||||
if (m_fileRequest)
|
||||
{
|
||||
AZ::Interface<AZ::IO::IStreamer>::Get()->RescheduleRequest(m_fileRequest, AZ::IO::IStreamerTypes::s_noDeadline,
|
||||
CStreamEngine::CryStreamPriorityToAZStreamPriority(ePriority));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unconditionally waits until the callback is called
|
||||
// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback
|
||||
// is called before return from this function (unless no callback was specified)
|
||||
void AZRequestReadStream::Wait(int maxWaitMillis)
|
||||
{
|
||||
// lock this object to avoid preliminary destruction
|
||||
AZRequestReadStream_AutoPtr refCountLock(this);
|
||||
|
||||
if (!m_isFinished && !m_isError && !m_fileRequest)
|
||||
{
|
||||
AZ_Error("AZRequestReadStream", false, "Stream for file %s is unwaitable", m_fileName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxWaitMillis > 0)
|
||||
{
|
||||
m_wait.try_acquire_for(AZStd::chrono::milliseconds(maxWaitMillis));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_wait.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char* AZRequestReadStream::GetErrorName() const
|
||||
{
|
||||
switch (m_IOError)
|
||||
{
|
||||
case ERROR_UNKNOWN_ERROR:
|
||||
return "Unknown error";
|
||||
case ERROR_UNEXPECTED_DESTRUCTION:
|
||||
return "Unexpected destruction";
|
||||
case ERROR_INVALID_CALL:
|
||||
return "Invalid call";
|
||||
case ERROR_CANT_OPEN_FILE:
|
||||
return "Cannot open the file";
|
||||
case ERROR_REFSTREAM_ERROR:
|
||||
return "Refstream error";
|
||||
case ERROR_OFFSET_OUT_OF_RANGE:
|
||||
return "Offset out of range";
|
||||
case ERROR_REGION_OUT_OF_RANGE:
|
||||
return "Region out of range";
|
||||
case ERROR_SIZE_OUT_OF_RANGE:
|
||||
return "Size out of range";
|
||||
case ERROR_CANT_START_READING:
|
||||
return "Cannot start reading";
|
||||
case ERROR_OUT_OF_MEMORY:
|
||||
return "Out of memory";
|
||||
case ERROR_ABORTED_ON_SHUTDOWN:
|
||||
return "Aborted on shutdown";
|
||||
case ERROR_OUT_OF_MEMORY_QUOTA:
|
||||
return "Out of memory quota";
|
||||
case ERROR_ZIP_CACHE_FAILURE:
|
||||
return "ZIP cache failure";
|
||||
case ERROR_USER_ABORT:
|
||||
return "User aborted";
|
||||
}
|
||||
return "Unrecognized error";
|
||||
}
|
||||
|
||||
int AZRequestReadStream::AddRef()
|
||||
{
|
||||
return m_refCount.fetch_add(1) + 1;
|
||||
}
|
||||
|
||||
int AZRequestReadStream::Release()
|
||||
{
|
||||
int refCount = m_refCount.fetch_sub(1);
|
||||
|
||||
#ifndef _RELEASE
|
||||
if (refCount < 1)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (refCount == 1)
|
||||
{
|
||||
//UNUSUAL, yet necessary.
|
||||
//Why "delete this"?
|
||||
//So, AZRequestReadStream is a replacement of CReadStream. The original design of
|
||||
//Cry Texture Mips Streaming makes use of CReadStream through IReadStreamPtr, which
|
||||
//is a smart pointer design that calls AddRef() and Release() but never calls "delete",
|
||||
//like AZStd::shared_ptr<> does. This means the original Cry design had a memory leak
|
||||
//because it never called delete on IReadStream objects. If you look at the original
|
||||
//code of CReadStream (StreamReadStream.cpp) , the static Allocate method has two paths
|
||||
//to allocate memory, one used a stack based memory allocation hack, and the other path
|
||||
//was doing a "new CReadStream". Using VS2017 debugger I found both paths to be used, but
|
||||
//"delete" and hence the destructor of CReadStream is never called causing minor memory leaks.
|
||||
//The best solution I found was to call "delete this" here and later when we chnage IReadStreamPtr
|
||||
//for AZstd::smart_ptr then AddRef() and Release() won't be needed anymore and this "delete this"
|
||||
//hack won't be necessary either.
|
||||
delete this;
|
||||
}
|
||||
|
||||
return refCount - 1;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void AZRequestReadStream::ExecuteAsyncCallback_CBLocked()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
if (!m_isAsyncCallbackExecuted && m_callback)
|
||||
{
|
||||
m_isAsyncCallbackExecuted = true;
|
||||
m_callback->StreamAsyncOnComplete(this, m_IOError);
|
||||
}
|
||||
}
|
||||
|
||||
void AZRequestReadStream::ExecuteSyncCallback_CBLocked()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
if (!m_isSyncCallbackExecuted && m_callback && (0 == (m_params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK)))
|
||||
{
|
||||
m_isSyncCallbackExecuted = true;
|
||||
|
||||
AZRequestReadStream_AutoPtr refCountLock(this); // Stream can be freed inside the callback!
|
||||
|
||||
m_callback->StreamOnComplete(this, m_IOError);
|
||||
|
||||
m_isFinished = true;
|
||||
FreeTemporaryMemory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void AZRequestReadStream::FreeTemporaryMemory()
|
||||
{
|
||||
// Make sure m_buffer is not freed if the file request is still in flight, as Streamer can still write to m_buffer in that case
|
||||
if (!m_fileRequest || AZ::Interface<AZ::IO::IStreamer>::Get()->HasRequestCompleted(m_fileRequest))
|
||||
{
|
||||
azfree(m_buffer);
|
||||
m_buffer = nullptr;
|
||||
m_numBytesRead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void AZRequestReadStream::OnRequestComplete(AZ::IO::SizeType numBytesRead, [[maybe_unused]] void* buffer, AZ::IO::IStreamerTypes::RequestStatus requestState)
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
if (!m_isFileRequestComplete)
|
||||
{
|
||||
switch (requestState)
|
||||
{
|
||||
case AZ::IO::IStreamerTypes::RequestStatus::Completed:
|
||||
m_IOError = 0;
|
||||
m_numBytesRead = static_cast<uint32>(numBytesRead);
|
||||
m_isError = false;
|
||||
if (m_params.pBuffer)
|
||||
{
|
||||
//In some systems, streaming-in-place is supported. The caveat
|
||||
//is that in some cases, the destination buffer is write-only. This is why
|
||||
//a final memcpy must be done here until support is added to AZ::IO::Streamer API
|
||||
//to decompress/load data into write-only buffers. SEE: LY-98089
|
||||
AZ_Assert(m_params.pBuffer != m_buffer, "Streaming-In-Place requires destination and source buffers to be different");
|
||||
memcpy(m_params.pBuffer, m_buffer, numBytesRead);
|
||||
}
|
||||
break;
|
||||
case AZ::IO::IStreamerTypes::RequestStatus::Canceled:
|
||||
m_IOError = ERROR_USER_ABORT;
|
||||
m_numBytesRead = 0;
|
||||
m_isError = true;
|
||||
break;
|
||||
default:
|
||||
m_IOError = ERROR_UNKNOWN_ERROR;
|
||||
m_numBytesRead = 0;
|
||||
m_isError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
m_isFileRequestComplete = true;
|
||||
|
||||
if (m_params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK)
|
||||
{
|
||||
// We do not need FileRequest here anymore, and not its temporary memory.
|
||||
m_fileRequest = nullptr;
|
||||
m_isFinished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//The completion must be triggered from MainThread. (Typically only happens when loading Terrain Macro Textures
|
||||
AddRef();
|
||||
AZ::SystemTickBus::QueueFunction([this] {
|
||||
RequestCompleteOnMainThread();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
m_wait.release();
|
||||
}
|
||||
|
||||
|
||||
void AZRequestReadStream::RequestCompleteOnMainThread()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
// call asynchronous callback function if needed synchronously
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
}
|
||||
|
||||
//Always called because before enqueuing this call was called AddRef()
|
||||
Release();
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
// Description : An IReadStream implementation designed to work with AZ::IO::Streamer
|
||||
// instead of CStreamEngine.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/parallel/semaphore.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include "IStreamEngine.h"
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
class Request;
|
||||
}
|
||||
}
|
||||
|
||||
//This class is a wrapper of AZ::IO::Request so Cry Classes can use AZ::IO::Streamer.
|
||||
//Basicallythis replaces CReadStream.
|
||||
class AZRequestReadStream
|
||||
: public IReadStream
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AZRequestReadStream, AZ::SystemAllocator, 0);
|
||||
|
||||
static AZRequestReadStream* Allocate(const EStreamTaskType tSource, const char* filename, IStreamCallback* callback,
|
||||
const StreamReadParams* params);
|
||||
|
||||
int AddRef() override;
|
||||
int Release() override;
|
||||
|
||||
DWORD_PTR GetUserData() override {return m_params.dwUserData; }
|
||||
|
||||
// set user defined data into stream's params
|
||||
void SetUserData(DWORD_PTR userData) override { m_params.dwUserData = userData; };
|
||||
|
||||
// returns true if the file read was not successful.
|
||||
bool IsError() override { return m_isError; };
|
||||
|
||||
// returns true if the file read was completed (successfully or unsuccessfully)
|
||||
// check IsError to check if the whole requested file (piece) was read
|
||||
bool IsFinished() override { return m_isFinished; };
|
||||
|
||||
// returns the number of bytes read so far (the whole buffer size if IsFinished())
|
||||
unsigned int GetBytesRead([[maybe_unused]] bool bWait) override { return static_cast<unsigned int>(m_numBytesRead); };
|
||||
|
||||
// returns the buffer into which the data has been or will be read
|
||||
// at least GetBytesRead() bytes in this buffer are guaranteed to be already read
|
||||
const void* GetBuffer() override { return m_buffer; };
|
||||
|
||||
// tries to stop reading the stream; this is advisory and may have no effect
|
||||
// but the callback will not be called after this. If you just destructing object,
|
||||
// dereference this object and it will automatically abort and release all associated resources.
|
||||
void Abort() override;
|
||||
bool TryAbort() override;
|
||||
|
||||
|
||||
|
||||
// unconditionally waits until the callback is called
|
||||
// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback
|
||||
// is called before return from this function (unless no callback was specified)
|
||||
void Wait(int maxWaitMillis = -1) override;
|
||||
|
||||
const StreamReadParams& GetParams() const override {return m_params; }
|
||||
|
||||
const EStreamTaskType GetCallerType() const override { return m_Type; }
|
||||
|
||||
//We must define this one. But it is never used in the context of AZ::IO::Streamer.
|
||||
//Legacy Cry StreamEngine stuff.
|
||||
EStreamSourceMediaType GetMediaType() const override { return EStreamSourceMediaType::eStreamSourceTypeUnknown; }
|
||||
|
||||
// return pointer to callback routine(can be NULL)
|
||||
IStreamCallback* GetCallback() const override { return m_callback; };
|
||||
|
||||
// return IO error #
|
||||
unsigned GetError() const override { return m_IOError; };
|
||||
|
||||
// Returns IO error name
|
||||
const char* GetErrorName() const override;
|
||||
|
||||
// return stream name
|
||||
const char* GetName() const override { return m_fileName.c_str(); };
|
||||
|
||||
void FreeTemporaryMemory() override;
|
||||
|
||||
// tries to raise the priority of the read; this is advisory and may have no effect
|
||||
void SetPriority(EStreamTaskPriority EPriority);
|
||||
uint64 GetPriority() const { return m_params.ePriority; };
|
||||
|
||||
void* GetFileReadBuffer() { return m_buffer; } //GetBuffer from IReadStream is "const void *"
|
||||
AZStd::size_t GetFileSize() { return m_fileSize; }
|
||||
|
||||
void SetFileRequest(AZ::IO::FileRequestPtr request) { m_fileRequest = AZStd::move(request); }
|
||||
AZ::IO::FileRequestPtr GetFileRequest() { return m_fileRequest; }
|
||||
|
||||
void OnRequestComplete(AZ::IO::SizeType numBytesRead, void* buffer, AZ::IO::IStreamerTypes::RequestStatus requestState);
|
||||
|
||||
private:
|
||||
AZRequestReadStream();
|
||||
virtual ~AZRequestReadStream();
|
||||
|
||||
// call the async callback
|
||||
void ExecuteAsyncCallback_CBLocked();
|
||||
void ExecuteSyncCallback_CBLocked();
|
||||
void RequestCompleteOnMainThread();
|
||||
|
||||
AZStd::atomic_int m_refCount;
|
||||
|
||||
CryCriticalSection m_callbackLock;
|
||||
StreamReadParams m_params;
|
||||
AZStd::semaphore m_wait;
|
||||
|
||||
CryStringLocal m_fileName;
|
||||
AZ::IO::FileRequestPtr m_fileRequest;
|
||||
|
||||
// Bytes actually read from media.
|
||||
void* m_buffer;
|
||||
|
||||
// the type of the task
|
||||
EStreamTaskType m_Type;
|
||||
// the initial data from the user
|
||||
// the callback; may be NULL
|
||||
IStreamCallback* m_callback;
|
||||
|
||||
AZ::IO::SizeType m_fileSize; //Expected number of bytes to be read.
|
||||
AZ::IO::SizeType m_numBytesRead; //On a successful read m_nBytesRead == m_fileSize;
|
||||
|
||||
bool m_isAsyncCallbackExecuted;
|
||||
bool m_isSyncCallbackExecuted;
|
||||
bool m_isFileRequestComplete;
|
||||
|
||||
bool m_isError;
|
||||
bool m_isFinished;
|
||||
unsigned int m_IOError;
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(AZRequestReadStream);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,571 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Thread for IO
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H
|
||||
#pragma once
|
||||
|
||||
#include <IStreamEngineDefs.h>
|
||||
#include <AzCore/Jobs/LegacyJobExecutor.h>
|
||||
#include "TimeValue.h"
|
||||
|
||||
#define STREAMENGINE_LL_ALIGN _MS_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)
|
||||
|
||||
class CStreamEngine;
|
||||
class CAsyncIOFileRequest;
|
||||
struct z_stream_s;
|
||||
class CStreamingIOThread;
|
||||
namespace AZ::IO
|
||||
{
|
||||
struct CCachedFileData;
|
||||
}
|
||||
class CCryFile;
|
||||
struct SStreamJobEngineState;
|
||||
class CMTSafeHeap;
|
||||
class CAsyncIOFileRequest_TransferPtr;
|
||||
struct SStreamEngineTempMemStats;
|
||||
|
||||
#if !defined(USE_EDGE_ZLIB)
|
||||
// Prevent compilation conflicts - zconf.h (included by zlib.h) defines WINDOWS and WIN32 - those
|
||||
// definitions conflict with CryEngine's definitions.
|
||||
|
||||
# if defined(CRY_TMP_DEFINED_WINDOWS) || defined(CRY_TMP_DEFINED_WIN32)
|
||||
# error CRY_TMP_DEFINED_WINDOWS and/or CRY_TMP_DEFINED_WIN32 already defined
|
||||
# endif
|
||||
|
||||
# if defined(WINDOWS)
|
||||
# define CRY_TMP_DEFINED_WINDOWS 1
|
||||
# endif
|
||||
# if defined(WIN32)
|
||||
# define CRY_TMP_DEFINED_WIN32 1
|
||||
# endif
|
||||
|
||||
# include <zlib.h>
|
||||
|
||||
# if !defined(CRY_TMP_DEFINED_WINDOWS)
|
||||
# undef WINDOWS
|
||||
#endif
|
||||
# undef CRY_TMP_DEFINED_WINDOWS
|
||||
# if !defined(CRY_TMP_DEFINED_WIN32)
|
||||
# undef WIN32
|
||||
# endif
|
||||
# undef CRY_TMP_DEFINED_WIN32
|
||||
|
||||
// Undefine macros defined in zutil.h to prevent compilation errors in 'steamclientpublic.h', 'OVR_Math.h' etc.
|
||||
# undef Assert
|
||||
# undef Trace
|
||||
# undef Tracev
|
||||
# undef Tracevv
|
||||
# undef Tracec
|
||||
# undef Tracecv
|
||||
|
||||
#endif // !defined(USE_EDGE_ZLIB)
|
||||
|
||||
namespace AZ::IO::ZipDir {
|
||||
struct UncompressLookahead;
|
||||
}
|
||||
|
||||
struct IAsyncIOFileCallback
|
||||
{
|
||||
virtual ~IAsyncIOFileCallback(){}
|
||||
// Asynchronous finished event.
|
||||
// Must be thread safe, can be called from a different thread.
|
||||
virtual void OnAsyncFinished(CAsyncIOFileRequest* pFileRequest) = 0;
|
||||
};
|
||||
|
||||
struct SStreamPageHdr
|
||||
{
|
||||
explicit SStreamPageHdr(int size)
|
||||
: nRefs()
|
||||
, nSize(size)
|
||||
{}
|
||||
|
||||
volatile int nRefs;
|
||||
int nSize;
|
||||
};
|
||||
|
||||
struct SStreamJobQueue
|
||||
{
|
||||
enum
|
||||
{
|
||||
MaxJobs = 256,
|
||||
};
|
||||
|
||||
struct Job
|
||||
{
|
||||
void* pSrc;
|
||||
SStreamPageHdr* pSrcHdr;
|
||||
uint32 nOffs;
|
||||
uint32 nBytes : 31;
|
||||
uint32 bLast : 1;
|
||||
};
|
||||
|
||||
SStreamJobQueue()
|
||||
: m_sema(MaxJobs, MaxJobs)
|
||||
{
|
||||
m_nQueueLen = 0;
|
||||
m_nPush = 0;
|
||||
m_nPop = 0;
|
||||
memset(m_jobs, 0, sizeof(m_jobs));
|
||||
}
|
||||
|
||||
void Flush(SStreamEngineTempMemStats& tms);
|
||||
|
||||
int Push(void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast);
|
||||
int Pop();
|
||||
|
||||
CryFastSemaphore m_sema;
|
||||
Job m_jobs[MaxJobs];
|
||||
volatile int m_nQueueLen;
|
||||
volatile int m_nPush;
|
||||
volatile int m_nPop;
|
||||
};
|
||||
|
||||
// This class represent a request to read some file from disk asynchronously via one of the IO threads.
|
||||
class CAsyncIOFileRequest
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
eStatusNotReady,
|
||||
eStatusInFileQueue,
|
||||
eStatusFailed,
|
||||
eStatusUnzipComplete,
|
||||
eStatusDone,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BUFFER_ALIGNMENT = 128,
|
||||
WINDOW_SIZE = 1 << 15,
|
||||
|
||||
#if defined(ANDROID)
|
||||
STREAMING_PAGE_SIZE = (128 * 1024),
|
||||
#else
|
||||
STREAMING_PAGE_SIZE = (1 * 1024 * 1024),
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
STREAMING_BLOCK_SIZE = (64 * 1024),
|
||||
#else
|
||||
STREAMING_BLOCK_SIZE = (32 * 1024),
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
static CAsyncIOFileRequest* Allocate(EStreamTaskType eType);
|
||||
static void Flush();
|
||||
|
||||
public:
|
||||
void AddRef();
|
||||
int Release();
|
||||
|
||||
public:
|
||||
void Init(EStreamTaskType eType);
|
||||
void Finalize();
|
||||
|
||||
void Reset();
|
||||
|
||||
ILINE bool IsCancelled() const { return m_nError == ERROR_USER_ABORT; }
|
||||
ILINE bool HasFailed() const { return m_nError != 0; }
|
||||
void Failed(uint32 nError)
|
||||
{
|
||||
CryInterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&m_nError), nError, 0);
|
||||
}
|
||||
|
||||
uint32 OpenFile(CCryFile& file);
|
||||
|
||||
uint32 ReadFile(CStreamingIOThread* pIOThread);
|
||||
uint32 ReadFileResume(CStreamingIOThread* pIOThread);
|
||||
uint32 ReadFileInPages(CStreamingIOThread* pIOThread, CCryFile& file);
|
||||
uint32 ReadFileCheckPreempt(CStreamingIOThread* pIOThread);
|
||||
|
||||
uint32 ConfigureRead(AZ::IO::CCachedFileData* pFileData);
|
||||
bool CanReadInPages();
|
||||
uint32 AllocateOutput(AZ::IO::CCachedFileData* pZipEntry);
|
||||
unsigned char* AllocatePage(size_t sz, bool bOnlyPakMem, SStreamPageHdr*& pHdrOut);
|
||||
|
||||
static void JobFinalize_Read(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState);
|
||||
|
||||
uint32 PushDecompressPage(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nBytes, bool bLast);
|
||||
uint32 PushDecompressBlock(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast);
|
||||
static void JobStart_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState, int nSlot);
|
||||
void DecompressBlockEntry(SStreamJobEngineState engineState, int nJob);
|
||||
|
||||
void Cancel();
|
||||
bool TryCancel();
|
||||
void SyncWithDecompress();
|
||||
void ComputeSortKey(uint64 nCurrentKeyInProgress);
|
||||
void SetPriority(EStreamTaskPriority estp);
|
||||
void BumpSweep();
|
||||
void FreeBuffer();
|
||||
|
||||
bool IgnoreOutofTmpMem() const;
|
||||
|
||||
CStreamEngine* GetStreamEngine();
|
||||
|
||||
EStreamSourceMediaType GetMediaType();
|
||||
|
||||
private:
|
||||
void* operator new (size_t sz);
|
||||
void operator delete(void* p);
|
||||
|
||||
private:
|
||||
static void JobFinalize_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState);
|
||||
static void JobFinalize_Transfer(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState);
|
||||
|
||||
private:
|
||||
void JobFinalize_Buffer(const SStreamJobEngineState& engineState);
|
||||
void JobFinalize_Validate(const SStreamJobEngineState& engineState);
|
||||
|
||||
private:
|
||||
CAsyncIOFileRequest();
|
||||
~CAsyncIOFileRequest();
|
||||
|
||||
public:
|
||||
static volatile int s_nLiveRequests;
|
||||
static SLockFreeSingleLinkedListHeader s_freeRequests;
|
||||
|
||||
public:
|
||||
// Must be first
|
||||
STREAMENGINE_LL_ALIGN SLockFreeSingleLinkedListEntry m_nextFree;
|
||||
|
||||
volatile int m_nRefCount;
|
||||
|
||||
// Locks to be held whilst the file is being read, and an external memory buffer is in use
|
||||
// (to ensure that if cancelled, the stream engine doesn't write to the external buffer)
|
||||
// Separate locks for read and decomp as they can overlap (block decompress)
|
||||
// Cancel() must acquire both
|
||||
CryCriticalSection m_externalBufferLockRead;
|
||||
CryCriticalSection m_externalBufferLockDecompress;
|
||||
|
||||
CryStringLocal m_strFileName;
|
||||
string m_pakFile;
|
||||
|
||||
// If request come from stream, it will be not 0.
|
||||
IReadStreamPtr m_pReadStream;
|
||||
|
||||
AZStd::unique_ptr<AZ::LegacyJobExecutor> m_decompJobExecutor;
|
||||
|
||||
// Only POD data should exist beyond this point - will be memsetted to 0 on Reset !
|
||||
|
||||
uint64 m_nSortKey;
|
||||
|
||||
EStreamTaskPriority m_ePriority;
|
||||
EStreamSourceMediaType m_eMediaType;
|
||||
EStreamTaskType m_eType;
|
||||
|
||||
volatile EStatus m_status;
|
||||
volatile uint32 m_nError;
|
||||
|
||||
uint32 m_nRequestedOffset;
|
||||
uint32 m_nRequestedSize;
|
||||
|
||||
// the file size, or 0 if the file couldn't be opened
|
||||
uint32 m_nFileSize;
|
||||
uint32 m_nFileSizeCompressed;
|
||||
|
||||
void* m_pMemoryBuffer;
|
||||
uint32 m_nMemoryBufferSize;
|
||||
volatile int m_nMemoryBufferUsers;
|
||||
|
||||
void* m_pExternalMemoryBuffer;
|
||||
void* m_pOutputMemoryBuffer;
|
||||
void* m_pReadMemoryBuffer;
|
||||
uint32 m_nReadMemoryBufferSize;
|
||||
|
||||
uint32 m_bCompressedBuffer : 1;
|
||||
uint32 m_bStatsUpdated : 1;
|
||||
uint32 m_bStreamInPlace : 1;
|
||||
uint32 m_bWriteOnlyExternal : 1;
|
||||
uint32 m_bSortKeyComputed : 1;
|
||||
uint32 m_bOutputAllocated : 1;
|
||||
uint32 m_bReadBegun : 1;
|
||||
|
||||
// Actual size of the data on the media.
|
||||
uint32 m_nSizeOnMedia;
|
||||
|
||||
int64 m_nDiskOffset;
|
||||
int32 m_nReadHeadOffsetKB; // Offset of the Read Head when reading from media.
|
||||
int32 m_nTimeGroup;
|
||||
int32 m_nSweep;
|
||||
|
||||
IAsyncIOFileCallback* m_pCallback;
|
||||
|
||||
//
|
||||
// Block based streaming
|
||||
//
|
||||
|
||||
uint32 m_nPageReadStart;
|
||||
uint32 m_nPageReadCurrent;
|
||||
uint32 m_nPageReadEnd;
|
||||
|
||||
volatile uint32 m_nBytesDecompressed;
|
||||
|
||||
uint32 m_crc32FromHeader;
|
||||
|
||||
volatile LONG m_nFinalised;
|
||||
|
||||
z_stream_s* m_pZlibStream;
|
||||
AZ::IO::ZipDir::UncompressLookahead* m_pLookahead;
|
||||
SStreamJobQueue* m_pDecompQueue;
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
// Time that read operation took.
|
||||
CTimeValue m_readTime;
|
||||
CTimeValue m_unzipTime;
|
||||
CTimeValue m_verifyTime;
|
||||
CTimeValue m_startTime;
|
||||
CTimeValue m_completionTime;
|
||||
|
||||
uint32 m_nReadCounter;
|
||||
#endif
|
||||
};
|
||||
TYPEDEF_AUTOPTR(CAsyncIOFileRequest);
|
||||
|
||||
struct SStreamRequestQueue
|
||||
{
|
||||
CryCriticalSection m_lock;
|
||||
std::vector<CAsyncIOFileRequest*> m_requests;
|
||||
|
||||
CryEvent m_awakeEvent;
|
||||
|
||||
SStreamRequestQueue();
|
||||
~SStreamRequestQueue();
|
||||
|
||||
void Reset();
|
||||
bool IsEmpty() const;
|
||||
|
||||
// Transfers ownership (rather than shares ownership) to the queue
|
||||
void TransferRequest(CAsyncIOFileRequest_TransferPtr& pReq);
|
||||
bool TryPopRequest(CAsyncIOFileRequest_AutoPtr& pOut);
|
||||
|
||||
private:
|
||||
SStreamRequestQueue(const SStreamRequestQueue&);
|
||||
SStreamRequestQueue& operator = (const SStreamRequestQueue&);
|
||||
};
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
struct SStreamEngineDecompressStats
|
||||
{
|
||||
uint64 m_nTotalBytesUnziped;
|
||||
uint64 m_nTempBytesUnziped;
|
||||
uint64 m_nTotalBytesVerified;
|
||||
uint64 m_nTempBytesVerified;
|
||||
|
||||
CTimeValue m_totalUnzipTime;
|
||||
CTimeValue m_tempUnzipTime;
|
||||
CTimeValue m_totalVerifyTime;
|
||||
CTimeValue m_tempVerifyTime;
|
||||
};
|
||||
#endif
|
||||
|
||||
class CAsyncIOFileRequest_TransferPtr
|
||||
{
|
||||
public:
|
||||
explicit CAsyncIOFileRequest_TransferPtr(CAsyncIOFileRequest* p)
|
||||
: m_p(p)
|
||||
{
|
||||
}
|
||||
|
||||
~CAsyncIOFileRequest_TransferPtr()
|
||||
{
|
||||
if (m_p)
|
||||
{
|
||||
m_p->Release();
|
||||
}
|
||||
}
|
||||
|
||||
CAsyncIOFileRequest* operator -> () { return m_p; }
|
||||
CAsyncIOFileRequest& operator * () { return *m_p; }
|
||||
|
||||
const CAsyncIOFileRequest* operator -> () const { return m_p; }
|
||||
const CAsyncIOFileRequest& operator * () const { return *m_p; }
|
||||
|
||||
operator bool () const {
|
||||
return m_p != NULL;
|
||||
}
|
||||
|
||||
CAsyncIOFileRequest* Relinquish()
|
||||
{
|
||||
CAsyncIOFileRequest* p = m_p;
|
||||
m_p = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
CAsyncIOFileRequest_TransferPtr& operator = (CAsyncIOFileRequest* p)
|
||||
{
|
||||
#ifndef _RELEASE
|
||||
if (m_p)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
m_p = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
CAsyncIOFileRequest_TransferPtr(const CAsyncIOFileRequest_TransferPtr&);
|
||||
CAsyncIOFileRequest_TransferPtr& operator = (const CAsyncIOFileRequest_TransferPtr&);
|
||||
|
||||
private:
|
||||
CAsyncIOFileRequest* m_p;
|
||||
};
|
||||
|
||||
class CStreamEngineWakeEvent
|
||||
{
|
||||
public:
|
||||
CStreamEngineWakeEvent()
|
||||
: m_state(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Set()
|
||||
{
|
||||
volatile LONG oldState, newState;
|
||||
bool bSignalInner;
|
||||
|
||||
do
|
||||
{
|
||||
bSignalInner = false;
|
||||
oldState = m_state;
|
||||
|
||||
newState = oldState | 0x80000000;
|
||||
if (oldState & 0x7fffffff)
|
||||
{
|
||||
bSignalInner = true;
|
||||
}
|
||||
}
|
||||
while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState);
|
||||
|
||||
if (bSignalInner)
|
||||
{
|
||||
m_innerEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
bool Wait(uint32 timeout = 0)
|
||||
{
|
||||
bool bTimedOut = false;
|
||||
bool bAcquiredSignal = false;
|
||||
|
||||
while (!bTimedOut && !bAcquiredSignal)
|
||||
{
|
||||
volatile long oldState, newState;
|
||||
do
|
||||
{
|
||||
bAcquiredSignal = false;
|
||||
|
||||
oldState = m_state;
|
||||
if (oldState & 0x80000000)
|
||||
{
|
||||
// Signalled
|
||||
newState = oldState & 0x7fffffff;
|
||||
bAcquiredSignal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newState = oldState + 1;
|
||||
}
|
||||
}
|
||||
while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState);
|
||||
|
||||
if (!bAcquiredSignal)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
m_innerEvent.Wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
bTimedOut = !m_innerEvent.Wait(timeout);
|
||||
}
|
||||
|
||||
if (!bTimedOut)
|
||||
{
|
||||
m_innerEvent.Reset();
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
bAcquiredSignal = false;
|
||||
|
||||
oldState = m_state;
|
||||
if (!bTimedOut && (oldState & 0x80000000))
|
||||
{
|
||||
newState = (oldState & 0x7fffffff) - 1;
|
||||
bAcquiredSignal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newState = oldState - 1;
|
||||
}
|
||||
}
|
||||
while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState);
|
||||
}
|
||||
}
|
||||
|
||||
return bAcquiredSignal;
|
||||
}
|
||||
|
||||
private:
|
||||
CStreamEngineWakeEvent(const CStreamEngineWakeEvent&);
|
||||
CStreamEngineWakeEvent& operator = (const CStreamEngineWakeEvent&);
|
||||
|
||||
private:
|
||||
volatile LONG m_state;
|
||||
CryEvent m_innerEvent;
|
||||
};
|
||||
|
||||
struct SStreamEngineTempMemStats
|
||||
{
|
||||
enum
|
||||
{
|
||||
MaxWakeEvents = 8,
|
||||
};
|
||||
|
||||
SStreamEngineTempMemStats()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
void* TempAlloc(CMTSafeHeap* pHeap, size_t nSize, const char* szDbgSource, bool bFallBackToMalloc = true, bool bUrgent = false, uint32 align = 0);
|
||||
void TempFree(CMTSafeHeap* pHeap, const void* p, size_t nSize);
|
||||
void ReportTempMemAlloc(uint32 nSizeAlloc, uint32 nSizeFree, bool bTriggerWake);
|
||||
|
||||
volatile LONG m_nTempAllocatedMemory;
|
||||
volatile LONG m_nTempAllocatedMemoryFrameMax;
|
||||
int m_nTempMemoryBudget;
|
||||
CStreamEngineWakeEvent* m_wakeEvents[MaxWakeEvents];
|
||||
int m_nWakeEvents;
|
||||
};
|
||||
|
||||
struct SStreamJobEngineState
|
||||
{
|
||||
std::vector<SStreamRequestQueue*>* pReportQueues;
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
SStreamEngineStatistics* pStats;
|
||||
SStreamEngineDecompressStats* pDecompressStats;
|
||||
#endif
|
||||
|
||||
SStreamEngineTempMemStats* pTempMem;
|
||||
|
||||
CMTSafeHeap* pHeap;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H
|
||||
@@ -1,531 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
#include <CryPath.h>
|
||||
#include "StreamAsyncFileRequest.h"
|
||||
|
||||
#include "MTSafeAllocator.h"
|
||||
|
||||
namespace AZ::IO::ZipDir::ZipDirStructuresInternal
|
||||
{
|
||||
extern void ZlibInflateElementPartial_Impl(
|
||||
int* pReturnCode, z_stream* pZStream, ZipDir::UncompressLookahead* pLookahead,
|
||||
uint8_t* pOutput, size_t nOutputLen, bool bOutputWriteOnly,
|
||||
const uint8_t* pInput, size_t nInputLen, size_t* pTotalOut);
|
||||
}
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
#include "IStreamEngine.h"
|
||||
class NotifyListener
|
||||
{
|
||||
public:
|
||||
NotifyListener(IStreamEngineListener* pL, CAsyncIOFileRequest* pReq)
|
||||
: m_pL(pL)
|
||||
, m_pReq(pReq)
|
||||
, m_bInProgress(false) {}
|
||||
virtual ~NotifyListener() {}
|
||||
protected:
|
||||
IStreamEngineListener* m_pL;
|
||||
CAsyncIOFileRequest* m_pReq;
|
||||
bool m_bInProgress;
|
||||
};
|
||||
class NotifyListenerInflate
|
||||
: NotifyListener
|
||||
{
|
||||
public:
|
||||
NotifyListenerInflate(IStreamEngineListener* pL, CAsyncIOFileRequest* pReq)
|
||||
: NotifyListener(pL, pReq)
|
||||
{
|
||||
if (m_pL)
|
||||
{
|
||||
m_pL->OnStreamBeginInflate(m_pReq);
|
||||
m_bInProgress = true;
|
||||
}
|
||||
}
|
||||
~NotifyListenerInflate()
|
||||
{
|
||||
End();
|
||||
}
|
||||
void End()
|
||||
{
|
||||
if (m_bInProgress)
|
||||
{
|
||||
m_pL->OnStreamEndInflate(m_pReq);
|
||||
m_bInProgress = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
#define STREAMENGINE_ENABLE_TIMING
|
||||
#endif
|
||||
|
||||
//#define STREAM_DECOMPRESS_TRACE(...) OutputDebugString(AZStd::string::format(__VA_ARGS__).c_str());
|
||||
#define STREAM_DECOMPRESS_TRACE(...)
|
||||
|
||||
void SStreamJobQueue::Flush(SStreamEngineTempMemStats& tms)
|
||||
{
|
||||
extern CMTSafeHeap* g_pPakHeap;
|
||||
|
||||
for (int c = m_nQueueLen, i = m_nPop % MaxJobs; c; --c, i = (i + 1) % MaxJobs)
|
||||
{
|
||||
Job& j = m_jobs[i];
|
||||
if (j.pSrcHdr && CryInterlockedDecrement(&j.pSrcHdr->nRefs) == 0)
|
||||
{
|
||||
tms.TempFree(g_pPakHeap, j.pSrc, j.pSrcHdr->nSize);
|
||||
}
|
||||
j.pSrc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int SStreamJobQueue::Push(void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast)
|
||||
{
|
||||
m_sema.Acquire();
|
||||
|
||||
int nSlot = (m_nPush++) % MaxJobs;
|
||||
|
||||
Job& j = m_jobs[nSlot];
|
||||
j.pSrc = pSrc;
|
||||
j.pSrcHdr = pSrcHdr;
|
||||
j.nOffs = nOffs;
|
||||
j.nBytes = nBytes;
|
||||
j.bLast = (uint32)bLast;
|
||||
|
||||
bool bStartNext = CryInterlockedIncrement(&m_nQueueLen) == 1;
|
||||
return bStartNext ? nSlot : -1;
|
||||
}
|
||||
|
||||
int SStreamJobQueue::Pop()
|
||||
{
|
||||
int nSlot = (++m_nPop) % MaxJobs;
|
||||
bool bStartNext = CryInterlockedDecrement(&m_nQueueLen) > 0;
|
||||
|
||||
m_sema.Release();
|
||||
|
||||
return bStartNext ? nSlot : -1;
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::AddRef()
|
||||
{
|
||||
//int nRef =
|
||||
CryInterlockedIncrement(&m_nRefCount);
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],AddRef,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nRef);
|
||||
}
|
||||
|
||||
int CAsyncIOFileRequest::Release()
|
||||
{
|
||||
int nRef = CryInterlockedDecrement(&m_nRefCount);
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],Release,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nRef);
|
||||
|
||||
#ifndef _RELEASE
|
||||
if (nRef < 0)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nRef == 0)
|
||||
{
|
||||
Finalize();
|
||||
|
||||
CryInterlockedPushEntrySList(s_freeRequests, m_nextFree);
|
||||
}
|
||||
|
||||
return nRef;
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::DecompressBlockEntry(SStreamJobEngineState engineState, int nJob)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::System);
|
||||
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],DecompressBlockEntry,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nJob);
|
||||
|
||||
CAsyncIOFileRequest_TransferPtr pSelf(this);
|
||||
|
||||
SStreamJobQueue::Job& job = m_pDecompQueue->m_jobs[nJob];
|
||||
|
||||
void* pSrc = job.pSrc;
|
||||
SStreamPageHdr* const pSrcHdr = job.pSrcHdr;
|
||||
const uint32 nOffs = job.nOffs;
|
||||
const uint32 nBytes = job.nBytes;
|
||||
const bool bLast = job.bLast;
|
||||
const bool bFailed = HasFailed();
|
||||
|
||||
if (!bFailed)
|
||||
{
|
||||
#if defined(STREAMENGINE_ENABLE_TIMING)
|
||||
LARGE_INTEGER liStart;
|
||||
QueryPerformanceCounter(&liStart);
|
||||
#endif
|
||||
|
||||
//printf("Inflate: %s Avail in: %d, Avail Out: %d, Next In: 0x%p, Next Out: 0x%p\n", m_strFileName.c_str(), m_pZlibStream->avail_in, m_pZlibStream->avail_out, m_pZlibStream->next_in, m_pZlibStream->next_out);
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
NotifyListenerInflate inflateListener(gEnv->pSystem->GetStreamEngine()->GetListener(), this);
|
||||
#endif
|
||||
|
||||
size_t nBytesDecomped = m_nBytesDecompressed;
|
||||
|
||||
STREAM_DECOMPRESS_TRACE ("[StreamDecompress],ZlibInflateElementPartial_Impl,0x%x,%s,0x%p,%i,0x%p,%i,%i\n",
|
||||
CryGetCurrentThreadId(),
|
||||
m_strFileName.c_str(),
|
||||
(uint8_t*)m_pReadMemoryBuffer + nBytesDecomped,
|
||||
m_nFileSize - nBytesDecomped,
|
||||
(uint8_t*)pSrc + nOffs,
|
||||
nBytes,
|
||||
nBytesDecomped);
|
||||
|
||||
int readStatus = Z_OK;
|
||||
|
||||
{
|
||||
CryOptionalAutoLock<CryCriticalSection> decompLock(m_externalBufferLockDecompress, m_pExternalMemoryBuffer != NULL);
|
||||
|
||||
AZ::IO::ZipDir::ZipDirStructuresInternal::ZlibInflateElementPartial_Impl(
|
||||
&readStatus,
|
||||
m_pZlibStream,
|
||||
m_pLookahead,
|
||||
(uint8_t*)m_pReadMemoryBuffer + nBytesDecomped,
|
||||
m_nFileSize - nBytesDecomped,
|
||||
m_bWriteOnlyExternal,
|
||||
(uint8_t*)pSrc + nOffs,
|
||||
nBytes,
|
||||
&nBytesDecomped
|
||||
);
|
||||
}
|
||||
|
||||
m_nBytesDecompressed = nBytesDecomped;
|
||||
|
||||
//inform listen, so aysnc callback does not overlap
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
inflateListener.End();
|
||||
#endif
|
||||
|
||||
if (readStatus == Z_OK || readStatus == Z_STREAM_END)
|
||||
{
|
||||
#if defined(STREAMENGINE_ENABLE_TIMING)
|
||||
LARGE_INTEGER liEnd, liFreq;
|
||||
QueryPerformanceCounter(&liEnd);
|
||||
QueryPerformanceFrequency(&liFreq);
|
||||
|
||||
m_unzipTime += CTimeValue((int64)((liEnd.QuadPart - liStart.QuadPart) * CTimeValue::TIMEVALUE_PRECISION / liFreq.QuadPart));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _RELEASE
|
||||
AZ_Assert(false, "Decomp Error: %s : %s\n", m_strFileName.c_str(), m_pZlibStream ? m_pZlibStream->msg : "m_pZlibStream == NULL, no message available");
|
||||
#endif
|
||||
Failed(ERROR_DECOMPRESSION_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSrcHdr)
|
||||
{
|
||||
if (CryInterlockedDecrement(&pSrcHdr->nRefs) == 0)
|
||||
{
|
||||
engineState.pTempMem->TempFree(engineState.pHeap, pSrc, pSrcHdr->nSize);
|
||||
}
|
||||
}
|
||||
|
||||
job.pSrc = NULL;
|
||||
|
||||
int nPopSlot = m_pDecompQueue->Pop();
|
||||
|
||||
// job is no longer valid
|
||||
|
||||
if (HasFailed() || bLast)
|
||||
{
|
||||
JobFinalize_Decompress(pSelf, engineState);
|
||||
}
|
||||
else if (nPopSlot >= 0)
|
||||
{
|
||||
// Chain start the next job, we're responsible for it.
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],Chaining,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nPopSlot);
|
||||
JobStart_Decompress(pSelf, engineState, nPopSlot);
|
||||
}
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
CryInterlockedDecrement(&engineState.pStats->nCurrentDecompressCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32 CAsyncIOFileRequest::PushDecompressPage(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nBytes, bool bLast)
|
||||
{
|
||||
uint32 nError = 0;
|
||||
|
||||
for (uint32 nBlockPos = 0; !nError && (nBlockPos < nBytes); nBlockPos += STREAMING_BLOCK_SIZE)
|
||||
{
|
||||
bool bLastBlock = (nBlockPos + STREAMING_BLOCK_SIZE) >= nBytes;
|
||||
uint32 nBlockSize = min(nBytes - nBlockPos, (uint32)STREAMING_BLOCK_SIZE);
|
||||
|
||||
nError = PushDecompressBlock(engineState, pSrc, pSrcHdr, nBlockPos, nBlockSize, bLast && bLastBlock);
|
||||
}
|
||||
|
||||
return nError;
|
||||
}
|
||||
|
||||
uint32 CAsyncIOFileRequest::PushDecompressBlock(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast)
|
||||
{
|
||||
uint32 nError = m_nError;
|
||||
|
||||
if (!nError)
|
||||
{
|
||||
if (pSrcHdr)
|
||||
{
|
||||
CryInterlockedIncrement(&pSrcHdr->nRefs);
|
||||
}
|
||||
|
||||
int nPushJob = m_pDecompQueue->Push(pSrc, pSrcHdr, nOffs, nBytes, bLast);
|
||||
if (nPushJob >= 0)
|
||||
{
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],PushDecompressBlock,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nPushJob);
|
||||
|
||||
AddRef();
|
||||
CAsyncIOFileRequest_TransferPtr pSelf(this);
|
||||
JobStart_Decompress(pSelf, engineState, nPushJob);
|
||||
}
|
||||
}
|
||||
|
||||
return nError;
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::JobStart_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState, int nJob)
|
||||
{
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],QueueDecompressBlockAppend,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, nJob);
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
CryInterlockedIncrement(&engineState.pStats->nCurrentDecompressCount);
|
||||
#endif
|
||||
|
||||
CAsyncIOFileRequest* request = pSelf.Relinquish();
|
||||
if (!request->m_decompJobExecutor)
|
||||
{
|
||||
request->m_decompJobExecutor = AZStd::make_unique<AZ::LegacyJobExecutor>();
|
||||
}
|
||||
request->m_decompJobExecutor->StartJob([request, engineState, nJob]()
|
||||
{
|
||||
request->DecompressBlockEntry(engineState, nJob);
|
||||
}); // Legacy JobManager priority: eStreamPriority
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CAsyncIOFileRequest::JobFinalize_Read(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState)
|
||||
{
|
||||
if (!pSelf->m_bCompressedBuffer || pSelf->HasFailed())
|
||||
{
|
||||
JobFinalize_Transfer(pSelf, engineState);
|
||||
}
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::JobFinalize_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState)
|
||||
{
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],FinalizeDecompress,0x%x,%s,0x%p,0x%p,0x%p,0x%p\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, &engineState, engineState.pStats, engineState.pDecompressStats);
|
||||
|
||||
CAsyncIOFileRequest* pReq = &*pSelf;
|
||||
|
||||
if (!pReq->HasFailed())
|
||||
{
|
||||
// Handle reads of subsections of a compressed file, by copying the section to the output
|
||||
uint8_t* pDst = (uint8_t*)pReq->m_pOutputMemoryBuffer;
|
||||
uint8_t* pSrc = (uint8_t*)pReq->m_pReadMemoryBuffer + pReq->m_nRequestedOffset;
|
||||
|
||||
if (pDst != pSrc)
|
||||
{
|
||||
memmove(pReq->m_pOutputMemoryBuffer, pSrc, pReq->m_nRequestedSize);
|
||||
}
|
||||
|
||||
pReq->JobFinalize_Validate(engineState);
|
||||
}
|
||||
|
||||
pReq->JobFinalize_Buffer(engineState);
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS) && defined(STREAMENGINE_ENABLE_TIMING)
|
||||
if (pReq->m_unzipTime.GetValue() != 0)
|
||||
{
|
||||
engineState.pDecompressStats->m_nTotalBytesUnziped += pReq->m_nFileSize;
|
||||
engineState.pDecompressStats->m_totalUnzipTime += pReq->m_unzipTime;
|
||||
|
||||
engineState.pDecompressStats->m_nTempBytesUnziped += pReq->m_nFileSize;
|
||||
engineState.pDecompressStats->m_tempUnzipTime += pReq->m_unzipTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
JobFinalize_Transfer(pSelf, engineState);
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::JobFinalize_Buffer(const SStreamJobEngineState& engineState)
|
||||
{
|
||||
if (CryInterlockedDecrement(&m_nMemoryBufferUsers) == 0)
|
||||
{
|
||||
z_stream_s* pZlib = m_pZlibStream;
|
||||
|
||||
if (pZlib)
|
||||
{
|
||||
//if the stream was cancelled in flight, inform zlib to free internal allocs
|
||||
if (pZlib->state)
|
||||
{
|
||||
inflateEnd(pZlib);
|
||||
}
|
||||
|
||||
m_pZlibStream = NULL;
|
||||
}
|
||||
|
||||
if (m_pMemoryBuffer)
|
||||
{
|
||||
engineState.pTempMem->TempFree(engineState.pHeap, m_pMemoryBuffer, m_nMemoryBufferSize);
|
||||
|
||||
m_pMemoryBuffer = NULL;
|
||||
m_nMemoryBufferSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::JobFinalize_Validate([[maybe_unused]] const SStreamJobEngineState& engineState)
|
||||
{
|
||||
#if defined(SKIP_CHECKSUM_FROM_OPTICAL_MEDIA)
|
||||
if (m_eMediaType != eStreamSourceTypeDisc)
|
||||
#endif //SKIP_CHECKSUM_FROM_OPTICAL_MEDIA
|
||||
{
|
||||
CryOptionalAutoLock<CryCriticalSection> readLock(m_externalBufferLockRead, m_pExternalMemoryBuffer != NULL);
|
||||
if (!HasFailed())
|
||||
{
|
||||
if (m_crc32FromHeader != 0 && m_nPageReadStart == 0 && m_nRequestedSize == m_nFileSize) //Compute the CRC32 if appropriate.
|
||||
{
|
||||
#if defined(STREAMENGINE_ENABLE_TIMING)
|
||||
LARGE_INTEGER liStart, liEnd, liFreq;
|
||||
QueryPerformanceCounter(&liStart);
|
||||
#endif //STREAMENGINE_ENABLE_TIMING
|
||||
|
||||
uint32 nCRC32 = crc32(0, (uint8_t*)m_pReadMemoryBuffer + m_nPageReadStart, m_nRequestedSize);
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_TIMING)
|
||||
QueryPerformanceCounter(&liEnd);
|
||||
QueryPerformanceFrequency(&liFreq);
|
||||
|
||||
m_verifyTime += CTimeValue((int64)((liEnd.QuadPart - liStart.QuadPart) * CTimeValue::TIMEVALUE_PRECISION / liFreq.QuadPart));
|
||||
|
||||
engineState.pDecompressStats->m_nTotalBytesVerified += m_nFileSize;
|
||||
engineState.pDecompressStats->m_totalVerifyTime += m_verifyTime;
|
||||
engineState.pDecompressStats->m_nTempBytesVerified += m_nFileSize;
|
||||
engineState.pDecompressStats->m_tempVerifyTime += m_verifyTime;
|
||||
#endif //STREAMENGINE_ENABLE_TIMING
|
||||
|
||||
if (m_crc32FromHeader != nCRC32)
|
||||
{
|
||||
//The contents of this file don't match what the header expects
|
||||
#if !defined(_RELEASE)
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR_DBGBRK, "Streaming Engine Failed to verify a file (%s). Computed CRC32 %d does not match stored CRC32 %d", m_strFileName.c_str(), nCRC32, m_crc32FromHeader);
|
||||
#endif //!_RELEASE
|
||||
Failed(ERROR_VERIFICATION_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAsyncIOFileRequest::JobFinalize_Transfer(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState)
|
||||
{
|
||||
STREAM_DECOMPRESS_TRACE("[StreamDecompress],FinalizeTransform,0x%x,%s,0x%p,0x%p,0x%p,0x%p\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, &engineState, engineState.pStats, engineState.pDecompressStats);
|
||||
|
||||
if (CryInterlockedCompareExchange(&pSelf->m_nFinalised, 1, 0) == 0)
|
||||
{
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
CryInterlockedIncrement(&engineState.pStats->nCurrentAsyncCount);
|
||||
#endif
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_TIMING)
|
||||
pSelf->m_completionTime = gEnv->pTimer->GetAsyncTime();
|
||||
#endif
|
||||
|
||||
int nCallbackThreads = engineState.pReportQueues->size();
|
||||
|
||||
EStreamTaskType eType = pSelf->m_eType;
|
||||
if (nCallbackThreads > 1 && eType == eStreamTaskTypeGeometry)
|
||||
{
|
||||
// If we have more then 1 call back threads, use this one for geometry only.
|
||||
(*engineState.pReportQueues)[1]->TransferRequest(pSelf);
|
||||
}
|
||||
else if (nCallbackThreads > 2 && eType == eStreamTaskTypeTexture)
|
||||
{
|
||||
// If we have more then 1 call back threads, use this one for textures only.
|
||||
(*engineState.pReportQueues)[2]->TransferRequest(pSelf);
|
||||
}
|
||||
else if (nCallbackThreads > 3 && eType == eStreamTaskTypeMergedMesh)
|
||||
{
|
||||
// If we have more then 3 call back threads, use this one for merged meshes only.
|
||||
(*engineState.pReportQueues)[3]->TransferRequest(pSelf);
|
||||
}
|
||||
else if (nCallbackThreads > 0)
|
||||
{
|
||||
(*engineState.pReportQueues)[0]->TransferRequest(pSelf);
|
||||
}
|
||||
else
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void SStreamRequestQueue::TransferRequest(CAsyncIOFileRequest_TransferPtr& pRequest)
|
||||
{
|
||||
{
|
||||
CryAutoLock<CryCriticalSection> l(m_lock);
|
||||
|
||||
m_requests.push_back(pRequest.Relinquish());
|
||||
}
|
||||
|
||||
m_awakeEvent.Set();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void SStreamEngineTempMemStats::TempFree(CMTSafeHeap* pHeap, const void* p, size_t nSize)
|
||||
{
|
||||
#if MTSAFE_USE_GENERAL_HEAP
|
||||
bool bInGenHeap = pHeap->IsInGeneralHeap(p);
|
||||
#else
|
||||
bool bInGenHeap = false;
|
||||
#endif
|
||||
pHeap->FreeTemporary(const_cast<void*>(p));
|
||||
ReportTempMemAlloc(0, bInGenHeap ? 0 : nSize, true);
|
||||
}
|
||||
|
||||
void SStreamEngineTempMemStats::ReportTempMemAlloc(uint32 nSizeAlloc, uint32 nSizeFree, bool bTriggerWake)
|
||||
{
|
||||
int nAdd = (int)nSizeAlloc - (int)nSizeFree;
|
||||
int const nOldSize = CryInterlockedExchangeAdd(&m_nTempAllocatedMemory, nAdd);
|
||||
int const nNewSize = nOldSize + nAdd;
|
||||
|
||||
LONG nNewMax = 0;
|
||||
LONG nOldMax = 0;
|
||||
do
|
||||
{
|
||||
nOldMax = m_nTempAllocatedMemoryFrameMax;
|
||||
nNewMax = (LONG)max((int)nNewSize, (int)nOldMax);
|
||||
}
|
||||
while (CryInterlockedCompareExchange(&m_nTempAllocatedMemoryFrameMax, nNewMax, nOldMax) != nOldMax);
|
||||
|
||||
if (bTriggerWake)
|
||||
{
|
||||
for (int i = 0, c = m_nWakeEvents; i != c; ++i)
|
||||
{
|
||||
m_wakeEvents[i]->Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Engine
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "IStreamEngine.h"
|
||||
#include "ISystem.h"
|
||||
#include "TimeValue.h"
|
||||
|
||||
#include <CryThread.h>
|
||||
#include "StreamIOThread.h"
|
||||
#include "StreamReadStream.h"
|
||||
|
||||
#include <AzFramework/Input/Events/InputChannelEventListener.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/std/chrono/clocks.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
|
||||
enum EIOThread
|
||||
{
|
||||
eIOThread_HDD = 0,
|
||||
eIOThread_Optical = 1,
|
||||
eIOThread_InMemory = 2,
|
||||
eIOThread_Last = 3,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CStreamEngine
|
||||
: public IStreamEngine
|
||||
, public ISystemEventListener
|
||||
, public AzFramework::InputChannelEventListener
|
||||
{
|
||||
public:
|
||||
CStreamEngine();
|
||||
~CStreamEngine();
|
||||
|
||||
void Shutdown();
|
||||
// This is called to cancel all pending requests, without sending callbacks.
|
||||
void CancelAll();
|
||||
|
||||
|
||||
//Helper added to aid in migration from Cry's CStreamEngine to AZ::IO::Streamer
|
||||
static AZ::IO::IStreamerTypes::Priority CryStreamPriorityToAZStreamPriority(EStreamTaskPriority cryPriority);
|
||||
static AZStd::chrono::milliseconds AZDeadlineFromReadParams(const StreamReadParams& params);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IStreamEngine interface
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IReadStreamPtr StartRead (const EStreamTaskType tSource, const char* szFile, IStreamCallback* pCallback, const StreamReadParams* pParams = NULL);
|
||||
size_t StartBatchRead(IReadStreamPtr* pStreamsOut, const StreamReadBatchParams* pReqs, size_t numReqs, AZStd::function<void()>* preRequestCallback = nullptr);
|
||||
void BeginReadGroup();
|
||||
void EndReadGroup();
|
||||
|
||||
bool IsStreamDataOnHDD() const { return m_bStreamDataOnHDD; }
|
||||
void SetStreamDataOnHDD(bool bFlag) { m_bStreamDataOnHDD = bFlag; }
|
||||
|
||||
void Update();
|
||||
void UpdateAndWait(bool bAbortAll = false);
|
||||
void Update(uint32 nUpdateTypesBitmask);
|
||||
|
||||
void GetMemoryStatistics(ICrySizer* pSizer);
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
SStreamEngineStatistics& GetStreamingStatistics();
|
||||
void ClearStatistics();
|
||||
|
||||
void GetBandwidthStats(EStreamTaskType type, float* bandwidth);
|
||||
#endif
|
||||
|
||||
void GetStreamingOpenStatistics(SStreamEngineOpenStats& openStatsOut);
|
||||
|
||||
const char* GetStreamTaskTypeName(EStreamTaskType type);
|
||||
|
||||
SStreamJobEngineState GetJobEngineState();
|
||||
SStreamEngineTempMemStats& GetTempMemStats() { return m_tempMem; }
|
||||
|
||||
// Will pause or unpause streaming of specified by mask data types
|
||||
void PauseStreaming(bool bPause, uint32 nPauseTypesBitmask);
|
||||
// Pause/resumes any IO active from the streaming engine
|
||||
void PauseIO(bool bPause);
|
||||
|
||||
uint32 GetPauseMask() const { return m_nPausedDataTypesMask; }
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_LISTENER)
|
||||
void SetListener(IStreamEngineListener* pListener);
|
||||
IStreamEngineListener* GetListener();
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// updates the job priority of an IO job into the IOQueue while maintaining order in the queue
|
||||
void UpdateJobPriority(IReadStreamPtr pJobStream);
|
||||
|
||||
void ReportAsyncFileRequestComplete(CAsyncIOFileRequest_AutoPtr pFileRequest);
|
||||
void AbortJob(CReadStream* pStream);
|
||||
|
||||
|
||||
// Dispatches synchrnous callbacks, free temporary memory hold for callbacks.
|
||||
void MainThread_FinalizeIOJobs();
|
||||
void MainThread_FinalizeIOJobs(uint32 type);
|
||||
|
||||
void* TempAlloc(size_t nSize, const char* szDbgSource, bool bFallBackToMalloc = true, bool bUrgent = false, uint32 align = 0);
|
||||
void TempFree(void* p, size_t nSize);
|
||||
|
||||
uint32 GetCurrentTempMemorySize() const { return m_tempMem.m_nTempAllocatedMemory; }
|
||||
void FlagTempMemOutOfBudget()
|
||||
{
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
m_bTempMemOutOfBudget = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzFramework::InputChannelEventListener
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool StartFileRequest(CAsyncIOFileRequest* pFileRequest);
|
||||
void SignalToStartWork(EIOThread e, bool bForce);
|
||||
|
||||
private:
|
||||
void StartThreads();
|
||||
void StopThreads();
|
||||
|
||||
void ResumePausedStreams_PauseLocked();
|
||||
|
||||
#if defined(STREAMENGINE_ENABLE_STATS)
|
||||
// add job to current statistics
|
||||
void UpdateStatistics(CReadStream* pReadStream);
|
||||
void DrawStatistics();
|
||||
#endif
|
||||
|
||||
void QueueRequestCompleteJob(class AZRequestReadStream* stream, AZ::IO::SizeType numBytesRead, void* buffer,
|
||||
AZ::IO::IStreamerTypes::RequestStatus requestState);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ISystemEventListener
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CryMT::set<CReadStream_AutoPtr> m_streams;
|
||||
CryMT::vector<CReadStream_AutoPtr> m_finishedStreams;
|
||||
std::vector<CReadStream_AutoPtr> m_tempFinishedStreams;
|
||||
|
||||
CryCriticalSection m_pendingRequestCompletionsLock;
|
||||
AZStd::queue<AZ::Job*> m_pendingRequestCompletions;
|
||||
|
||||
// 2 IO threads.
|
||||
_smart_ptr<CStreamingIOThread> m_pThreadIO[eIOThread_Last];
|
||||
std::vector<_smart_ptr<CStreamingWorkerThread> > m_asyncCallbackThreads;
|
||||
std::vector<SStreamRequestQueue*> m_asyncCallbackQueues;
|
||||
|
||||
CryCriticalSection m_pausedLock;
|
||||
std::vector<CReadStream_AutoPtr> m_pausedStreams;
|
||||
volatile uint32 m_nPausedDataTypesMask;
|
||||
|
||||
bool m_bStreamDataOnHDD;
|
||||
bool m_bUseOpticalDriveThread;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Streaming statistics.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
IStreamEngineListener* m_pListener;
|
||||
#endif
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
SStreamEngineStatistics m_Statistics;
|
||||
SStreamEngineDecompressStats m_decompressStats;
|
||||
CTimeValue m_TimeOfLastReset;
|
||||
CTimeValue m_TimeOfLastUpdate;
|
||||
|
||||
CryCriticalSection m_csStats;
|
||||
std::vector<CAsyncIOFileRequest_AutoPtr> m_statsRequestList;
|
||||
|
||||
struct SExtensionInfo
|
||||
{
|
||||
SExtensionInfo()
|
||||
: m_fTotalReadTime(0.0f)
|
||||
, m_nTotalRequests(0)
|
||||
, m_nTotalReadSize(0)
|
||||
, m_nTotalRequestSize(0)
|
||||
{
|
||||
}
|
||||
float m_fTotalReadTime;
|
||||
size_t m_nTotalRequests;
|
||||
uint64 m_nTotalReadSize;
|
||||
uint64 m_nTotalRequestSize;
|
||||
};
|
||||
typedef std::map<string, SExtensionInfo> TExtensionInfoMap;
|
||||
TExtensionInfoMap m_PerExtensionInfo;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Used to calculate unzip/verify bandwidth for statistics.
|
||||
uint32 m_nUnzipBandwidth;
|
||||
uint32 m_nUnzipBandwidthAverage;
|
||||
uint32 m_nVerifyBandwidth;
|
||||
uint32 m_nVerifyBandwidthAverage;
|
||||
CTimeValue m_nLastBandwidthUpdateTime;
|
||||
|
||||
bool m_bStreamingStatsPaused;
|
||||
bool m_bInputCallback;
|
||||
bool m_bTempMemOutOfBudget;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
SStreamEngineOpenStats m_OpenStatistics;
|
||||
|
||||
bool m_bShutDown;
|
||||
|
||||
volatile int m_nBatchMode;
|
||||
|
||||
// Memory currently allocated by streaming engine for temporary storage.
|
||||
SStreamEngineTempMemStats m_tempMem;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H
|
||||
@@ -1,819 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Thread for IO
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "StreamIOThread.h"
|
||||
#include "StreamEngine.h"
|
||||
#include "../System.h"
|
||||
|
||||
extern SSystemCVars g_cvars;
|
||||
|
||||
//#pragma("control %push O=0") // to disable optimization
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CStreamingIOThread::CStreamingIOThread(CStreamEngine* pStreamEngine, EStreamSourceMediaType mediaType, const char* name)
|
||||
{
|
||||
m_pStreamEngine = pStreamEngine;
|
||||
m_bCancelThreadRequest = false;
|
||||
m_bNeedSorting = false;
|
||||
m_bNeedReset = false;
|
||||
m_bNewRequests = false;
|
||||
m_name = name;
|
||||
m_eMediaType = mediaType;
|
||||
m_nFallbackMTs = 0;
|
||||
|
||||
m_iUrgentRequests = 0;
|
||||
|
||||
m_bPaused = false;
|
||||
m_bAbortReads = false;
|
||||
|
||||
m_nReadCounter = 0;
|
||||
m_nStreamingCPU = -1;
|
||||
|
||||
Start((unsigned)(1 << g_cvars.sys_streaming_cpu), name);
|
||||
}
|
||||
|
||||
CStreamingIOThread::~CStreamingIOThread()
|
||||
{
|
||||
Cancel();
|
||||
Stop();
|
||||
WaitForThread();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::AddRequest(CAsyncIOFileRequest* pRequest, bool bStartImmidietly)
|
||||
{
|
||||
pRequest->AddRef(); // Acquire ownership on file request.
|
||||
pRequest->m_status = CAsyncIOFileRequest::eStatusInFileQueue;
|
||||
if (pRequest->m_eMediaType != eStreamSourceTypeMemory)
|
||||
{
|
||||
pRequest->m_eMediaType = m_eMediaType;
|
||||
}
|
||||
// does this ignore the tmp out of memory
|
||||
if (pRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedIncrement(&m_iUrgentRequests);
|
||||
}
|
||||
m_newFileRequests.push_back(pRequest);
|
||||
|
||||
if (bStartImmidietly)
|
||||
{
|
||||
READ_WRITE_BARRIER
|
||||
m_bNewRequests = true;
|
||||
m_awakeEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::SignalStartWork(bool bForce)
|
||||
{
|
||||
if (!m_newFileRequests.empty() || bForce)
|
||||
{
|
||||
READ_WRITE_BARRIER
|
||||
m_bNewRequests = true;
|
||||
|
||||
m_awakeEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CStreamingIOThread::Pause(bool bPause)
|
||||
{
|
||||
m_bPaused = bPause;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::Run()
|
||||
{
|
||||
SetName(m_name);
|
||||
|
||||
CTimeValue t0 = gEnv->pTimer->GetAsyncTime();
|
||||
|
||||
m_nLastReadDiskOffset = 0;
|
||||
|
||||
//
|
||||
// Main thread loop
|
||||
while (!m_bCancelThreadRequest)
|
||||
{
|
||||
if (m_nStreamingCPU != g_cvars.sys_streaming_cpu)
|
||||
{
|
||||
m_nStreamingCPU = g_cvars.sys_streaming_cpu;
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#undef AZ_RESTRICTED_SECTION
|
||||
#define STREAMIOTHREAD_CPP_SECTION_1 1
|
||||
#define STREAMIOTHREAD_CPP_SECTION_2 2
|
||||
#endif
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION STREAMIOTHREAD_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE(StreamEngine/StreamIOThread_cpp)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_bNewRequests || !m_newFileRequests.empty())
|
||||
{
|
||||
READ_WRITE_BARRIER
|
||||
ProcessNewRequests();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_RELEASE)
|
||||
m_awakeEvent.Wait();
|
||||
#elif defined(STREAMENGINE_ENABLE_STATS)
|
||||
// compute max time to wait - revive thread every second at least once to update stats
|
||||
bool bWaiting = true;
|
||||
while (bWaiting)
|
||||
{
|
||||
CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
|
||||
CTimeValue deltaT = t1 - t0;
|
||||
uint64 msec = deltaT.GetMilliSecondsAsInt64();
|
||||
if (msec < 1000)
|
||||
{
|
||||
bWaiting = !m_awakeEvent.Wait(1000 - (uint32)msec);
|
||||
}
|
||||
|
||||
if (bWaiting)
|
||||
{
|
||||
// update the delta time again
|
||||
t1 = gEnv->pTimer->GetAsyncTime();
|
||||
deltaT = t1 - t0;
|
||||
|
||||
m_InMemoryStats.Update(deltaT);
|
||||
m_NotInMemoryStats.Update(deltaT);
|
||||
|
||||
t0 = t1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_bNeedReset)
|
||||
{
|
||||
ProcessReset();
|
||||
}
|
||||
|
||||
bool bIsOOM = false;
|
||||
|
||||
while (!m_bCancelThreadRequest && !m_fileRequestQueue.empty())
|
||||
{
|
||||
CAsyncIOFileRequest_TransferPtr pFileRequest(m_fileRequestQueue.back());
|
||||
m_fileRequestQueue.pop_back();
|
||||
|
||||
assert (&*pFileRequest);
|
||||
|
||||
if (pFileRequest->HasFailed())
|
||||
{
|
||||
// check if request was high prio, then decr open count
|
||||
if (pFileRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedDecrement(&m_iUrgentRequests);
|
||||
}
|
||||
|
||||
CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// When temporary memory goes out of budget we must loop here and wait until previous file requests are finished and free up memory.
|
||||
// Only allow processing of requests which are flagged for processing when out of tmp memory
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if (bIsOOM && !m_bCancelThreadRequest)
|
||||
{
|
||||
m_pStreamEngine->FlagTempMemOutOfBudget();
|
||||
if (m_iUrgentRequests > 0)
|
||||
{
|
||||
if (m_bNewRequests || !m_newFileRequests.empty())
|
||||
{
|
||||
READ_WRITE_BARRIER
|
||||
ProcessNewRequests();
|
||||
}
|
||||
|
||||
// readd the current request
|
||||
m_fileRequestQueue.push_back(pFileRequest.Relinquish());
|
||||
|
||||
// search for the first request which ignores the current out of mem state
|
||||
// Search for next highest priority request
|
||||
std::vector<CAsyncIOFileRequest*>::reverse_iterator rit;
|
||||
for (rit = m_fileRequestQueue.rbegin(); rit != m_fileRequestQueue.rend(); ++rit)
|
||||
{
|
||||
if ((*rit)->IgnoreOutofTmpMem())
|
||||
{
|
||||
pFileRequest = *rit;
|
||||
std::vector<CAsyncIOFileRequest*>::iterator it(rit.base());
|
||||
--it;
|
||||
m_fileRequestQueue.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// read the current request
|
||||
m_fileRequestQueue.push_back(pFileRequest.Relinquish());
|
||||
}
|
||||
}
|
||||
|
||||
// Simply let the io thread sleep when paused before doing any actual IO
|
||||
while (m_bPaused)
|
||||
{
|
||||
CrySleep(10);
|
||||
}
|
||||
|
||||
// If at this point, the filerequest is zero, the above prioritization of
|
||||
// urgent requests couldn't find a new task to displace the current
|
||||
// one. As the current one had been pushed back previously, we can safely
|
||||
// assume that restarting the loop will grab it again (eventually).
|
||||
if (!pFileRequest)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// check if request was high prio, then decr open count
|
||||
if (pFileRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedDecrement(&m_iUrgentRequests);
|
||||
}
|
||||
|
||||
bIsOOM = false;
|
||||
|
||||
uint32 nSizeOnMedia = pFileRequest->m_nSizeOnMedia;
|
||||
uint32 nError = 0;
|
||||
|
||||
// Handle file request.
|
||||
if (m_bAbortReads)
|
||||
{
|
||||
nError = ERROR_ABORTED_ON_SHUTDOWN;
|
||||
}
|
||||
else if (pFileRequest->m_bReadBegun)
|
||||
{
|
||||
nError = pFileRequest->ReadFileResume(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
nError = pFileRequest->ReadFile(this);
|
||||
}
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
pFileRequest->m_nReadCounter = m_nReadCounter++;
|
||||
#endif
|
||||
|
||||
if (nError == 0)
|
||||
{
|
||||
if (pFileRequest->m_eMediaType != eStreamSourceTypeMemory)
|
||||
{
|
||||
pFileRequest->m_nReadHeadOffsetKB = (int32)(((int64)pFileRequest->m_nDiskOffset - m_nLastReadDiskOffset) >> 10); // in KB
|
||||
m_nLastReadDiskOffset = pFileRequest->m_nDiskOffset + nSizeOnMedia;
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
m_NotInMemoryStats.m_nTempReadOffset += abs(pFileRequest->m_nReadHeadOffsetKB);
|
||||
m_NotInMemoryStats.m_nTotalReadOffset += abs(pFileRequest->m_nReadHeadOffsetKB);
|
||||
|
||||
m_NotInMemoryStats.m_nTempRequestCount++;
|
||||
|
||||
// Calc IO bandwidth only for non memory files.
|
||||
m_NotInMemoryStats.m_nTempBytesRead += nSizeOnMedia;
|
||||
m_NotInMemoryStats.m_TempReadTime += pFileRequest->m_readTime;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
m_InMemoryStats.m_nTempRequestCount++;
|
||||
|
||||
// Calc IO bandwidth only for in memory files.
|
||||
m_InMemoryStats.m_nTempBytesRead += nSizeOnMedia;
|
||||
m_InMemoryStats.m_TempReadTime += pFileRequest->m_readTime;
|
||||
#endif
|
||||
}
|
||||
|
||||
CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (nError)
|
||||
{
|
||||
case ERROR_OUT_OF_MEMORY:
|
||||
bIsOOM = true;
|
||||
|
||||
pFileRequest->SetPriority(estpPreempted);
|
||||
|
||||
if (pFileRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedIncrement(&m_iUrgentRequests);
|
||||
}
|
||||
|
||||
m_fileRequestQueue.push_back(pFileRequest.Relinquish());
|
||||
m_bNewRequests = true;
|
||||
break;
|
||||
|
||||
case ERROR_PREEMPTED:
|
||||
pFileRequest->SetPriority(estpPreempted);
|
||||
|
||||
if (pFileRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedIncrement(&m_iUrgentRequests);
|
||||
}
|
||||
|
||||
m_fileRequestQueue.push_back(pFileRequest.Relinquish());
|
||||
m_bNewRequests = true;
|
||||
break;
|
||||
|
||||
case ERROR_MISSCHEDULED:
|
||||
// Request tried to read a file that has changed media type. Reset the sort key
|
||||
// and reschedule.
|
||||
pFileRequest->m_bSortKeyComputed = 0;
|
||||
AddRequest(&*pFileRequest, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
pFileRequest->SyncWithDecompress();
|
||||
pFileRequest->Failed(nError);
|
||||
|
||||
CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if (m_bNewRequests)
|
||||
{
|
||||
READ_WRITE_BARRIER
|
||||
ProcessNewRequests();
|
||||
}
|
||||
if (m_bNeedReset)
|
||||
{
|
||||
ProcessReset();
|
||||
}
|
||||
if (m_bNeedSorting)
|
||||
{
|
||||
SortRequests();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
if (g_cvars.sys_streaming_max_bandwidth != 0)
|
||||
{
|
||||
CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
|
||||
CTimeValue deltaT = t1 - t0;
|
||||
|
||||
// Sleep in case we are streaming too fast.
|
||||
const float fTheoreticalReadTime = float(nSizeOnMedia) / g_cvars.sys_streaming_max_bandwidth * 0.00000095367431640625f; // / (1024*1024)
|
||||
|
||||
if (fTheoreticalReadTime - deltaT.GetSeconds() > FLT_EPSILON)
|
||||
{
|
||||
uint32 nSleepTime = uint32(1000.f * (fTheoreticalReadTime - deltaT.GetSeconds()));
|
||||
CrySleep(nSleepTime);
|
||||
}
|
||||
}
|
||||
|
||||
CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
|
||||
CTimeValue deltaT = t1 - t0;
|
||||
|
||||
// update the stats every second
|
||||
if (deltaT.GetMilliSecondsAsInt64() > 1000)
|
||||
{
|
||||
m_InMemoryStats.Update(deltaT);
|
||||
m_NotInMemoryStats.Update(deltaT);
|
||||
|
||||
t0 = t1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
void CStreamingIOThread::SStats::Update(const CTimeValue& deltaT)
|
||||
{
|
||||
m_nReadBytesInLastSecond = (uint32)m_nTempBytesRead;
|
||||
m_nRequestCountInLastSecond = m_nTempRequestCount;
|
||||
m_nTotalReadBytes += (uint32)m_nTempBytesRead;
|
||||
m_nTotalRequestCount += m_nTempRequestCount;
|
||||
m_TotalReadTime += m_TempReadTime;
|
||||
|
||||
if (m_TempReadTime.GetValue() != 0)
|
||||
{
|
||||
m_nActualReadBandwith = (uint32)(m_nTempBytesRead / m_TempReadTime.GetSeconds());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nActualReadBandwith = 0;
|
||||
}
|
||||
m_nCurrentReadBandwith = (uint32)(m_nTempBytesRead / deltaT.GetSeconds());
|
||||
m_fReadingDuringLastSecond = m_TempReadTime.GetSeconds() / deltaT.GetSeconds() * 100;
|
||||
|
||||
if (m_nTempRequestCount > 0)
|
||||
{
|
||||
m_nReadOffsetInLastSecond = m_nTempReadOffset / m_nTempRequestCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nReadOffsetInLastSecond = 0;
|
||||
}
|
||||
|
||||
m_TempReadTime.SetValue(0);
|
||||
m_nTempBytesRead = 0;
|
||||
m_nTempReadOffset = 0;
|
||||
m_nTempRequestCount = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::Cancel()
|
||||
{
|
||||
m_bCancelThreadRequest = true;
|
||||
m_awakeEvent.Set();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct SCompareAsyncFileRequest
|
||||
{
|
||||
bool operator()(CAsyncIOFileRequest* pFile1, CAsyncIOFileRequest* pFile2) const
|
||||
{
|
||||
return pFile1->m_nSortKey > pFile2->m_nSortKey;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::SortRequests()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
std::sort(m_fileRequestQueue.begin(), m_fileRequestQueue.end(), SCompareAsyncFileRequest());
|
||||
|
||||
/*
|
||||
int nStartOfQueue = 0;
|
||||
int64 nDiskOffsetLimit = m_nLastReadDiskOffset - 32*1024; // 32KB less only
|
||||
|
||||
int nCount = (int)m_fileRequestQueue.size();
|
||||
for (int i = nCount-1; i >= 0; i--)
|
||||
{
|
||||
if (m_fileRequestQueue[i]->m_nDiskOffset > nDiskOffsetLimit)
|
||||
{
|
||||
nStartOfQueue = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nStartOfQueue < nCount && nStartOfQueue > 0)
|
||||
{
|
||||
int nElements = nCount - nStartOfQueue;
|
||||
// Move all elements up to nStartOfQueue, from begining of the request array to the end.
|
||||
m_temporaryArray.resize(0);
|
||||
// Copy to temp array elements up to nStartOfQueue
|
||||
m_temporaryArray.insert( m_temporaryArray.end(),m_fileRequestQueue.begin()+nStartOfQueue,m_fileRequestQueue.end() );
|
||||
// Remove elements up to nStartOfQueue from request list
|
||||
m_fileRequestQueue.erase( m_fileRequestQueue.begin()+nStartOfQueue,m_fileRequestQueue.end() );
|
||||
// Add elemenets at the end from temp array.
|
||||
m_fileRequestQueue.insert( m_fileRequestQueue.begin(),m_temporaryArray.begin(),m_temporaryArray.end() );
|
||||
}
|
||||
*/
|
||||
m_bNeedSorting = false;
|
||||
}
|
||||
|
||||
void CStreamingIOThread::NeedSorting()
|
||||
{
|
||||
m_bNeedSorting = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::ProcessNewRequests()
|
||||
{
|
||||
m_bNewRequests = false;
|
||||
|
||||
std::vector<CAsyncIOFileRequest*> temporaryArray;
|
||||
temporaryArray.reserve(m_newFileRequests.size());
|
||||
m_newFileRequests.swap(temporaryArray);
|
||||
|
||||
std::vector<CAsyncIOFileRequest*>& newFiles = temporaryArray;
|
||||
|
||||
if (!newFiles.empty())
|
||||
{
|
||||
uint64 nCurrentKeyInProgress = m_fileRequestQueue.size() ? m_fileRequestQueue.back()->m_nSortKey : 0;
|
||||
|
||||
// Compute sorting key for new file entries.
|
||||
int iWakeFallback(0);
|
||||
const TFallbackIOVecConstIt itEnd = m_FallbackIOThreads.end();
|
||||
const size_t fallbackNum = m_FallbackIOThreads.size();
|
||||
PREFAST_SUPPRESS_WARNING(6255)
|
||||
uint8 * pFallbackSignals = fallbackNum ? (uint8*)alloca(fallbackNum) : NULL;
|
||||
for (uint32 fb = 0; fb < fallbackNum; ++fb)
|
||||
{
|
||||
pFallbackSignals[fb] = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0, num = newFiles.size(); i < num; i++)
|
||||
{
|
||||
CAsyncIOFileRequest* pFilepRequest = newFiles[i];
|
||||
|
||||
pFilepRequest->ComputeSortKey(nCurrentKeyInProgress);
|
||||
static_cast<CReadStream*>(&*pFilepRequest->m_pReadStream)->ComputedMediaType(pFilepRequest->m_eMediaType);
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
IStreamEngineListener* pListener = m_pStreamEngine->GetListener();
|
||||
if (pListener)
|
||||
{
|
||||
pListener->OnStreamComputedSortKey(pFilepRequest, pFilepRequest->m_nSortKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool bFallback = false;
|
||||
int idx = -1;
|
||||
for (TFallbackIOVecConstIt it = m_FallbackIOThreads.begin(); it != itEnd && !bFallback; ++it)
|
||||
{
|
||||
++idx;
|
||||
if (it->second == pFilepRequest->GetMediaType())
|
||||
{
|
||||
if (pFilepRequest->IgnoreOutofTmpMem())
|
||||
{
|
||||
CryInterlockedDecrement(&m_iUrgentRequests);
|
||||
}
|
||||
(it->first)->AddRequest(pFilepRequest, true);
|
||||
pFilepRequest->Release(); // Release local ownership of request (moved to fallback IO thread)
|
||||
iWakeFallback++;
|
||||
bFallback = true;
|
||||
pFallbackSignals[idx] = 1;
|
||||
}
|
||||
}
|
||||
if (!bFallback)
|
||||
{
|
||||
m_fileRequestQueue.push_back(pFilepRequest);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 fb = 0; fb < fallbackNum; ++fb)
|
||||
{
|
||||
if (pFallbackSignals[fb] != 0)
|
||||
{
|
||||
(m_FallbackIOThreads[fb].first)->SignalStartWork(false);
|
||||
}
|
||||
}
|
||||
|
||||
SortRequests();
|
||||
/*
|
||||
if (m_fileRequestQueue.back() != pRequest && pRequest != 0)
|
||||
{
|
||||
// Highest priority changed.
|
||||
if (m_fileRequestQueue.back()->m_nDiskOffset < (m_nLastReadDiskOffset-32*1024))
|
||||
{
|
||||
//CryLog( "Bad Offset in Queue" );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void CStreamingIOThread::ProcessReset()
|
||||
{
|
||||
if (!m_fileRequestQueue.empty())
|
||||
{
|
||||
for (std::vector<CAsyncIOFileRequest*>::iterator it = m_fileRequestQueue.begin(), itEnd = m_fileRequestQueue.end(); it != itEnd; ++it)
|
||||
{
|
||||
(*it)->Release();
|
||||
}
|
||||
}
|
||||
|
||||
stl::free_container(m_fileRequestQueue);
|
||||
|
||||
if (!m_temporaryArray.empty())
|
||||
{
|
||||
for (std::vector<CAsyncIOFileRequest*>::iterator it = m_temporaryArray.begin(), itEnd = m_temporaryArray.end(); it != itEnd; ++it)
|
||||
{
|
||||
(*it)->Release();
|
||||
}
|
||||
}
|
||||
|
||||
stl::free_container(m_temporaryArray);
|
||||
|
||||
m_bNeedReset = false;
|
||||
m_resetDoneEvent.Set();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::CancelAll()
|
||||
{
|
||||
{
|
||||
CryMT::vector<CAsyncIOFileRequest*>::AutoLock lock(m_newFileRequests.get_lock());
|
||||
|
||||
if (!m_newFileRequests.empty())
|
||||
{
|
||||
CAsyncIOFileRequest* const* it = &m_newFileRequests.front();
|
||||
CAsyncIOFileRequest* const* itEnd = it + m_newFileRequests.size();
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
(*it)->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_newFileRequests.free_memory();
|
||||
m_iUrgentRequests = 0;
|
||||
}
|
||||
|
||||
void CStreamingIOThread::AbortAll(bool bAbort)
|
||||
{
|
||||
m_bAbortReads = bAbort;
|
||||
}
|
||||
|
||||
void CStreamingIOThread::BeginReset()
|
||||
{
|
||||
CancelAll();
|
||||
|
||||
m_resetDoneEvent.Reset();
|
||||
m_bNeedReset = true;
|
||||
m_awakeEvent.Set();
|
||||
}
|
||||
|
||||
void CStreamingIOThread::EndReset()
|
||||
{
|
||||
m_resetDoneEvent.Wait();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingIOThread::RegisterFallbackIOThread(EStreamSourceMediaType mediaType, CStreamingIOThread* pIOThread)
|
||||
{
|
||||
//check if media has not yet been registered
|
||||
if (!pIOThread)
|
||||
{
|
||||
return;//no need for NULL register anymore
|
||||
}
|
||||
const TFallbackIOVecConstIt itEnd = m_FallbackIOThreads.end();
|
||||
for (TFallbackIOVecConstIt it = m_FallbackIOThreads.begin(); it != itEnd; ++it)
|
||||
{
|
||||
if (it->second == mediaType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_FallbackIOThreads.push_back(std::make_pair(pIOThread, mediaType));
|
||||
m_nFallbackMTs |= 1 << mediaType;
|
||||
}
|
||||
|
||||
bool CStreamingIOThread::HasUrgentRequests()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (m_iUrgentRequests > 0)
|
||||
{
|
||||
//lock to prevent list modification whilst traversing
|
||||
m_newFileRequests.get_lock().Lock();
|
||||
|
||||
int nRequests = m_newFileRequests.size();
|
||||
|
||||
if (nRequests)
|
||||
{
|
||||
for (int i = 0; i < nRequests; i++)
|
||||
{
|
||||
if (m_newFileRequests[i]->m_ePriority == estpUrgent)
|
||||
{
|
||||
//printf("Urgent task pending: %s\n", m_newFileRequests[i]->m_strFileName.c_str());
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_newFileRequests.get_lock().Unlock();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CStreamingIOThread::IsMisscheduled(EStreamSourceMediaType mt) const
|
||||
{
|
||||
if (mt == m_eMediaType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_nFallbackMTs & (1 << mt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CStreamingWorkerThread::CStreamingWorkerThread(CStreamEngine* pStreamEngine, const char* name, EWorkerType type, SStreamRequestQueue* pQueue)
|
||||
{
|
||||
m_type = type;
|
||||
m_name = name;
|
||||
m_pStreamEngine = pStreamEngine;
|
||||
m_pQueue = pQueue;
|
||||
m_bCancelThreadRequest = false;
|
||||
m_bNeedsReset = false;
|
||||
|
||||
Start((unsigned)1 << g_cvars.sys_streaming_cpu_worker, name);
|
||||
}
|
||||
|
||||
CStreamingWorkerThread::~CStreamingWorkerThread()
|
||||
{
|
||||
Cancel();
|
||||
Stop();
|
||||
WaitForThread();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingWorkerThread::Run()
|
||||
{
|
||||
SetName(m_name);
|
||||
|
||||
#if defined(AZ_RESTRICTED_PLATFORM)
|
||||
#define AZ_RESTRICTED_SECTION STREAMIOTHREAD_CPP_SECTION_2
|
||||
#include AZ_RESTRICTED_FILE(StreamEngine/StreamIOThread_cpp)
|
||||
#endif
|
||||
|
||||
// Main thread loop
|
||||
while (!m_bCancelThreadRequest)
|
||||
{
|
||||
m_pQueue->m_awakeEvent.Wait();
|
||||
m_pQueue->m_awakeEvent.Reset();
|
||||
|
||||
CAsyncIOFileRequest_AutoPtr pFileRequest;
|
||||
while (!m_bCancelThreadRequest && !m_bNeedsReset && m_pQueue->TryPopRequest(pFileRequest))
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case eWorkerAsyncCallback:
|
||||
{
|
||||
#ifndef _RELEASE
|
||||
float fTime = gEnv->pTimer->GetAsyncCurTime();
|
||||
#endif
|
||||
|
||||
m_pStreamEngine->ReportAsyncFileRequestComplete(pFileRequest);
|
||||
#ifndef _RELEASE
|
||||
float fTime1 = gEnv->pTimer->GetAsyncCurTime();
|
||||
#endif
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
CryInterlockedDecrement(&m_pStreamEngine->GetStreamingStatistics().nCurrentAsyncCount);
|
||||
#endif
|
||||
|
||||
#ifndef _RELEASE
|
||||
if ((fTime1 - fTime) > 1.f && !pFileRequest->m_strFileName.empty())
|
||||
{
|
||||
string str;
|
||||
str.Format("[ACALL] %s time=%.5f\n", pFileRequest->m_strFileName.c_str(), (fTime1 - fTime));
|
||||
if (gEnv && gEnv->pSystem && gEnv->pLog)
|
||||
{
|
||||
gEnv->pLog->Log(str.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bNeedsReset)
|
||||
{
|
||||
m_pQueue->Reset();
|
||||
m_bNeedsReset = false;
|
||||
m_resetDoneEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingWorkerThread::Cancel()
|
||||
{
|
||||
m_bCancelThreadRequest = true;
|
||||
m_pQueue->m_awakeEvent.Set();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStreamingWorkerThread::CancelAll()
|
||||
{
|
||||
m_pQueue->Reset();
|
||||
}
|
||||
|
||||
void CStreamingWorkerThread::BeginReset()
|
||||
{
|
||||
CancelAll();
|
||||
|
||||
m_resetDoneEvent.Reset();
|
||||
m_bNeedsReset = true;
|
||||
m_pQueue->m_awakeEvent.Set();
|
||||
}
|
||||
|
||||
void CStreamingWorkerThread::EndReset()
|
||||
{
|
||||
m_resetDoneEvent.Wait();
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Thread for IO
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H
|
||||
#pragma once
|
||||
|
||||
#include <IStreamEngine.h>
|
||||
#include "StreamAsyncFileRequest.h"
|
||||
|
||||
|
||||
class CStreamEngine;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Thread that performs IO operations.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CStreamingIOThread
|
||||
: public CrySimpleThread<CStreamingIOThread>
|
||||
, public CMultiThreadRefCount
|
||||
{
|
||||
public:
|
||||
CStreamingIOThread(CStreamEngine* pStreamEngine, EStreamSourceMediaType mediaType, const char* name);
|
||||
~CStreamingIOThread();
|
||||
|
||||
void CancelAll();
|
||||
void AbortAll(bool bAbort);
|
||||
|
||||
void BeginReset();
|
||||
void EndReset();
|
||||
|
||||
void AddRequest(CAsyncIOFileRequest* pRequest, bool bStartImmidietly);
|
||||
int GetRequestCount() const { return m_fileRequestQueue.size(); };
|
||||
void SortRequests();
|
||||
void NeedSorting();
|
||||
void SignalStartWork(bool bForce);
|
||||
bool HasUrgentRequests();
|
||||
EStreamSourceMediaType GetMediaType() const { return m_eMediaType; }
|
||||
bool IsMisscheduled(EStreamSourceMediaType mt) const;
|
||||
|
||||
void Pause(bool bPause);
|
||||
|
||||
void RegisterFallbackIOThread(EStreamSourceMediaType mediaType, CStreamingIOThread* pIOThread);
|
||||
|
||||
CStreamEngineWakeEvent& GetWakeEvent() { return m_awakeEvent; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CrySimpleThread
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void Run();
|
||||
virtual void Cancel();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
|
||||
void ProcessNewRequests();
|
||||
void ProcessReset();
|
||||
|
||||
public:
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
struct SStats
|
||||
{
|
||||
SStats()
|
||||
: m_nTotalReadBytes(0)
|
||||
, m_nCurrentReadBandwith(0)
|
||||
, m_nReadBytesInLastSecond(0)
|
||||
, m_fReadingDuringLastSecond(.0f)
|
||||
, m_nTempBytesRead(0)
|
||||
, m_nActualReadBandwith(0)
|
||||
, m_nTempReadOffset(0)
|
||||
, m_nTotalReadOffset(0)
|
||||
, m_nReadOffsetInLastSecond(0)
|
||||
, m_nTempRequestCount(0)
|
||||
, m_nTotalRequestCount(0)
|
||||
, m_nRequestCountInLastSecond(0)
|
||||
{}
|
||||
|
||||
void Update(const CTimeValue& deltaT);
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_nTotalReadBytes = 0;
|
||||
m_nTotalReadOffset = 0;
|
||||
m_nTotalRequestCount = 0;
|
||||
m_TotalReadTime.SetValue(0);
|
||||
}
|
||||
|
||||
float m_fReadingDuringLastSecond;
|
||||
CTimeValue m_TotalReadTime;
|
||||
uint64 m_nTotalReadBytes;
|
||||
uint64 m_nTotalReadOffset;
|
||||
uint32 m_nTotalRequestCount;
|
||||
uint32 m_nCurrentReadBandwith; // Read bandwidth over one second
|
||||
uint32 m_nActualReadBandwith; // Actual read bandwidth extrapolated over one second
|
||||
uint32 m_nReadBytesInLastSecond;
|
||||
uint32 m_nRequestCountInLastSecond;
|
||||
uint64 m_nReadOffsetInLastSecond;
|
||||
|
||||
uint32 m_nTempRequestCount;
|
||||
uint64 m_nTempBytesRead;
|
||||
uint64 m_nTempReadOffset;
|
||||
CTimeValue m_TempReadTime;
|
||||
};
|
||||
|
||||
SStats m_InMemoryStats;
|
||||
SStats m_NotInMemoryStats;
|
||||
#endif
|
||||
|
||||
int64 m_nLastReadDiskOffset;
|
||||
int m_nStreamingCPU;
|
||||
|
||||
private:
|
||||
CStreamEngine* m_pStreamEngine;
|
||||
std::vector<CAsyncIOFileRequest*> m_fileRequestQueue;
|
||||
std::vector<CAsyncIOFileRequest*> m_temporaryArray;
|
||||
CryMT::vector<CAsyncIOFileRequest*> m_newFileRequests;
|
||||
|
||||
EStreamSourceMediaType m_eMediaType;
|
||||
uint32 m_nFallbackMTs;
|
||||
|
||||
typedef std::pair<CStreamingIOThread*, EStreamSourceMediaType> TFallbackIOPair;
|
||||
typedef std::vector<TFallbackIOPair> TFallbackIOVec;
|
||||
typedef TFallbackIOVec::iterator TFallbackIOVecConstIt;
|
||||
TFallbackIOVec m_FallbackIOThreads;
|
||||
|
||||
volatile bool m_bCancelThreadRequest;
|
||||
volatile bool m_bNeedSorting;
|
||||
volatile bool m_bNewRequests;
|
||||
volatile bool m_bPaused;
|
||||
volatile bool m_bNeedReset;
|
||||
volatile bool m_bAbortReads;
|
||||
|
||||
volatile int m_iUrgentRequests;
|
||||
|
||||
CStreamEngineWakeEvent m_awakeEvent;
|
||||
CryEvent m_resetDoneEvent;
|
||||
string m_name;
|
||||
uint32 m_nReadCounter;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Thread that performs IO operations.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CStreamingWorkerThread
|
||||
: public CrySimpleThread<CStreamingIOThread>
|
||||
, public CMultiThreadRefCount
|
||||
{
|
||||
public:
|
||||
enum EWorkerType
|
||||
{
|
||||
eWorkerAsyncCallback,
|
||||
};
|
||||
CStreamingWorkerThread(CStreamEngine* pStreamEngine, const char* name, EWorkerType type, SStreamRequestQueue* pQueue);
|
||||
~CStreamingWorkerThread();
|
||||
|
||||
void BeginReset();
|
||||
void EndReset();
|
||||
|
||||
void CancelAll();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CrySimpleThread
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void Run();
|
||||
virtual void Cancel();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
EWorkerType m_type;
|
||||
CStreamEngine* m_pStreamEngine;
|
||||
SStreamRequestQueue* m_pQueue;
|
||||
|
||||
volatile bool m_bCancelThreadRequest;
|
||||
volatile bool m_bNeedsReset;
|
||||
|
||||
CryEvent m_resetDoneEvent;
|
||||
string m_name;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H
|
||||
@@ -1,516 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Engine
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include <ISystem.h>
|
||||
#include <ILog.h>
|
||||
|
||||
#include "StreamReadStream.h"
|
||||
#include "StreamEngine.h"
|
||||
#include "MTSafeAllocator.h"
|
||||
|
||||
extern CMTSafeHeap* g_pPakHeap;
|
||||
SLockFreeSingleLinkedListHeader CReadStream::s_freeRequests;
|
||||
|
||||
CReadStream* CReadStream::Allocate(CStreamEngine* pEngine, const EStreamTaskType tSource, const char* szFilename, IStreamCallback* pCallback, const StreamReadParams* pParams)
|
||||
{
|
||||
char* pFree = reinterpret_cast<char*>(CryInterlockedPopEntrySList(s_freeRequests));
|
||||
|
||||
CReadStream* pReq;
|
||||
IF_LIKELY (pFree)
|
||||
{
|
||||
AZ_PUSH_DISABLE_WARNING(,"-Winvalid-offsetof")
|
||||
ptrdiff_t offs = offsetof(CReadStream, m_nextFree);
|
||||
AZ_POP_DISABLE_WARNING
|
||||
pReq = reinterpret_cast<CReadStream*>(pFree - offs);
|
||||
}
|
||||
else
|
||||
{
|
||||
pReq = new CReadStream;
|
||||
}
|
||||
|
||||
pReq->m_pEngine = pEngine;
|
||||
pReq->m_Type = tSource;
|
||||
pReq->m_strFileName = szFilename;
|
||||
pReq->m_pCallback = pCallback;
|
||||
if (pParams)
|
||||
{
|
||||
pReq->m_Params = *pParams;
|
||||
}
|
||||
pReq->m_pBuffer = pReq->m_Params.pBuffer;
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
pReq->m_requestTime = gEnv->pTimer->GetAsyncTime();
|
||||
#endif
|
||||
|
||||
return pReq;
|
||||
}
|
||||
|
||||
void CReadStream::Flush()
|
||||
{
|
||||
AZ_PUSH_DISABLE_WARNING(, "-Winvalid-offsetof")
|
||||
ptrdiff_t offs = offsetof(CReadStream, m_nextFree);
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
for (char* pFree = reinterpret_cast<char*>(CryInterlockedPopEntrySList(s_freeRequests));
|
||||
pFree;
|
||||
pFree = reinterpret_cast<char*>(CryInterlockedPopEntrySList(s_freeRequests)))
|
||||
{
|
||||
CReadStream* pReq = reinterpret_cast<CReadStream*>(pFree - offs);
|
||||
delete pReq;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadStream::CReadStream()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadStream::~CReadStream()
|
||||
{
|
||||
}
|
||||
|
||||
// returns true if the file read was completed (successfully or unsuccessfully)
|
||||
// check IsError to check if the whole requested file (piece) was read
|
||||
bool CReadStream::IsFinished()
|
||||
{
|
||||
return m_bFinished;
|
||||
}
|
||||
|
||||
// returns the number of bytes read so far (the whole buffer size if IsFinished())
|
||||
unsigned int CReadStream::GetBytesRead ([[maybe_unused]] bool bWait)
|
||||
{
|
||||
if (!m_bError)
|
||||
{
|
||||
return m_Params.nSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// returns the buffer into which the data has been or will be read
|
||||
// at least GetBytesRead() bytes in this buffer are guaranteed to be already read
|
||||
const void* CReadStream::GetBuffer ()
|
||||
{
|
||||
return m_pBuffer;
|
||||
}
|
||||
|
||||
void CReadStream::AbortShutdown()
|
||||
{
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
m_bError = true;
|
||||
m_nIOError = ERROR_ABORTED_ON_SHUTDOWN;
|
||||
m_bFileRequestComplete = true;
|
||||
|
||||
if (m_pFileRequest)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
}
|
||||
|
||||
// lock this object to avoid preliminary destruction
|
||||
CReadStream_AutoPtr pLock(this);
|
||||
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
// all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
|
||||
m_pCallback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// tries to stop reading the stream; this is advisory and may have no effect
|
||||
// all the callbacks will be called after this. If you just destructing object,
|
||||
// dereference this object and it will automatically abort and release all associated resources.
|
||||
void CReadStream::Abort()
|
||||
{
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
m_bError = true;
|
||||
m_nIOError = ERROR_USER_ABORT;
|
||||
m_bFileRequestComplete = true;
|
||||
|
||||
if (m_pFileRequest)
|
||||
{
|
||||
m_pFileRequest->Cancel();
|
||||
m_pFileRequest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// lock this object to avoid preliminary destruction
|
||||
CReadStream_AutoPtr pLock(this);
|
||||
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
// all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
|
||||
m_pCallback = NULL;
|
||||
}
|
||||
|
||||
m_pEngine->AbortJob(this);
|
||||
}
|
||||
|
||||
bool CReadStream::TryAbort()
|
||||
{
|
||||
if (!m_callbackLock.TryLock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pFileRequest && !m_pFileRequest->TryCancel())
|
||||
{
|
||||
m_callbackLock.Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bError = true;
|
||||
m_nIOError = ERROR_USER_ABORT;
|
||||
m_bFileRequestComplete = true;
|
||||
m_pFileRequest = 0;
|
||||
|
||||
// lock this object to avoid preliminary destruction
|
||||
CReadStream_AutoPtr pLock(this);
|
||||
|
||||
// all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
|
||||
m_pCallback = NULL;
|
||||
|
||||
m_callbackLock.Unlock();
|
||||
|
||||
m_pEngine->AbortJob(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// tries to raise the priority of the read; this is advisory and may have no effect
|
||||
void CReadStream::SetPriority (EStreamTaskPriority ePriority)
|
||||
{
|
||||
if (m_Params.ePriority != ePriority)
|
||||
{
|
||||
m_Params.ePriority = ePriority;
|
||||
if (m_pFileRequest && m_pFileRequest->m_status == CAsyncIOFileRequest::eStatusInFileQueue)
|
||||
{
|
||||
m_pEngine->UpdateJobPriority(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unconditionally waits until the callback is called
|
||||
// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback
|
||||
// is called before return from this function (unless no callback was specified)
|
||||
void CReadStream::Wait(int nMaxWaitMillis)
|
||||
{
|
||||
// lock this object to avoid preliminary destruction
|
||||
CReadStream_AutoPtr pLock(this);
|
||||
|
||||
bool bNeedFinalize = (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK) == 0;
|
||||
|
||||
if (!m_bFinished && !m_bError && !m_pFileRequest)
|
||||
{
|
||||
assert(m_pFileRequest != NULL); // If we want to Wait for stream its file request must not be NULL.
|
||||
// This will almost certainly cause Dead-Lock
|
||||
CryFatalError("Waiting for stream when StreamingEngine is paused");
|
||||
}
|
||||
|
||||
CTimeValue t0;
|
||||
|
||||
if (nMaxWaitMillis > 0)
|
||||
{
|
||||
t0 = gEnv->pTimer->GetAsyncTime();
|
||||
}
|
||||
|
||||
while (!m_bFinished && !m_bError)
|
||||
{
|
||||
if (bNeedFinalize)
|
||||
{
|
||||
m_pEngine->MainThread_FinalizeIOJobs();
|
||||
}
|
||||
if (!m_bFileRequestComplete)
|
||||
{
|
||||
CrySleep(5);
|
||||
}
|
||||
|
||||
if (nMaxWaitMillis > 0)
|
||||
{
|
||||
CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
|
||||
if (CTimeValue(t1 - t0).GetMilliSeconds() > nMaxWaitMillis)
|
||||
{
|
||||
// Break if we are waiting for too long.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
uint64 CReadStream::GetPriority() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this gets called upon the IO has been executed to call the callbacks
|
||||
void CReadStream::MainThread_Finalize()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
// call asynchronous callback function if needed synchronously
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
ExecuteSyncCallback_CBLocked();
|
||||
}
|
||||
m_pFileRequest = 0;
|
||||
}
|
||||
|
||||
IStreamCallback* CReadStream::GetCallback() const
|
||||
{
|
||||
return m_pCallback;
|
||||
}
|
||||
|
||||
unsigned CReadStream::GetError() const
|
||||
{
|
||||
return m_nIOError;
|
||||
}
|
||||
|
||||
const char* CReadStream::GetErrorName() const
|
||||
{
|
||||
switch (m_nIOError)
|
||||
{
|
||||
case ERROR_UNKNOWN_ERROR:
|
||||
return "Unknown error";
|
||||
case ERROR_UNEXPECTED_DESTRUCTION:
|
||||
return "Unexpected destruction";
|
||||
case ERROR_INVALID_CALL:
|
||||
return "Invalid call";
|
||||
case ERROR_CANT_OPEN_FILE:
|
||||
return "Cannot open the file";
|
||||
case ERROR_REFSTREAM_ERROR:
|
||||
return "Refstream error";
|
||||
case ERROR_OFFSET_OUT_OF_RANGE:
|
||||
return "Offset out of range";
|
||||
case ERROR_REGION_OUT_OF_RANGE:
|
||||
return "Region out of range";
|
||||
case ERROR_SIZE_OUT_OF_RANGE:
|
||||
return "Size out of range";
|
||||
case ERROR_CANT_START_READING:
|
||||
return "Cannot start reading";
|
||||
case ERROR_OUT_OF_MEMORY:
|
||||
return "Out of memory";
|
||||
case ERROR_ABORTED_ON_SHUTDOWN:
|
||||
return "Aborted on shutdown";
|
||||
case ERROR_OUT_OF_MEMORY_QUOTA:
|
||||
return "Out of memory quota";
|
||||
case ERROR_ZIP_CACHE_FAILURE:
|
||||
return "ZIP cache failure";
|
||||
case ERROR_USER_ABORT:
|
||||
return "User aborted";
|
||||
}
|
||||
return "Unrecognized error";
|
||||
}
|
||||
|
||||
int CReadStream::AddRef()
|
||||
{
|
||||
return CryInterlockedIncrement(&m_nRefCount);
|
||||
}
|
||||
|
||||
int CReadStream::Release()
|
||||
{
|
||||
int nRef = CryInterlockedDecrement(&m_nRefCount);
|
||||
|
||||
#ifndef _RELEASE
|
||||
if (nRef < 0)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nRef == 0)
|
||||
{
|
||||
Reset();
|
||||
CryInterlockedPushEntrySList(s_freeRequests, m_nextFree);
|
||||
}
|
||||
|
||||
return nRef;
|
||||
}
|
||||
|
||||
void CReadStream::Reset()
|
||||
{
|
||||
m_strFileName.clear();
|
||||
m_pFileRequest = NULL;
|
||||
m_Params = StreamReadParams();
|
||||
memset((void*)&m_nRefCount, 0, (char*)(this + 1) - (char*)(&m_nRefCount));
|
||||
}
|
||||
|
||||
void CReadStream::SetUserData(DWORD_PTR dwUserData)
|
||||
{
|
||||
m_Params.dwUserData = dwUserData;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CReadStream::ExecuteAsyncCallback_CBLocked()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
if (!m_bIsAsyncCallbackExecuted && m_pCallback)
|
||||
{
|
||||
m_bIsAsyncCallbackExecuted = true;
|
||||
m_pCallback->StreamAsyncOnComplete(this, m_nIOError);
|
||||
}
|
||||
}
|
||||
|
||||
void CReadStream::ExecuteSyncCallback_CBLocked()
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM);
|
||||
|
||||
if (!m_bIsSyncCallbackExecuted && m_pCallback && (0 == (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK)))
|
||||
{
|
||||
m_bIsSyncCallbackExecuted = true;
|
||||
|
||||
CReadStream_AutoPtr protectMe(this); // Stream can be freed inside the callback!
|
||||
|
||||
m_pCallback->StreamOnComplete(this, m_nIOError);
|
||||
|
||||
// We do not need FileRequest here anymore, and not its temporary memory.
|
||||
m_pFileRequest = 0;
|
||||
m_pBuffer = NULL;
|
||||
m_bFinished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFileRequest = 0;
|
||||
m_pBuffer = NULL;
|
||||
m_bFinished = true;
|
||||
}
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_LISTENER
|
||||
IStreamEngineListener* pListener = m_pEngine->GetListener();
|
||||
if (pListener)
|
||||
{
|
||||
pListener->OnStreamDone(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void* CReadStream::operator new (size_t sz)
|
||||
{
|
||||
return CryModuleMemalign(sz, alignof(CReadStream));
|
||||
}
|
||||
|
||||
void CReadStream::operator delete(void* p)
|
||||
{
|
||||
CryModuleMemalignFree(p);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CReadStream::FreeTemporaryMemory()
|
||||
{
|
||||
// Free temporary block.
|
||||
if (m_pFileRequest)
|
||||
{
|
||||
m_pFileRequest->SyncWithDecompress();
|
||||
m_pFileRequest->FreeBuffer();
|
||||
}
|
||||
m_pBuffer = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CReadStream::IsReqReading()
|
||||
{
|
||||
if (m_strFileName.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CAsyncIOFileRequest* CReadStream::CreateFileRequest()
|
||||
{
|
||||
m_pFileRequest = CAsyncIOFileRequest::Allocate(m_Type);
|
||||
m_pFileRequest->m_nRequestedSize = m_Params.nSize;
|
||||
m_pFileRequest->m_nRequestedOffset = m_Params.nOffset;
|
||||
m_pFileRequest->m_pExternalMemoryBuffer = m_pBuffer;
|
||||
m_pFileRequest->m_bWriteOnlyExternal = (m_Params.nFlags & IStreamEngine::FLAGS_WRITE_ONLY_EXTERNAL_BUFFER) != 0;
|
||||
m_pFileRequest->m_pReadStream = this;
|
||||
m_pFileRequest->m_strFileName = m_strFileName;
|
||||
m_pFileRequest->m_ePriority = m_Params.ePriority;
|
||||
m_pFileRequest->m_eMediaType = m_Params.eMediaType;
|
||||
|
||||
m_bFileRequestComplete = false;
|
||||
return m_pFileRequest;
|
||||
}
|
||||
|
||||
void* CReadStream::OnNeedStorage(size_t size, bool& bAbortOnFailToAlloc)
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
if (m_pCallback)
|
||||
{
|
||||
return m_pCallback->StreamOnNeedStorage(this, size, bAbortOnFailToAlloc);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CReadStream::OnAsyncFileRequestComplete()
|
||||
{
|
||||
CryAutoCriticalSection lock(m_callbackLock);
|
||||
|
||||
if (!m_bFileRequestComplete)
|
||||
{
|
||||
if (m_pFileRequest)
|
||||
{
|
||||
m_Params.nSize = m_pFileRequest->m_nRequestedSize;
|
||||
m_pBuffer = m_pFileRequest->m_pOutputMemoryBuffer;
|
||||
m_nBytesRead = m_pFileRequest->m_nSizeOnMedia;
|
||||
m_nIOError = m_pFileRequest->m_nError;
|
||||
m_bError = m_nIOError != 0;
|
||||
if (m_bError)
|
||||
{
|
||||
m_nBytesRead = 0;
|
||||
}
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
m_ReadTime = m_pFileRequest->m_readTime;
|
||||
#endif
|
||||
}
|
||||
|
||||
ExecuteAsyncCallback_CBLocked();
|
||||
|
||||
if (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK)
|
||||
{
|
||||
// We do not need FileRequest here anymore, and not its temporary memory.
|
||||
m_pFileRequest = 0;
|
||||
m_bFinished = true;
|
||||
}
|
||||
|
||||
m_bFileRequestComplete = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Streaming Engine
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "IStreamEngine.h"
|
||||
#include "StreamAsyncFileRequest.h"
|
||||
|
||||
class CStreamEngine;
|
||||
|
||||
class CReadStream
|
||||
: public IReadStream
|
||||
{
|
||||
friend class CStreamEngine;
|
||||
|
||||
public:
|
||||
static CReadStream* Allocate(CStreamEngine* pEngine, const EStreamTaskType tSource, const char* szFilename, IStreamCallback* pCallback, const StreamReadParams* pParams);
|
||||
static void Flush();
|
||||
|
||||
public:
|
||||
CReadStream();
|
||||
virtual ~CReadStream ();
|
||||
|
||||
virtual int AddRef();
|
||||
virtual int Release();
|
||||
|
||||
virtual DWORD_PTR GetUserData() {return m_Params.dwUserData; }
|
||||
|
||||
// set user defined data into stream's params
|
||||
virtual void SetUserData(DWORD_PTR dwUserData);
|
||||
|
||||
// returns true if the file read was not successful.
|
||||
virtual bool IsError() { return m_bError; };
|
||||
|
||||
// returns true if the file read was completed (successfully or unsuccessfully)
|
||||
// check IsError to check if the whole requested file (piece) was read
|
||||
virtual bool IsFinished();
|
||||
|
||||
// returns the number of bytes read so far (the whole buffer size if IsFinished())
|
||||
virtual unsigned int GetBytesRead (bool bWait);
|
||||
|
||||
// returns the buffer into which the data has been or will be read
|
||||
// at least GetBytesRead() bytes in this buffer are guaranteed to be already read
|
||||
virtual const void* GetBuffer ();
|
||||
|
||||
void AbortShutdown();
|
||||
|
||||
// tries to stop reading the stream; this is advisory and may have no effect
|
||||
// but the callback will not be called after this. If you just destructing object,
|
||||
// dereference this object and it will automatically abort and release all associated resources.
|
||||
virtual void Abort();
|
||||
virtual bool TryAbort();
|
||||
|
||||
// tries to raise the priority of the read; this is advisory and may have no effect
|
||||
virtual void SetPriority (EStreamTaskPriority EPriority);
|
||||
|
||||
// unconditionally waits until the callback is called
|
||||
// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback
|
||||
// is called before return from this function (unless no callback was specified)
|
||||
virtual void Wait(int nMaxWaitMillis = -1);
|
||||
|
||||
virtual uint64 GetPriority() const;
|
||||
|
||||
virtual const StreamReadParams& GetParams() const {return m_Params; }
|
||||
|
||||
virtual const EStreamTaskType GetCallerType() const { return m_Type; }
|
||||
|
||||
virtual EStreamSourceMediaType GetMediaType() const { return m_MediaType; }
|
||||
|
||||
// return pointer to callback routine(can be NULL)
|
||||
virtual IStreamCallback* GetCallback() const;
|
||||
|
||||
// return IO error #
|
||||
virtual unsigned GetError() const;
|
||||
|
||||
// Returns IO error name
|
||||
virtual const char* GetErrorName() const;
|
||||
|
||||
// return stream name
|
||||
virtual const char* GetName() const { return m_strFileName.c_str(); };
|
||||
|
||||
virtual void FreeTemporaryMemory();
|
||||
|
||||
// this gets called upon the IO has been executed to call the callbacks
|
||||
void MainThread_Finalize();
|
||||
|
||||
bool IsReqReading();
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
void SetRequestTime(CTimeValue& time) { m_requestTime = time; }
|
||||
const CTimeValue& GetRequestTime() { return m_requestTime; }
|
||||
#endif
|
||||
|
||||
// decompression of zip-compressed files with default behavior
|
||||
CAsyncIOFileRequest* CreateFileRequest();
|
||||
void ComputedMediaType(EStreamSourceMediaType eMT) { m_MediaType = eMT; }
|
||||
void* OnNeedStorage(size_t size, bool& bAbortOnFailToAlloc);
|
||||
void OnAsyncFileRequestComplete();
|
||||
CAsyncIOFileRequest* GetFileRequest() { return m_pFileRequest; }
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
||||
// call the async callback
|
||||
void ExecuteAsyncCallback_CBLocked();
|
||||
|
||||
// call the sync callback
|
||||
void ExecuteSyncCallback_CBLocked();
|
||||
|
||||
private:
|
||||
void* operator new (size_t sz);
|
||||
void operator delete(void* p);
|
||||
|
||||
private:
|
||||
static SLockFreeSingleLinkedListHeader s_freeRequests;
|
||||
|
||||
private:
|
||||
STREAMENGINE_LL_ALIGN SLockFreeSingleLinkedListEntry m_nextFree;
|
||||
|
||||
CryStringLocal m_strFileName;
|
||||
CryCriticalSection m_callbackLock;
|
||||
CAsyncIOFileRequest_AutoPtr m_pFileRequest;
|
||||
|
||||
StreamReadParams m_Params;
|
||||
|
||||
// Only POD types must exist below here. They will be memset!
|
||||
|
||||
volatile int m_nRefCount;
|
||||
CStreamEngine* m_pEngine;
|
||||
|
||||
// the type of the task
|
||||
EStreamTaskType m_Type;
|
||||
EStreamSourceMediaType m_MediaType;
|
||||
// the initial data from the user
|
||||
// the callback; may be NULL
|
||||
IStreamCallback* m_pCallback;
|
||||
|
||||
// Bytes actually read from media.
|
||||
uint32 m_nBytesRead;
|
||||
|
||||
volatile bool m_bIsAsyncCallbackExecuted;
|
||||
volatile bool m_bIsSyncCallbackExecuted;
|
||||
volatile bool m_bFileRequestComplete;
|
||||
|
||||
// the actual buffer to read to
|
||||
void* m_pBuffer;
|
||||
|
||||
volatile bool m_bError;
|
||||
volatile bool m_bFinished;
|
||||
unsigned int m_nIOError;
|
||||
|
||||
#ifdef STREAMENGINE_ENABLE_STATS
|
||||
// time when request was made
|
||||
CTimeValue m_requestTime;
|
||||
// Time for actual reading
|
||||
CTimeValue m_ReadTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(CReadStream);
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H
|
||||
@@ -135,14 +135,12 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
#include "XML/xml.h"
|
||||
#include "XML/ReadWriteXMLSink.h"
|
||||
|
||||
#include "StreamEngine/StreamEngine.h"
|
||||
#include "PhysRenderer.h"
|
||||
|
||||
#include "LocalizedStringManager.h"
|
||||
#include "XML/XmlUtils.h"
|
||||
#include "SystemEventDispatcher.h"
|
||||
#include "ServerThrottle.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "HMDBus.h"
|
||||
|
||||
#include "IZLibCompressor.h"
|
||||
@@ -157,7 +155,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
#include "CryWaterMark.h"
|
||||
WATERMARKDATA(_m);
|
||||
|
||||
#include "ImageHandler.h"
|
||||
#include <LyShine/Bus/UiCursorBus.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/Input/Buses/Requests/InputSystemRequestBus.h>
|
||||
@@ -179,7 +176,6 @@ WATERMARKDATA(_m);
|
||||
|
||||
#include <ILevelSystem.h>
|
||||
|
||||
#include <CrtDebugStats.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
// profilers api.
|
||||
@@ -191,14 +187,6 @@ SSystemCVars g_cvars;
|
||||
|
||||
#include "ITextModeConsole.h"
|
||||
|
||||
extern int CryMemoryGetAllocatedSize();
|
||||
|
||||
// these heaps are used by underlying System structures
|
||||
// to allocate, accordingly, small (like elements of std::set<..*>) and big (like memory for reading files) objects
|
||||
// hopefully someday we'll have standard MT-safe heap
|
||||
//CMTSafeHeap g_pakHeap;
|
||||
CMTSafeHeap* g_pPakHeap = 0;// = &g_pakHeap;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#include "Validator.h"
|
||||
|
||||
@@ -266,7 +254,6 @@ namespace
|
||||
// System Implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
|
||||
: m_imageHandler(std::make_unique<ImageHandler>())
|
||||
{
|
||||
CrySystemRequestBus::Handler::BusConnect();
|
||||
|
||||
@@ -307,8 +294,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
|
||||
m_env.pSharedEnvironment = pSharedEnvironment;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
m_pStreamEngine = NULL;
|
||||
|
||||
m_pIFont = NULL;
|
||||
m_pIFontUi = NULL;
|
||||
m_rWidth = NULL;
|
||||
@@ -322,7 +307,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
|
||||
m_rStencilBits = NULL;
|
||||
m_rFullscreen = NULL;
|
||||
m_sysNoUpdate = NULL;
|
||||
m_pMemoryManager = NULL;
|
||||
m_pProcess = NULL;
|
||||
|
||||
m_pValidator = NULL;
|
||||
@@ -387,12 +371,8 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
|
||||
|
||||
|
||||
m_pXMLUtils = new CXmlUtils(this);
|
||||
m_pMemoryManager = CryGetIMemoryManager();
|
||||
m_pResourceManager = new CResourceManager;
|
||||
m_pTextModeConsole = NULL;
|
||||
|
||||
g_pPakHeap = new CMTSafeHeap;
|
||||
|
||||
if (!AZ::AllocatorInstance<AZ::OSAllocator>::IsReady())
|
||||
{
|
||||
m_initedOSAllocator = true;
|
||||
@@ -433,11 +413,8 @@ CSystem::~CSystem()
|
||||
CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere");
|
||||
|
||||
SAFE_DELETE(m_pXMLUtils);
|
||||
SAFE_DELETE(m_pResourceManager);
|
||||
SAFE_DELETE(m_pSystemEventDispatcher);
|
||||
|
||||
SAFE_DELETE(g_pPakHeap);
|
||||
|
||||
AZCoreLogSink::Disconnect();
|
||||
if (m_initedSysAllocator)
|
||||
{
|
||||
@@ -477,12 +454,6 @@ void CSystem::FreeLib(AZStd::unique_ptr<AZ::DynamicModuleHandle>& hLibModule)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IStreamEngine* CSystem::GetStreamEngine()
|
||||
{
|
||||
return m_pStreamEngine;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IRemoteConsole* CSystem::GetIRemoteConsole()
|
||||
{
|
||||
@@ -582,9 +553,6 @@ void CSystem::ShutDown()
|
||||
// Shutdown any running VR devices.
|
||||
EBUS_EVENT(AZ::VR::HMDInitRequestBus, Shutdown);
|
||||
|
||||
// Shutdown resource manager.
|
||||
m_pResourceManager->Shutdown();
|
||||
|
||||
if (gEnv && gEnv->pLyShine)
|
||||
{
|
||||
gEnv->pLyShine->Release();
|
||||
@@ -645,11 +613,6 @@ void CSystem::ShutDown()
|
||||
|
||||
SAFE_DELETE(m_pLocalizationManager);
|
||||
|
||||
//DebugStats(false, false);//true);
|
||||
//CryLogAlways("");
|
||||
//CryLogAlways("release mode memory manager stats:");
|
||||
//DumpMMStats(true);
|
||||
|
||||
SAFE_DELETE(m_pCpu);
|
||||
|
||||
delete m_pCmdLine;
|
||||
@@ -659,8 +622,7 @@ void CSystem::ShutDown()
|
||||
// Shut down audio as late as possible but before the streaming system and console get released!
|
||||
Audio::Gem::AudioSystemGemRequestBus::Broadcast(&Audio::Gem::AudioSystemGemRequestBus::Events::Release);
|
||||
|
||||
// Shut down the streaming system and console as late as possible and after audio!
|
||||
SAFE_DELETE(m_pStreamEngine);
|
||||
// Shut down console as late as possible and after audio!
|
||||
SAFE_RELEASE(m_env.pConsole);
|
||||
|
||||
// Log must be last thing released.
|
||||
@@ -904,12 +866,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
}
|
||||
#endif //PROFILE_WITH_VTUNE
|
||||
|
||||
if (m_pStreamEngine)
|
||||
{
|
||||
FRAME_PROFILER("StreamEngine::Update()", this, PROFILE_SYSTEM);
|
||||
m_pStreamEngine->Update();
|
||||
}
|
||||
|
||||
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
|
||||
if (m_bIgnoreUpdates)
|
||||
{
|
||||
@@ -1024,14 +980,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Update Resource Manager.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
{
|
||||
FRAME_PROFILER("SysUpdate:ResourceManager", this, PROFILE_SYSTEM);
|
||||
m_pResourceManager->Update();
|
||||
}
|
||||
|
||||
// Use UI timer for CryMovie, because it should not be affected by pausing game time
|
||||
const float fMovieFrameTime = m_Time.GetFrameTime(ITimer::ETIMER_UI);
|
||||
|
||||
@@ -1419,24 +1367,12 @@ void CSystem::Relaunch(bool bRelaunch)
|
||||
SaveConfiguration();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
uint32 CSystem::GetUsedMemory()
|
||||
{
|
||||
return CryMemoryGetAllocatedSize();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ILocalizationManager* CSystem::GetLocalizationManager()
|
||||
{
|
||||
return m_pLocalizationManager;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IResourceManager* CSystem::GetIResourceManager()
|
||||
{
|
||||
return m_pResourceManager;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CSystem::debug_GetCallStackRaw(void** callstack, uint32& callstackLength)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "CmdLine.h"
|
||||
#include "CryName.h"
|
||||
|
||||
#include "MTSafeAllocator.h"
|
||||
#include "CPUDetect.h"
|
||||
#include <AzFramework/Archive/ArchiveVars.h>
|
||||
#include "RenderBus.h"
|
||||
@@ -276,33 +275,6 @@ extern SSystemCVars g_cvars;
|
||||
|
||||
class CSystem;
|
||||
|
||||
struct SmallModuleInfo
|
||||
{
|
||||
string name;
|
||||
CryModuleMemoryInfo memInfo;
|
||||
};
|
||||
|
||||
struct SCryEngineStatsModuleInfo
|
||||
{
|
||||
string name;
|
||||
CryModuleMemoryInfo memInfo;
|
||||
uint32 moduleStaticSize;
|
||||
uint32 usedInModule;
|
||||
uint32 SizeOfCode;
|
||||
uint32 SizeOfInitializedData;
|
||||
uint32 SizeOfUninitializedData;
|
||||
};
|
||||
|
||||
struct SCryEngineStatsGlobalMemInfo
|
||||
{
|
||||
int totalUsedInModules;
|
||||
int totalCodeAndStatic;
|
||||
int countedMemoryModules;
|
||||
uint64 totalAllocatedInModules;
|
||||
int totalNumAllocsInModules;
|
||||
std::vector<SCryEngineStatsModuleInfo> modules;
|
||||
};
|
||||
|
||||
struct CProfilingSystem
|
||||
: public IProfilingSystem
|
||||
{
|
||||
@@ -338,17 +310,6 @@ class CSystem
|
||||
, public CrySystemRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
inline void* operator new(std::size_t)
|
||||
{
|
||||
size_t allocated = 0;
|
||||
return CryMalloc(sizeof(CSystem), allocated, 64);
|
||||
}
|
||||
inline void operator delete(void* p)
|
||||
{
|
||||
CryFree(p, 64);
|
||||
}
|
||||
|
||||
CSystem(SharedEnvironmentInstance* pSharedEnvironment);
|
||||
~CSystem();
|
||||
|
||||
@@ -390,8 +351,6 @@ public:
|
||||
ISystem* GetCrySystem() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32 GetUsedMemory();
|
||||
|
||||
virtual bool SteamInit();
|
||||
|
||||
void Relaunch(bool bRelaunch);
|
||||
@@ -412,17 +371,14 @@ public:
|
||||
IConsole* GetIConsole() { return m_env.pConsole; };
|
||||
IRemoteConsole* GetIRemoteConsole();
|
||||
IMovieSystem* GetIMovieSystem() { return m_env.pMovieSystem; };
|
||||
IMemoryManager* GetIMemoryManager(){ return m_pMemoryManager; }
|
||||
ICryFont* GetICryFont(){ return m_env.pCryFont; }
|
||||
ILog* GetILog(){ return m_env.pLog; }
|
||||
ICmdLine* GetICmdLine(){ return m_pCmdLine; }
|
||||
IStreamEngine* GetStreamEngine();
|
||||
IValidator* GetIValidator() { return m_pValidator; };
|
||||
INameTable* GetINameTable() { return m_env.pNameTable; };
|
||||
IViewSystem* GetIViewSystem();
|
||||
ILevelSystem* GetILevelSystem();
|
||||
ISystemEventDispatcher* GetISystemEventDispatcher() { return m_pSystemEventDispatcher; }
|
||||
IResourceManager* GetIResourceManager();
|
||||
ITextModeConsole* GetITextModeConsole();
|
||||
IProfilingSystem* GetIProfilingSystem() { return &m_ProfilingSystem; }
|
||||
IZLibCompressor* GetIZLibCompressor() { return m_pIZLibCompressor; }
|
||||
@@ -509,11 +465,6 @@ public:
|
||||
virtual int ShowMessage(const char* text, const char* caption, unsigned int uType);
|
||||
bool CheckLogVerbosity(int verbosity);
|
||||
|
||||
virtual void DebugStats(bool checkpoint, bool leaks);
|
||||
void DumpWinHeaps();
|
||||
|
||||
virtual int DumpMMStats(bool log);
|
||||
|
||||
//! Return pointer to user defined callback.
|
||||
ISystemUserCallback* GetUserCallback() const { return m_pUserCallback; };
|
||||
|
||||
@@ -541,8 +492,6 @@ public:
|
||||
void SetVersionInfo(const char* const szVersion);
|
||||
#endif
|
||||
|
||||
virtual const IImageHandler* GetImageHandler() const override { return m_imageHandler.get(); }
|
||||
|
||||
void ShutdownModuleLibraries();
|
||||
|
||||
#if defined(WIN32)
|
||||
@@ -570,7 +519,6 @@ private:
|
||||
bool InitConsole();
|
||||
bool InitFileSystem();
|
||||
bool InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams);
|
||||
bool InitStreamEngine();
|
||||
bool InitAudioSystem(const SSystemInitParams& initParams);
|
||||
bool InitShine(const SSystemInitParams& initParams);
|
||||
|
||||
@@ -597,7 +545,6 @@ private:
|
||||
#endif // #ifndef _RELEASE
|
||||
|
||||
bool ReLaunchMediaCenter();
|
||||
void LogSystemInfo();
|
||||
void UpdateAudioSystems();
|
||||
|
||||
void AddCVarGroupDirectory(const string& sPath);
|
||||
@@ -690,14 +637,9 @@ private: // ------------------------------------------------------
|
||||
|
||||
std::map<CCryNameCRC, AZStd::unique_ptr<AZ::DynamicModuleHandle> > m_moduleDLLHandles;
|
||||
|
||||
//! THe streaming engine
|
||||
class CStreamEngine* m_pStreamEngine;
|
||||
|
||||
//! current active process
|
||||
IProcess* m_pProcess;
|
||||
|
||||
IMemoryManager* m_pMemoryManager;
|
||||
|
||||
CCamera m_PhysRendererCamera;
|
||||
ICVar* m_p_draw_helpers_str;
|
||||
int m_iJumpToPhysProfileEnt;
|
||||
@@ -914,7 +856,6 @@ public:
|
||||
protected: // -------------------------------------------------------------
|
||||
|
||||
CCmdLine* m_pCmdLine;
|
||||
class CResourceManager* m_pResourceManager;
|
||||
ITextModeConsole* m_pTextModeConsole;
|
||||
|
||||
string m_currentLanguageAudio;
|
||||
@@ -943,7 +884,6 @@ protected: // -------------------------------------------------------------
|
||||
|
||||
bool m_bIsSteamInitialized;
|
||||
|
||||
std::unique_ptr<IImageHandler> m_imageHandler;
|
||||
std::vector<IWindowMessageHandler*> m_windowMessageHandlers;
|
||||
bool m_initedOSAllocator = false;
|
||||
bool m_initedSysAllocator = false;
|
||||
|
||||
@@ -95,7 +95,6 @@
|
||||
#include "XConsole.h"
|
||||
#include "Log.h"
|
||||
#include "XML/xml.h"
|
||||
#include "StreamEngine/StreamEngine.h"
|
||||
#include "PhysRenderer.h"
|
||||
#include "LocalizedStringManager.h"
|
||||
#include "SystemEventDispatcher.h"
|
||||
@@ -103,8 +102,6 @@
|
||||
#include "ServerThrottle.h"
|
||||
#include "SystemCFG.h"
|
||||
#include "AutoDetectSpec.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "MTSafeAllocator.h"
|
||||
#include "ZLibCompressor.h"
|
||||
#include "ZLibDecompressor.h"
|
||||
#include "ZStdDecompressor.h"
|
||||
@@ -245,8 +242,6 @@ CUNIXConsole* pUnixConsole;
|
||||
|
||||
#define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow()
|
||||
|
||||
extern CMTSafeHeap* g_pPakHeap;
|
||||
|
||||
#ifdef WIN32
|
||||
extern HMODULE gDLLHandle;
|
||||
#endif
|
||||
@@ -274,7 +269,6 @@ struct SCVarsClientConfigSink
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static inline void InlineInitializationProcessing([[maybe_unused]] const char* sDescription)
|
||||
{
|
||||
assert(CryMemory::IsHeapValid());
|
||||
if (gEnv->pLog)
|
||||
{
|
||||
gEnv->pLog->UpdateLoadingScreen(0);
|
||||
@@ -1101,12 +1095,7 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
|
||||
auto projectName = AZ::Utils::GetProjectName();
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str());
|
||||
|
||||
// simply open all paks if fast load pak can't be found
|
||||
if (!m_pResourceManager->LoadFastLoadPaks(true))
|
||||
{
|
||||
OpenBasicPaks();
|
||||
}
|
||||
|
||||
OpenBasicPaks();
|
||||
|
||||
// Load game-specific folder.
|
||||
LoadConfiguration("game.cfg");
|
||||
@@ -1120,21 +1109,6 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
|
||||
return (true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitStreamEngine()
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
if (m_pUserCallback)
|
||||
{
|
||||
m_pUserCallback->OnInitProgress("Initializing Stream Engine...");
|
||||
}
|
||||
|
||||
m_pStreamEngine = new CStreamEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::InitAudioSystem(const SSystemInitParams& initParams)
|
||||
{
|
||||
@@ -1299,8 +1273,6 @@ void CSystem::OpenBasicPaks()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char* const assetsDir = "@assets@";
|
||||
const char* shaderCachePakDir = "@assets@/shadercache.pak";
|
||||
const char* shaderCacheStartupPakDir = "@assets@/shadercachestartup.pak";
|
||||
|
||||
// After game paks to have same search order as with files on disk
|
||||
m_env.pCryPak->OpenPack(assetsDir, "Engine.pak");
|
||||
@@ -1310,11 +1282,6 @@ void CSystem::OpenBasicPaks()
|
||||
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
|
||||
#endif
|
||||
|
||||
m_env.pCryPak->OpenPack(assetsDir, shaderCachePakDir);
|
||||
m_env.pCryPak->OpenPack(assetsDir, shaderCacheStartupPakDir);
|
||||
m_env.pCryPak->OpenPack(assetsDir, "Shaders.pak");
|
||||
m_env.pCryPak->OpenPack(assetsDir, "ShadersBin.pak");
|
||||
|
||||
#ifdef AZ_PLATFORM_ANDROID
|
||||
// Load Android Obb files if available
|
||||
const char* obbStorage = AZ::Android::Utils::GetObbStoragePath();
|
||||
@@ -1326,22 +1293,6 @@ void CSystem::OpenBasicPaks()
|
||||
|
||||
InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( Engine... )");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Open paks in MOD subfolders.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(_RELEASE)
|
||||
if (const ICmdLineArg* pModArg = GetICmdLine()->FindArg(eCLAT_Pre, "MOD"))
|
||||
{
|
||||
if (IsMODValid(pModArg->GetValue()))
|
||||
{
|
||||
AZStd::string modFolder = "Mods\\";
|
||||
modFolder += pModArg->GetValue();
|
||||
modFolder += "\\*.pak";
|
||||
GetIPak()->OpenPacks(assetsDir, modFolder, AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK);
|
||||
}
|
||||
}
|
||||
#endif // !defined(_RELEASE)
|
||||
|
||||
// Load paks required for game init to mem
|
||||
gEnv->pCryPak->LoadPakToMemory("Engine.pak", AZ::IO::IArchive::eInMemoryPakLocale_GPU);
|
||||
}
|
||||
@@ -1687,8 +1638,6 @@ bool CSystem::Init(const SSystemInitParams& startupParams)
|
||||
m_systemConfigName += ".cfg";
|
||||
}
|
||||
|
||||
AZ_Assert(CryMemory::IsHeapValid(), "Memory heap must be valid before continuing SystemInit.");
|
||||
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
// check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this
|
||||
{
|
||||
@@ -1709,8 +1658,6 @@ AZ_POP_DISABLE_WARNING
|
||||
}
|
||||
#endif
|
||||
|
||||
m_pResourceManager->Init();
|
||||
|
||||
// Get file version information.
|
||||
QueryVersionInfo();
|
||||
DetectGameFolderAccessRights();
|
||||
@@ -1983,11 +1930,6 @@ AZ_POP_DISABLE_WARNING
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!startupParams.bSkipConsole)
|
||||
{
|
||||
LogSystemInfo();
|
||||
}
|
||||
|
||||
InlineInitializationProcessing("CSystem::Init Load Engine Folders");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -2052,29 +1994,6 @@ AZ_POP_DISABLE_WARNING
|
||||
gEnv->bNoAssertDialog = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Stream Engine
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Stream Engine Initialization");
|
||||
InitStreamEngine();
|
||||
InlineInitializationProcessing("CSystem::Init StreamEngine");
|
||||
|
||||
|
||||
{
|
||||
if (m_pCmdLine->FindArg(eCLAT_Pre, "NullRenderer"))
|
||||
{
|
||||
m_env.pConsole->LoadConfigVar("r_Driver", "NULL");
|
||||
}
|
||||
else if (m_pCmdLine->FindArg(eCLAT_Pre, "DX11"))
|
||||
{
|
||||
m_env.pConsole->LoadConfigVar("r_Driver", "DX11");
|
||||
}
|
||||
else if (m_pCmdLine->FindArg(eCLAT_Pre, "GL"))
|
||||
{
|
||||
m_env.pConsole->LoadConfigVar("r_Driver", "GL");
|
||||
}
|
||||
}
|
||||
|
||||
LogBuildInfo();
|
||||
|
||||
InlineInitializationProcessing("CSystem::Init LoadConfigurations");
|
||||
|
||||
@@ -47,13 +47,10 @@
|
||||
#define SYSTEMRENDERER_CPP_SECTION_2 2
|
||||
#endif
|
||||
|
||||
extern CMTSafeHeap* g_pPakHeap;
|
||||
#if defined(AZ_PLATFORM_ANDROID)
|
||||
#include <AzCore/Android/Utils.h>
|
||||
#endif
|
||||
|
||||
extern int CryMemoryGetAllocatedSize();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::GetPrimaryPhysicalDisplayDimensions([[maybe_unused]] int& o_widthPixels, [[maybe_unused]] int& o_heightPixels)
|
||||
{
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#endif
|
||||
|
||||
#include "XConsole.h"
|
||||
#include "StreamEngine/StreamEngine.h"
|
||||
#include "LocalizedStringManager.h"
|
||||
#include "XML/XmlUtils.h"
|
||||
#include "AutoDetectSpec.h"
|
||||
@@ -121,19 +120,6 @@ struct PEHeader_DLL
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
const SmallModuleInfo* FindModuleInfo(std::vector<SmallModuleInfo>& vec, const char* name)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size(); ++i)
|
||||
{
|
||||
if (!vec[i].name.compareNoCase(name))
|
||||
{
|
||||
return &vec[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char* CSystem::GetUserName()
|
||||
{
|
||||
@@ -231,30 +217,6 @@ int CSystem::GetApplicationLogInstance([[maybe_unused]] const char* logFilePath)
|
||||
#endif
|
||||
}
|
||||
|
||||
// these 2 functions are duplicated in System.cpp in editor
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(LINUX)
|
||||
extern int CryStats(char* buf);
|
||||
#endif
|
||||
int CSystem::DumpMMStats(bool log)
|
||||
{
|
||||
#if defined(LINUX)
|
||||
return 0;
|
||||
#else
|
||||
if (log)
|
||||
{
|
||||
char buf[1024];
|
||||
int n = CryStats(buf);
|
||||
GetILog()->Log(buf);
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CryStats(NULL);
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct CryDbgModule
|
||||
{
|
||||
@@ -264,273 +226,7 @@ struct CryDbgModule
|
||||
DWORD dwSize;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CSystem::DebugStats([[maybe_unused]] bool checkpoint, [[maybe_unused]] bool leaks)
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::vector<CryDbgModule> dbgmodules;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Use windows Performance Monitoring API to enumerate all modules of current process.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
HANDLE hSnapshot;
|
||||
hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
|
||||
if (hSnapshot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MODULEENTRY32 me;
|
||||
memset (&me, 0, sizeof(me));
|
||||
me.dwSize = sizeof(me);
|
||||
|
||||
if (Module32First (hSnapshot, &me))
|
||||
{
|
||||
// the sizes of each module group
|
||||
do
|
||||
{
|
||||
CryDbgModule module;
|
||||
module.handle = me.hModule;
|
||||
module.name = me.szModule;
|
||||
module.dwSize = me.modBaseSize;
|
||||
dbgmodules.push_back(module);
|
||||
} while (Module32Next(hSnapshot, &me));
|
||||
}
|
||||
CloseHandle (hSnapshot);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int nolib = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
ILog* log = GetILog();
|
||||
int totalal = 0;
|
||||
int totalbl = 0;
|
||||
int extrastats[10];
|
||||
#endif
|
||||
|
||||
int totalUsedInModules = 0;
|
||||
int countedMemoryModules = 0;
|
||||
for (int i = 0; i < (int)(dbgmodules.size()); i++)
|
||||
{
|
||||
if (!dbgmodules[i].handle)
|
||||
{
|
||||
CryLogAlways("WARNING: CSystem::DebugStats: NULL handle for %s", dbgmodules[i].name.c_str());
|
||||
nolib++;
|
||||
continue;
|
||||
}
|
||||
;
|
||||
|
||||
typedef int (* PFN_MODULEMEMORY)();
|
||||
PFN_MODULEMEMORY fpCryModuleGetAllocatedMemory = (PFN_MODULEMEMORY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CryModuleGetAllocatedMemory");
|
||||
if (fpCryModuleGetAllocatedMemory)
|
||||
{
|
||||
int allocatedMemory = fpCryModuleGetAllocatedMemory();
|
||||
totalUsedInModules += allocatedMemory;
|
||||
countedMemoryModules++;
|
||||
CryLogAlways("%8d K used in Module %s: ", allocatedMemory / 1024, dbgmodules[i].name.c_str());
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
typedef void (* PFNUSAGESUMMARY)(ILog* log, const char*, int*);
|
||||
typedef void (* PFNCHECKPOINT)();
|
||||
PFNUSAGESUMMARY fpu = (PFNUSAGESUMMARY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "UsageSummary");
|
||||
PFNCHECKPOINT fpc = (PFNCHECKPOINT)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CheckPoint");
|
||||
if (fpu && fpc)
|
||||
{
|
||||
if (checkpoint)
|
||||
{
|
||||
fpc();
|
||||
}
|
||||
else
|
||||
{
|
||||
extrastats[2] = (int)leaks;
|
||||
fpu(log, dbgmodules[i].name.c_str(), extrastats);
|
||||
totalal += extrastats[0];
|
||||
totalbl += extrastats[1];
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways("WARNING: CSystem::DebugStats: could not retrieve function from DLL %s", dbgmodules[i].name.c_str());
|
||||
nolib++;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef HANDLE(* PFNGETDLLHEAP)();
|
||||
PFNGETDLLHEAP fpg = (PFNGETDLLHEAP)::GetProcAddress((HMODULE)dbgmodules[i].handle, "GetDLLHeap");
|
||||
if (fpg)
|
||||
{
|
||||
dbgmodules[i].heap = fpg();
|
||||
}
|
||||
;
|
||||
}
|
||||
;
|
||||
|
||||
CryLogAlways("-------------------------------------------------------");
|
||||
CryLogAlways("%8d K Total Memory Allocated in %d Modules", totalUsedInModules / 1024, countedMemoryModules);
|
||||
#ifdef _DEBUG
|
||||
CryLogAlways("$8GRAND TOTAL: %d k, %d blocks (%d dlls not included)", totalal / 1024, totalbl, nolib);
|
||||
CryLogAlways("estimated debugalloc overhead: between %d k and %d k", totalbl * 36 / 1024, totalbl * 72 / 1024);
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Get HeapQueryInformation pointer if on windows XP.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
typedef BOOL (WINAPI * FUNC_HeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
|
||||
FUNC_HeapQueryInformation pFnHeapQueryInformation = NULL;
|
||||
HMODULE hKernelInstance = CryLoadLibrary("Kernel32.dll");
|
||||
if (hKernelInstance)
|
||||
{
|
||||
pFnHeapQueryInformation = (FUNC_HeapQueryInformation)(::GetProcAddress(hKernelInstance, "HeapQueryInformation"));
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const int MAXHANDLES = 100;
|
||||
HANDLE handles[MAXHANDLES];
|
||||
int realnumh = GetProcessHeaps(MAXHANDLES, handles);
|
||||
char hinfo[1024];
|
||||
PROCESS_HEAP_ENTRY phe;
|
||||
CryLogAlways("$6--------------------- dump of windows heaps ---------------------");
|
||||
int nTotalC = 0, nTotalCP = 0, nTotalUC = 0, nTotalUCP = 0, totalo = 0;
|
||||
for (int i = 0; i < realnumh; i++)
|
||||
{
|
||||
HANDLE hHeap = handles[i];
|
||||
HeapCompact(hHeap, 0);
|
||||
hinfo[0] = 0;
|
||||
if (pFnHeapQueryInformation)
|
||||
{
|
||||
pFnHeapQueryInformation(hHeap, HeapCompatibilityInformation, hinfo, 1024, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int m = 0; m < (int)(dbgmodules.size()); m++)
|
||||
{
|
||||
if (dbgmodules[m].heap == handles[i])
|
||||
{
|
||||
azstrcpy(hinfo, AZ_ARRAY_SIZE(hinfo), dbgmodules[m].name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
phe.lpData = NULL;
|
||||
int nCommitted = 0, nUncommitted = 0, nOverhead = 0;
|
||||
int nCommittedPieces = 0, nUncommittedPieces = 0;
|
||||
#if !defined(NDEBUG)
|
||||
int nPrevRegionIndex = -1;
|
||||
#endif
|
||||
while (HeapWalk(hHeap, &phe))
|
||||
{
|
||||
if (phe.wFlags & PROCESS_HEAP_REGION)
|
||||
{
|
||||
assert (++nPrevRegionIndex == phe.iRegionIndex);
|
||||
nCommitted += phe.Region.dwCommittedSize;
|
||||
nUncommitted += phe.Region.dwUnCommittedSize;
|
||||
assert (phe.cbData == 0 || (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY));
|
||||
}
|
||||
else
|
||||
if (phe.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
|
||||
{
|
||||
nUncommittedPieces += phe.cbData;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY)
|
||||
nCommittedPieces += phe.cbData;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/*
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery(phe.lpData, &mbi,sizeof(mbi)) == sizeof(mbi))
|
||||
{
|
||||
if (mbi.State == MEM_COMMIT)
|
||||
nCommittedPieces += phe.cbData;//mbi.RegionSize;
|
||||
//else
|
||||
// nUncommitted += mbi.RegionSize;
|
||||
}
|
||||
else
|
||||
nCommittedPieces += phe.cbData;
|
||||
*/
|
||||
}
|
||||
|
||||
nOverhead += phe.cbOverhead;
|
||||
}
|
||||
|
||||
CryLogAlways("* heap %8x: %6d (or ~%6d) K in use, %6d..%6d K uncommitted, %6d K overhead (%s)\n",
|
||||
handles[i], nCommittedPieces / 1024, nCommitted / 1024, nUncommittedPieces / 1024, nUncommitted / 1024, nOverhead / 1024, hinfo);
|
||||
|
||||
nTotalC += nCommitted;
|
||||
nTotalCP += nCommittedPieces;
|
||||
nTotalUC += nUncommitted;
|
||||
nTotalUCP += nUncommittedPieces;
|
||||
totalo += nOverhead;
|
||||
}
|
||||
;
|
||||
CryLogAlways("$6----------------- total in heaps: %d megs committed (win stats shows ~%d) (%d..%d uncommitted, %d k overhead) ---------------------", nTotalCP / 1024 / 1024, nTotalC / 1024 / 1024, nTotalUCP / 1024 / 1024, nTotalUC / 1024 / 1024, totalo / 1024);
|
||||
|
||||
#endif //WIN32
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
struct DumpHeap32Stats
|
||||
{
|
||||
DumpHeap32Stats()
|
||||
: dwFree(0)
|
||||
, dwMoveable(0)
|
||||
, dwFixed(0)
|
||||
, dwUnknown(0)
|
||||
{
|
||||
}
|
||||
void operator += (const DumpHeap32Stats& right)
|
||||
{
|
||||
dwFree += right.dwFree;
|
||||
dwMoveable += right.dwMoveable;
|
||||
dwFixed += right.dwFixed;
|
||||
dwUnknown += right.dwUnknown;
|
||||
}
|
||||
DWORD dwFree;
|
||||
DWORD dwMoveable;
|
||||
DWORD dwFixed;
|
||||
DWORD dwUnknown;
|
||||
};
|
||||
static void DumpHeap32 (const HEAPLIST32& hl, DumpHeap32Stats& stats)
|
||||
{
|
||||
HEAPENTRY32 he;
|
||||
memset (&he, 0, sizeof(he));
|
||||
he.dwSize = sizeof(he);
|
||||
|
||||
if (Heap32First (&he, hl.th32ProcessID, hl.th32HeapID))
|
||||
{
|
||||
DumpHeap32Stats heap;
|
||||
do
|
||||
{
|
||||
if (he.dwFlags & LF32_FREE)
|
||||
{
|
||||
heap.dwFree += he.dwBlockSize;
|
||||
}
|
||||
else
|
||||
if (he.dwFlags & LF32_MOVEABLE)
|
||||
{
|
||||
heap.dwMoveable += he.dwBlockSize;
|
||||
}
|
||||
else
|
||||
if (he.dwFlags & LF32_FIXED)
|
||||
{
|
||||
heap.dwFixed += he.dwBlockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
heap.dwUnknown += he.dwBlockSize;
|
||||
}
|
||||
} while (Heap32Next (&he));
|
||||
|
||||
CryLogAlways ("%08X %6d %6d %6d (%d)", hl.th32HeapID, heap.dwFixed / 0x400, heap.dwFree / 0x400, heap.dwMoveable / 0x400, heap.dwUnknown / 0x400);
|
||||
stats += heap;
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways ("%08X empty or invalid");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CStringOrder
|
||||
{
|
||||
@@ -566,94 +262,6 @@ const char* GetModuleGroup (const char* szString)
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CSystem::DumpWinHeaps()
|
||||
{
|
||||
#ifdef WIN32
|
||||
//
|
||||
// Retrieve modules and log them; remember the process id
|
||||
|
||||
HANDLE hSnapshot;
|
||||
hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CryLogAlways ("Cannot get the module snapshot, error code %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD dwProcessID = GetCurrentProcessId();
|
||||
|
||||
MODULEENTRY32 me;
|
||||
memset (&me, 0, sizeof(me));
|
||||
me.dwSize = sizeof(me);
|
||||
|
||||
if (Module32First (hSnapshot, &me))
|
||||
{
|
||||
// the sizes of each module group
|
||||
StringToSizeMap mapGroupSize;
|
||||
DWORD dwTotalModuleSize = 0;
|
||||
CryLogAlways ("base size module");
|
||||
do
|
||||
{
|
||||
dwProcessID = me.th32ProcessID;
|
||||
const char* szGroup = GetModuleGroup (me.szModule);
|
||||
CryLogAlways ("%08X %8X %25s - %s", me.modBaseAddr, me.modBaseSize, me.szModule, azstricmp(szGroup, "Other") ? szGroup : "");
|
||||
dwTotalModuleSize += me.modBaseSize;
|
||||
AddSize (mapGroupSize, szGroup, me.modBaseSize);
|
||||
} while (Module32Next(hSnapshot, &me));
|
||||
|
||||
CryLogAlways ("------------------------------------");
|
||||
for (StringToSizeMap::iterator it = mapGroupSize.begin(); it != mapGroupSize.end(); ++it)
|
||||
{
|
||||
CryLogAlways (" %6.3f Mbytes - %s", double(it->second) / 0x100000, it->first);
|
||||
}
|
||||
CryLogAlways ("------------------------------------");
|
||||
CryLogAlways (" %6.3f Mbytes - TOTAL", double(dwTotalModuleSize) / 0x100000);
|
||||
CryLogAlways ("------------------------------------");
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways ("No modules to dump");
|
||||
}
|
||||
|
||||
CloseHandle (hSnapshot);
|
||||
|
||||
//
|
||||
// Retrieve the heaps and dump each of them with a special function
|
||||
|
||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CryLogAlways ("Cannot get the heap LIST snapshot, error code %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
HEAPLIST32 hl;
|
||||
memset (&hl, 0, sizeof(hl));
|
||||
hl.dwSize = sizeof(hl);
|
||||
|
||||
CryLogAlways ("__Heap__ fixed free move (unknown)");
|
||||
if (Heap32ListFirst (hSnapshot, &hl))
|
||||
{
|
||||
DumpHeap32Stats stats;
|
||||
do
|
||||
{
|
||||
DumpHeap32 (hl, stats);
|
||||
} while (Heap32ListNext (hSnapshot, &hl));
|
||||
|
||||
CryLogAlways ("-------------------------------------------------");
|
||||
CryLogAlways ("$6 %6.3f %6.3f %6.3f (%.3f) Mbytes", double(stats.dwFixed) / 0x100000, double(stats.dwFree) / 0x100000, double(stats.dwMoveable) / 0x100000, double(stats.dwUnknown) / 0x100000);
|
||||
CryLogAlways ("-------------------------------------------------");
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways ("No heaps to dump");
|
||||
}
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Make system error message string
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//! \return pointer to the null terminated error string or 0
|
||||
@@ -739,8 +347,6 @@ void CSystem::FatalError(const char* format, ...)
|
||||
assert(szBuffer[0] >= ' ');
|
||||
// strcpy(szBuffer,szBuffer+1); // remove verbosity tag since it is not supported by ::MessageBox
|
||||
|
||||
LogSystemInfo();
|
||||
|
||||
OutputDebugString(szBuffer);
|
||||
#ifdef WIN32
|
||||
OnFatalError(szBuffer);
|
||||
@@ -879,146 +485,6 @@ bool CSystem::ReLaunchMediaCenter()
|
||||
}
|
||||
#endif //defined(WIN32)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if defined(WIN32)
|
||||
void CSystem::LogSystemInfo()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Write the system informations to the log
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
char szBuffer[1024];
|
||||
char szProfileBuffer[128];
|
||||
char szLanguageBuffer[64];
|
||||
//char szCPUModel[64];
|
||||
|
||||
MEMORYSTATUSEX MemoryStatus;
|
||||
MemoryStatus.dwLength = sizeof(MemoryStatus);
|
||||
|
||||
DEVMODE DisplayConfig;
|
||||
OSVERSIONINFO OSVerInfo;
|
||||
OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
|
||||
// log system language
|
||||
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, szLanguageBuffer, sizeof(szLanguageBuffer));
|
||||
azsprintf(szBuffer, "System language: %s", szLanguageBuffer);
|
||||
CryLogAlways(szBuffer);
|
||||
|
||||
// log Windows directory
|
||||
GetWindowsDirectory(szBuffer, sizeof(szBuffer));
|
||||
string str = "Windows Directory: \"";
|
||||
str += szBuffer;
|
||||
str += "\"";
|
||||
CryLogAlways(str);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Send system time & date
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
str = "Local time is ";
|
||||
azstrtime(szBuffer);
|
||||
str += szBuffer;
|
||||
str += " ";
|
||||
_strdate_s(szBuffer);
|
||||
str += szBuffer;
|
||||
azsprintf(szBuffer, ", system running for %lu minutes", GetTickCount() / 60000);
|
||||
str += szBuffer;
|
||||
CryLogAlways(str);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Send system memory status
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
GlobalMemoryStatusEx(&MemoryStatus);
|
||||
azsprintf(szBuffer, "%I64dMB physical memory installed, %I64dMB available, %I64dMB virtual memory installed, %ld percent of memory in use",
|
||||
MemoryStatus.ullTotalPhys / 1048576 + 1,
|
||||
MemoryStatus.ullAvailPhys / 1048576,
|
||||
MemoryStatus.ullTotalVirtual / 1048576,
|
||||
MemoryStatus.dwMemoryLoad);
|
||||
CryLogAlways(szBuffer);
|
||||
|
||||
if (GetISystem()->GetIMemoryManager())
|
||||
{
|
||||
IMemoryManager::SProcessMemInfo memCounters;
|
||||
GetISystem()->GetIMemoryManager()->GetProcessMemInfo(memCounters);
|
||||
|
||||
uint64 PagefileUsage = memCounters.PagefileUsage;
|
||||
uint64 PeakPagefileUsage = memCounters.PeakPagefileUsage;
|
||||
uint64 WorkingSetSize = memCounters.WorkingSetSize;
|
||||
azsprintf(szBuffer, "PageFile usage: %I64dMB, Working Set: %I64dMB, Peak PageFile usage: %I64dMB,",
|
||||
(uint64)PagefileUsage / (1024 * 1024),
|
||||
(uint64)WorkingSetSize / (1024 * 1024),
|
||||
(uint64)PeakPagefileUsage / (1024 * 1024));
|
||||
CryLogAlways(szBuffer);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Send display settings
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
|
||||
GetPrivateProfileString("boot.description", "display.drv",
|
||||
"(Unknown graphics card)", szProfileBuffer, sizeof(szProfileBuffer),
|
||||
"system.ini");
|
||||
azsprintf(szBuffer, "Current display mode is %lux%lux%lu, %s",
|
||||
DisplayConfig.dmPelsWidth, DisplayConfig.dmPelsHeight,
|
||||
DisplayConfig.dmBitsPerPel, szProfileBuffer);
|
||||
CryLogAlways(szBuffer);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Send input device configuration
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
str = "";
|
||||
// Detect the keyboard type
|
||||
switch (GetKeyboardType(0))
|
||||
{
|
||||
case 1:
|
||||
str = "IBM PC/XT (83-key)";
|
||||
break;
|
||||
case 2:
|
||||
str = "ICO (102-key)";
|
||||
break;
|
||||
case 3:
|
||||
str = "IBM PC/AT (84-key)";
|
||||
break;
|
||||
case 4:
|
||||
str = "IBM enhanced (101/102-key)";
|
||||
break;
|
||||
case 5:
|
||||
str = "Nokia 1050";
|
||||
break;
|
||||
case 6:
|
||||
str = "Nokia 9140";
|
||||
break;
|
||||
case 7:
|
||||
str = "Japanese";
|
||||
break;
|
||||
default:
|
||||
str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
// Any mouse attached ?
|
||||
if (!GetSystemMetrics(SM_MOUSEPRESENT))
|
||||
{
|
||||
CryLogAlways(str + " keyboard and no mouse installed");
|
||||
}
|
||||
else
|
||||
{
|
||||
azsprintf(szBuffer, " keyboard and %i+ button mouse installed",
|
||||
GetSystemMetrics(SM_CMOUSEBUTTONS));
|
||||
CryLogAlways(str + szBuffer);
|
||||
}
|
||||
|
||||
CryLogAlways("--------------------------------------------------------------------------------");
|
||||
}
|
||||
#else
|
||||
void CSystem::LogSystemInfo()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(WIN32) || defined(WIN64))
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSystem::GetWinGameFolder(char* szMyDocumentsPath, int maxPathSize)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <LegacyAllocator.h>
|
||||
#include <System.h>
|
||||
#include <CryMemoryManager.h>
|
||||
|
||||
namespace UnitTests
|
||||
{
|
||||
@@ -25,10 +24,6 @@ namespace UnitTests
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
IMemoryManager* cryMemoryManager = nullptr;
|
||||
CryGetIMemoryManagerInterface((void**)&cryMemoryManager);
|
||||
AZ_Assert(cryMemoryManager, "Unable to resolve CryMemoryManager");
|
||||
m_cryMemoryManager = AZ::Environment::CreateVariable<IMemoryManager*>("CryIMemoryManagerInterface", cryMemoryManager);
|
||||
SSystemInitParams startupParams;
|
||||
AZ::AllocatorInstance<AZ::LegacyAllocator>::Create();
|
||||
AZ::AllocatorInstance<CryStringAllocator>::Create();
|
||||
@@ -44,8 +39,6 @@ namespace UnitTests
|
||||
|
||||
|
||||
CSystem* m_system = nullptr;
|
||||
AZ::EnvironmentVariable<IMemoryManager*> m_cryMemoryManager;
|
||||
|
||||
};
|
||||
|
||||
TEST_F(CSystemUnitTests, ApplicationLogInstanceUnitTests)
|
||||
|
||||
@@ -272,7 +272,6 @@ void CXmlUtils::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wpar
|
||||
case ESYSTEM_EVENT_LEVEL_POST_UNLOAD:
|
||||
case ESYSTEM_EVENT_LEVEL_LOAD_END:
|
||||
g_pCXmlNode_PoolAlloc->FreeMemoryIfEmpty();
|
||||
STLALLOCATOR_CLEANUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,10 @@ set(FILES
|
||||
ConsoleBatchFile.cpp
|
||||
ConsoleHelpGen.cpp
|
||||
CryAsyncMemcpy.cpp
|
||||
GeneralMemoryHeap.cpp
|
||||
HandlerBase.cpp
|
||||
AsyncPakManager.cpp
|
||||
Log.cpp
|
||||
SystemRender.cpp
|
||||
PhysRenderer.cpp
|
||||
ResourceManager.cpp
|
||||
ServerHandler.cpp
|
||||
ServerThrottle.cpp
|
||||
SyncLock.cpp
|
||||
@@ -42,9 +39,7 @@ set(FILES
|
||||
AutoDetectSpec.h
|
||||
ClientHandler.h
|
||||
HandlerBase.h
|
||||
AsyncPakManager.h
|
||||
PhysRenderer.h
|
||||
ResourceManager.h
|
||||
ServerHandler.h
|
||||
ServerThrottle.h
|
||||
SyncLock.h
|
||||
@@ -58,7 +53,6 @@ set(FILES
|
||||
ConsoleBatchFile.h
|
||||
ConsoleHelpGen.h
|
||||
CryWaterMark.h
|
||||
GeneralMemoryHeap.h
|
||||
Log.h
|
||||
resource.h
|
||||
SimpleStringPool.h
|
||||
@@ -71,18 +65,6 @@ set(FILES
|
||||
WindowsConsole.h
|
||||
XConsole.h
|
||||
XConsoleVariable.h
|
||||
crash_face.bmp
|
||||
ImageHandler.h
|
||||
ImageHandler.cpp
|
||||
MemoryAddressRange.cpp
|
||||
PageMappingHeap.cpp
|
||||
CustomMemoryHeap.cpp
|
||||
MemoryManager.cpp
|
||||
MTSafeAllocator.cpp
|
||||
MemoryAddressRange.h
|
||||
PageMappingHeap.h
|
||||
MemoryManager.h
|
||||
MTSafeAllocator.h
|
||||
XML/SerializeXMLReader.cpp
|
||||
XML/SerializeXMLWriter.cpp
|
||||
XML/xml.cpp
|
||||
@@ -126,18 +108,6 @@ set(FILES
|
||||
ViewSystem/ViewSystem.h
|
||||
ZStdDecompressor.h
|
||||
ZStdDecompressor.cpp
|
||||
StreamEngine/StreamAsyncFileRequest.cpp
|
||||
StreamEngine/StreamAsyncFileRequest_Jobs.cpp
|
||||
StreamEngine/StreamEngine.cpp
|
||||
StreamEngine/StreamIOThread.cpp
|
||||
StreamEngine/StreamReadStream.cpp
|
||||
StreamEngine/AZRequestReadStream.cpp
|
||||
StreamEngine/StreamAsyncFileRequest.h
|
||||
StreamEngine/StreamEngine.h
|
||||
StreamEngine/StreamIOThread.h
|
||||
StreamEngine/StreamReadStream.h
|
||||
StreamEngine/AZRequestReadStream.h
|
||||
CrashHandler.rc
|
||||
CrySystem_precompiled.cpp
|
||||
CPUDetect.cpp
|
||||
CPUDetect.h
|
||||
|
||||
Reference in New Issue
Block a user