You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1390 lines
55 KiB
C++
1390 lines
55 KiB
C++
/*
|
|
* 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 : Visual helper for checking a local memory usage on maps
|
|
|
|
/*
|
|
TODO:
|
|
- Procedural vegetation
|
|
|
|
- Permanent mip-map problem (streaming will collect a permanent mip-maps when travelling)
|
|
- ? Foliage render nodes
|
|
|
|
must make a decision about the local / global problem:
|
|
- Particle effects (must check the calculation)
|
|
- Characters (calculation is DONE)
|
|
|
|
- StatObj LOD streaming (I think that there is no LOD streaming, but i'm not sure about this)
|
|
- Terrain texture streaming (not detail textures!) //It's not needed because this system using a fix-size pool
|
|
- Animation streaming: completely different system, not need to measure now
|
|
- IsoMesh streaming: completely different system, not need to measure now
|
|
*/
|
|
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
|
|
#include "LocalMemoryUsage.h"
|
|
|
|
#include <ITimer.h>
|
|
#include <IConsole.h>
|
|
#include <I3DEngine.h>
|
|
#include <IRenderAuxGeom.h>
|
|
|
|
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
|
|
|
//#define MAX_LODS 6 // I want an engine-wide const :-(
|
|
#define MAX_SLOTS 100 // GetSlotCount() is not working :-(
|
|
#define BIG_NUMBER 1e20f
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace LocalMemoryUsageDrawHelper
|
|
{
|
|
enum eDrawRectParams
|
|
{
|
|
DSP_YDIR = 0,
|
|
DSP_XDIR = 1,
|
|
DSP_REVERSE_TRIANGLES = 2,
|
|
DSP_REVERSE_ARROW = 4,
|
|
};
|
|
|
|
void DrawRect(IRenderer* pRenderer, const CCamera* camera, const Vec3& p1, const Vec3& p3, const ColorB& color, int params = 0)
|
|
{
|
|
Vec3 p2, p4, projectedPos;
|
|
if (!(params & DSP_REVERSE_TRIANGLES))
|
|
{
|
|
if (params & DSP_XDIR)
|
|
{
|
|
p2 = Vec3(p1.x, p3.y, p1.z);
|
|
p4 = Vec3(p3.x, p1.y, p3.z);
|
|
}
|
|
else
|
|
{
|
|
p2 = Vec3(p1.x, p3.y, p3.z);
|
|
p4 = Vec3(p3.x, p1.y, p1.z);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (params & DSP_XDIR)
|
|
{
|
|
p4 = Vec3(p1.x, p3.y, p1.z);
|
|
p2 = Vec3(p3.x, p1.y, p3.z);
|
|
}
|
|
else
|
|
{
|
|
p4 = Vec3(p1.x, p3.y, p3.z);
|
|
p2 = Vec3(p3.x, p1.y, p1.z);
|
|
}
|
|
}
|
|
|
|
if (camera->Project(p1, projectedPos) || camera->Project(p2, projectedPos) || camera->Project(p3, projectedPos) || camera->Project(p4, projectedPos))
|
|
{
|
|
IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom();
|
|
|
|
pRenderAuxGeom->DrawTriangle(p1, color, p2, color, p3, color);
|
|
pRenderAuxGeom->DrawTriangle(p3, color, p4, color, p1, color);
|
|
}
|
|
}
|
|
|
|
void DrawArrow(IRenderer* pRenderer, const CCamera* camera, Vec3 pStart, Vec3 pEnd, float width, float head, float lengthSub, const ColorB& color, int params = 0)
|
|
{
|
|
Vec3 p1, p2, p3, p4, p5, p6, p7, projectedPos;
|
|
|
|
if (params & DSP_REVERSE_ARROW)
|
|
{
|
|
std::swap(pStart, pEnd);
|
|
}
|
|
|
|
Vec3 vParallel((pEnd - pStart).GetNormalized());
|
|
Vec3 vOrto = vParallel.Cross(Vec3(0, 0, 1)).GetNormalized();
|
|
pStart += vParallel * lengthSub;
|
|
pEnd -= vParallel * lengthSub;
|
|
|
|
p1 = pStart - (vOrto * width * 0.5f);
|
|
p2 = pStart + (vOrto * width * 0.5f);
|
|
p3 = (pEnd - vParallel * head) - (vOrto * width * 0.5f);
|
|
p4 = (pEnd - vParallel * head) + (vOrto * width * 0.5f);
|
|
p5 = (pEnd - vParallel * head * 1.5f) - (vOrto * head * 0.9f);
|
|
p6 = (pEnd - vParallel * head * 1.5f) + (vOrto * head * 0.9f);
|
|
p7 = pEnd;
|
|
|
|
if (camera->Project(p1, projectedPos) || camera->Project(p7, projectedPos))
|
|
{
|
|
IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom();
|
|
|
|
pRenderAuxGeom->DrawTriangle(p1, color, p2, color, p4, color);
|
|
pRenderAuxGeom->DrawTriangle(p4, color, p3, color, p1, color);
|
|
pRenderAuxGeom->DrawTriangle(p3, color, p4, color, p7, color);
|
|
pRenderAuxGeom->DrawTriangle(p4, color, p6, color, p7, color);
|
|
pRenderAuxGeom->DrawTriangle(p5, color, p3, color, p7, color);
|
|
}
|
|
}
|
|
|
|
#define DRAWHELPER_CIRCLE_POINT_NR 32
|
|
|
|
|
|
static Vec3 s_CirclePoints[DRAWHELPER_CIRCLE_POINT_NR + 1];
|
|
static bool s_CircleDataInited = false;
|
|
void InitCircleData()
|
|
{
|
|
s_CircleDataInited = true;
|
|
float angleDiff = 2.0f * 3.1415927f / DRAWHELPER_CIRCLE_POINT_NR;
|
|
|
|
for (int i = 0; i < DRAWHELPER_CIRCLE_POINT_NR + 1; i++)
|
|
{
|
|
s_CirclePoints[i] = Vec3(cos(i * angleDiff), sin(i * angleDiff), 0.0f);
|
|
}
|
|
}
|
|
|
|
void DrawCircle(IRenderer* pRenderer, [[maybe_unused]] const CCamera* camera, const Vec3& origo, float radius, float ratio, const ColorB& color1, const ColorB& color2)
|
|
{
|
|
if (!s_CircleDataInited)
|
|
{
|
|
InitCircleData();
|
|
}
|
|
float radius2 = radius * 0.90f;
|
|
|
|
IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom();
|
|
|
|
Vec3 oldPoint = origo + s_CirclePoints[0] * radius;
|
|
Vec3 oldPoint2 = origo + s_CirclePoints[0] * radius2;
|
|
|
|
for (int i = 0; i < DRAWHELPER_CIRCLE_POINT_NR; i++)
|
|
{
|
|
Vec3 newPoint = origo + s_CirclePoints[i + 1] * radius;
|
|
Vec3 newPoint2 = origo + s_CirclePoints[i + 1] * radius2;
|
|
if (i < ratio * DRAWHELPER_CIRCLE_POINT_NR)
|
|
{
|
|
pRenderAuxGeom->DrawTriangle(origo, color1, oldPoint, color1, newPoint, color1);
|
|
}
|
|
else
|
|
{
|
|
//pRenderAuxGeom->DrawTriangle( origo, color2, oldPoint, color2, newPoint, color2 );
|
|
pRenderAuxGeom->DrawTriangle(oldPoint2, color2, oldPoint, color2, newPoint, color2);
|
|
pRenderAuxGeom->DrawTriangle(newPoint, color2, newPoint2, color2, oldPoint2, color2);
|
|
}
|
|
oldPoint = newPoint;
|
|
oldPoint2 = newPoint2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
namespace Distance
|
|
{
|
|
// Distance: AABB_AABB
|
|
//----------------------------------------------------------------------------------
|
|
// Calculate the closest distance of a AABB to an another AABB in 3d-space.
|
|
// The function returns the squared distance.
|
|
// optionally the closest point on the hull is calculated
|
|
//
|
|
// Example:
|
|
// float result = Distance::Point_AABBSq( aabb1, aabb2 );
|
|
//----------------------------------------------------------------------------------
|
|
|
|
ILINE float AABB_AABBSq( const AABB& aabb1, const AABB& aabb2 )
|
|
{
|
|
float fDist2 = 0;
|
|
for(int i=0; i<3; ++i)
|
|
{
|
|
float max1 = aabb1.max[i];
|
|
if(max1 < aabb2.min[i])
|
|
{
|
|
fDist2 += sqr(max1-aabb2.min[i]);
|
|
}
|
|
else
|
|
{
|
|
float min1 = aabb1.min[i];
|
|
if(min1 > aabb2.max[i])
|
|
{
|
|
fDist2 += sqr(aabb2.max[i]-min1);
|
|
}
|
|
}
|
|
}
|
|
return fDist2;
|
|
}
|
|
|
|
// Distance: AABB_AABB_2D
|
|
//----------------------------------------------------------------------------------
|
|
// Calculate the closest distance of a AABB to an another AABB in 2d-space.
|
|
// The function returns the squared distance.
|
|
// optionally the closest point on the hull is calculated
|
|
//
|
|
// Example:
|
|
// float result = Distance::AABB_AABB2DSq( aabb1, aabb2 );
|
|
//----------------------------------------------------------------------------------
|
|
|
|
ILINE float AABB_AABB2DSq( const AABB& aabb1, const AABB& aabb2 )
|
|
{
|
|
float fDist2 = 0;
|
|
for(int i=0; i<2; ++i) //We are using only 2 of the dimensions!
|
|
{
|
|
float max1 = aabb1.max[i];
|
|
if(max1 < aabb2.min[i])
|
|
{
|
|
fDist2 += sqr(max1-aabb2.min[i]);
|
|
}
|
|
else
|
|
{
|
|
float min1 = aabb1.min[i];
|
|
if(min1 > aabb2.max[i])
|
|
{
|
|
fDist2 += sqr(aabb2.max[i]-min1);
|
|
}
|
|
}
|
|
}
|
|
return fDist2;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int CLocalMemoryUsage::SResource::m_arrMemoryUsage[LOCALMEMORY_SECTOR_PER_PASS];
|
|
int CLocalMemoryUsage::SResource::m_arrPieces[LOCALMEMORY_SECTOR_PER_PASS];
|
|
|
|
|
|
CLocalMemoryUsage::SResource::SResource()
|
|
{
|
|
m_used = true;
|
|
}
|
|
|
|
void CLocalMemoryUsage::SResource::Init(CLocalMemoryUsage* pLocalMemoryUsage)
|
|
{
|
|
m_pLocalMemoryUsage = pLocalMemoryUsage;
|
|
|
|
StartChecking();
|
|
}
|
|
|
|
void CLocalMemoryUsage::SResource::StartChecking()
|
|
{
|
|
const RectI& actProcessedSectors = m_pLocalMemoryUsage->m_actProcessedSectors;
|
|
|
|
float* pMipFactor = m_arrMipFactor;
|
|
for (int i = 0; i < actProcessedSectors.w * actProcessedSectors.h; i++)
|
|
{
|
|
*pMipFactor = BIG_NUMBER;
|
|
pMipFactor++;
|
|
}
|
|
bool* pRowDirty = m_arrRowDirty;
|
|
for (int i = 0; i < LOCALMEMORY_SECTOR_PER_PASS; i++)
|
|
{
|
|
*pRowDirty = false;
|
|
pRowDirty++;
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::SResource::CheckOnAllSectorsP1(const AABB& bounding, float maxViewDist, float scale, float mipFactor)
|
|
{
|
|
//FRAME_PROFILER("! CLocalMemoryUsage::SResource::CheckOnAllSectorsP1", GetISystem(), PROFILE_SYSTEM);
|
|
|
|
float modifiedmaxViewDist = maxViewDist;
|
|
float modifiedmaxViewDistSqr = sqr(modifiedmaxViewDist);
|
|
|
|
const RectI& actProcessedSectors = m_pLocalMemoryUsage->m_actProcessedSectors;
|
|
|
|
int xMin = (int)max(0, int((bounding.min.x - modifiedmaxViewDist) / LOCALMEMORY_SECTOR_SIZE ) - actProcessedSectors.x);
|
|
int xMax = (int)min(actProcessedSectors.w, int((bounding.max.x + modifiedmaxViewDist) / LOCALMEMORY_SECTOR_SIZE + 1) - actProcessedSectors.x);
|
|
int yMin = (int)max(0, int((bounding.min.y - modifiedmaxViewDist) / LOCALMEMORY_SECTOR_SIZE ) - actProcessedSectors.y);
|
|
int yMax = (int)min(actProcessedSectors.h, int((bounding.max.y + modifiedmaxViewDist) / LOCALMEMORY_SECTOR_SIZE + 1) - actProcessedSectors.y);
|
|
|
|
AABB sectorBounding(AABB::RESET);
|
|
float sectorDistanceSqr;
|
|
float fDistYSqr;
|
|
|
|
for (int y = yMin; y < yMax; y++)
|
|
{
|
|
float* pMipFactor = &m_arrMipFactor[actProcessedSectors.w * y + xMin];
|
|
|
|
sectorBounding.min.y = (y + actProcessedSectors.y) * LOCALMEMORY_SECTOR_SIZE;
|
|
sectorBounding.max.y = sectorBounding.min.y + LOCALMEMORY_SECTOR_SIZE;
|
|
sectorBounding.min.x = (xMin + actProcessedSectors.x) * LOCALMEMORY_SECTOR_SIZE;
|
|
|
|
assert(y < LOCALMEMORY_SECTOR_PER_PASS);
|
|
m_arrRowDirty[y] = true;
|
|
|
|
//Calculating Y distance sqr
|
|
{
|
|
fDistYSqr = 0;
|
|
if (bounding.max.y < sectorBounding.min.y)
|
|
{
|
|
fDistYSqr += sqr(bounding.max.y - sectorBounding.min.y);
|
|
}
|
|
else
|
|
{
|
|
if (bounding.min.y > sectorBounding.max.y)
|
|
{
|
|
fDistYSqr += sqr(sectorBounding.max.y - bounding.min.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int x = xMin; x < xMax; x++)
|
|
{
|
|
sectorBounding.max.x = sectorBounding.min.x + LOCALMEMORY_SECTOR_SIZE;
|
|
|
|
//sectorDistanceSqr = Distance::AABB_AABB2DSq(bounding, sectorBounding);
|
|
|
|
//Adding X distance sqr
|
|
{
|
|
sectorDistanceSqr = fDistYSqr;
|
|
if (bounding.max.x < sectorBounding.min.x)
|
|
{
|
|
sectorDistanceSqr += sqr(bounding.max.x - sectorBounding.min.x);
|
|
}
|
|
else
|
|
{
|
|
if (bounding.min.x > sectorBounding.max.x)
|
|
{
|
|
sectorDistanceSqr += sqr(sectorBounding.max.x - bounding.min.x);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sectorDistanceSqr < modifiedmaxViewDistSqr)
|
|
{
|
|
*pMipFactor = min(*pMipFactor, sectorDistanceSqr * scale * scale * mipFactor);
|
|
}
|
|
|
|
pMipFactor++;
|
|
|
|
sectorBounding.min.x = sectorBounding.max.x;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CLocalMemoryUsage::STextureInfo::STextureInfo()
|
|
{
|
|
m_pTexture = NULL;
|
|
|
|
//m_size = 0;
|
|
//m_xSize = 0;
|
|
//m_ySize = 0;
|
|
//m_numMips = 0;
|
|
}
|
|
|
|
CLocalMemoryUsage::STextureInfo::~STextureInfo()
|
|
{
|
|
if (m_pTexture)
|
|
{
|
|
m_pTexture->Release();
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::STextureInfo::CheckOnAllSectorsP2()
|
|
{
|
|
int x, y, nMip, nStreamableMipNr, memoryUsage, xOldMemoryUsage, xOldPieces;
|
|
bool nonZero;
|
|
ITexture* pTexture;
|
|
|
|
const RectI& actProcessedSectors = m_pLocalMemoryUsage->m_actProcessedSectors;
|
|
|
|
bool wasDirty = false;
|
|
for (y = 0; y < actProcessedSectors.h; y++)
|
|
{
|
|
int* pMemoryUsage = m_arrMemoryUsage;
|
|
int* pPieces = m_arrPieces;
|
|
if (m_arrRowDirty[y] || (wasDirty))
|
|
{
|
|
SSector* sector = &m_pLocalMemoryUsage->m_arrSectors[(y + actProcessedSectors.y) * LOCALMEMORY_SECTOR_NR_X + actProcessedSectors.x];
|
|
float* pMipFactor = &m_arrMipFactor[y * actProcessedSectors.w ];
|
|
xOldMemoryUsage = 0;
|
|
xOldPieces = 0;
|
|
for (x = 0; x < actProcessedSectors.w; x++)
|
|
{
|
|
nonZero = (*pMipFactor != BIG_NUMBER);
|
|
if (nonZero) // One more row
|
|
{
|
|
pTexture = m_pTexture;
|
|
if (!nonZero)
|
|
{
|
|
memoryUsage = 0;
|
|
nStreamableMipNr = 0;
|
|
}
|
|
else
|
|
{
|
|
nMip = max(0, pTexture->StreamCalculateMipsSigned(*pMipFactor));
|
|
memoryUsage = pTexture->GetStreamableMemoryUsage(nMip);
|
|
nStreamableMipNr = pTexture->GetStreamableMipNumber() - nMip;
|
|
}
|
|
|
|
sector->m_memoryUsage_Textures += memoryUsage;
|
|
|
|
xOldMemoryUsage = memoryUsage;
|
|
*pMemoryUsage = memoryUsage;
|
|
xOldPieces = nStreamableMipNr;
|
|
*pPieces = nStreamableMipNr;
|
|
}
|
|
else
|
|
{
|
|
xOldMemoryUsage = 0;
|
|
*pMemoryUsage = 0;
|
|
xOldPieces = 0;
|
|
*pPieces = 0;
|
|
}
|
|
sector++;
|
|
pMipFactor++;
|
|
pMemoryUsage++;
|
|
pPieces++;
|
|
}
|
|
wasDirty = m_arrRowDirty[y];
|
|
}
|
|
else
|
|
{
|
|
for (x = 0; x < actProcessedSectors.w; x++)
|
|
{
|
|
*pMemoryUsage = 0;
|
|
pMemoryUsage++;
|
|
*pPieces = 0;
|
|
pPieces++;
|
|
}
|
|
wasDirty = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CLocalMemoryUsage::SMaterialInfo::SMaterialInfo()
|
|
{
|
|
}
|
|
|
|
void CLocalMemoryUsage::SMaterialInfo::AddTextureInfo(STextureInfoAndTilingFactor textureInfo)
|
|
{
|
|
m_textures.push_back(textureInfo);
|
|
}
|
|
|
|
void CLocalMemoryUsage::SMaterialInfo::CheckOnAllSectorsP2()
|
|
{
|
|
int x, y;
|
|
|
|
const RectI& actProcessedSectors = m_pLocalMemoryUsage->m_actProcessedSectors;
|
|
|
|
for (y = 0; y < actProcessedSectors.h; y++)
|
|
{
|
|
if (m_arrRowDirty[y])
|
|
{
|
|
float* pMipFactor = &m_arrMipFactor[y * actProcessedSectors.w ];
|
|
for (x = 0; x < actProcessedSectors.w; x++)
|
|
{
|
|
if (*pMipFactor != BIG_NUMBER)
|
|
{
|
|
//(Spidy) Send the material MinDistance values to textures
|
|
for (TTextureVector::iterator it = m_textures.begin(); it != m_textures.end(); ++it)
|
|
{
|
|
STextureInfoAndTilingFactor& textureInfo = *it;
|
|
textureInfo.m_pTextureInfo->m_arrRowDirty[y] = true;
|
|
|
|
float& textureMipFactor = textureInfo.m_pTextureInfo->m_arrMipFactor[actProcessedSectors.w * y + x];
|
|
textureMipFactor = min(textureMipFactor, *pMipFactor * textureInfo.m_tilingFactor);
|
|
}
|
|
}
|
|
pMipFactor++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CLocalMemoryUsage::SStatObjInfo::SStatObjInfo()
|
|
{
|
|
m_streamableContentMemoryUsage = 0;
|
|
|
|
m_bSubObject = false;
|
|
/*
|
|
m_lodNr = 0;
|
|
m_vertices = 0;
|
|
m_indices = 0;
|
|
m_meshSize = 0;
|
|
m_physProxySize = 0;
|
|
m_physPrimitives = 0;
|
|
for( int i=0; i < MAX_LODS; i++)
|
|
{
|
|
m_indicesPerLod[i]=0;
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CLocalMemoryUsage::SStatObjInfo::CheckOnAllSectorsP2()
|
|
{
|
|
int x, y, memoryUsage, pieces, xOldMemoryUsage, xOldPieces;
|
|
bool nonZero;
|
|
|
|
const RectI& actProcessedSectors = m_pLocalMemoryUsage->m_actProcessedSectors;
|
|
|
|
bool wasDirty = false;
|
|
for (y = 0; y < actProcessedSectors.h; y++)
|
|
{
|
|
int* pMemoryUsage = m_arrMemoryUsage;
|
|
int* pPieces = m_arrPieces;
|
|
if (m_arrRowDirty[y])
|
|
{
|
|
SSector* sector = &m_pLocalMemoryUsage->m_arrSectors[(y + actProcessedSectors.y) * LOCALMEMORY_SECTOR_NR_X + actProcessedSectors.x];
|
|
float* pMipFactor = &m_arrMipFactor[y * actProcessedSectors.w ];
|
|
xOldMemoryUsage = 0;
|
|
xOldPieces = 0;
|
|
for (x = 0; x < actProcessedSectors.w; x++)
|
|
{
|
|
nonZero = (*pMipFactor != BIG_NUMBER);
|
|
if (nonZero) // One more row
|
|
{
|
|
/*
|
|
memoryUsage = 0;
|
|
float minDistance = sqrt_tpl(minDistanceSqr);
|
|
CStatObj* pStatObj = (CStatObj*)(m_pStatObj.get()); //(Spidy) Huh...
|
|
|
|
//Iterate on all subobjects, like CStatObj::UpdateStreamableComponents
|
|
float fSubObjectScale = 1.0f;
|
|
//float fSubObjectScale = matSubObject.GetColumn0().GetLength(); //TODO
|
|
int lod = pStatObj->GetLodFromScale(1.0f, fSubObjectScale, minDistance, false);
|
|
//(Spidy) az objMatrix scale es a fLodRatioNorm mar bele vannak szamolva a minDistance-ba!
|
|
memoryUsage = m_streamableContentMemoryUsage;
|
|
*/
|
|
memoryUsage = m_streamableContentMemoryUsage;
|
|
pieces = 1;
|
|
|
|
if (!nonZero)
|
|
{
|
|
memoryUsage = 0;
|
|
pieces = 0;
|
|
}
|
|
|
|
sector->m_memoryUsage_Geometry += memoryUsage;
|
|
|
|
xOldMemoryUsage = memoryUsage;
|
|
*pMemoryUsage = memoryUsage;
|
|
xOldPieces = pieces;
|
|
*pPieces = pieces;
|
|
}
|
|
else
|
|
{
|
|
xOldMemoryUsage = 0;
|
|
*pMemoryUsage = 0;
|
|
xOldPieces = 0;
|
|
*pPieces = 0;
|
|
}
|
|
sector++;
|
|
pMipFactor++;
|
|
pMemoryUsage++;
|
|
pPieces++;
|
|
}
|
|
wasDirty = m_arrRowDirty[y];
|
|
}
|
|
else
|
|
{
|
|
for (x = 0; x < actProcessedSectors.w; x++)
|
|
{
|
|
*pMemoryUsage = 0;
|
|
pMemoryUsage++;
|
|
*pPieces = 0;
|
|
pPieces++;
|
|
}
|
|
wasDirty = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CLocalMemoryUsage::SSector::SSector()
|
|
{
|
|
StartChecking();
|
|
}
|
|
|
|
void CLocalMemoryUsage::SSector::StartChecking()
|
|
{
|
|
m_memoryUsage_Textures = 0;
|
|
m_memoryUsage_Geometry = 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CLocalMemoryUsage::CLocalMemoryUsage()
|
|
{
|
|
REGISTER_CVAR(sys_LocalMemoryTextureLimit, 64, VF_NULL, "LocalMemoryUsage tool: Set the texture memory limit to check streaming (Mb/sec)");
|
|
REGISTER_CVAR(sys_LocalMemoryGeometryLimit, 32, VF_NULL, "LocalMemoryUsage tool: Set the statobj geometry memory limit to check streaming (Mb/sec)");
|
|
REGISTER_CVAR(sys_LocalMemoryTextureStreamingSpeedLimit, 10, VF_NULL, "LocalMemoryUsage tool: Texture streaming speed limit (approx, Mb/sec)");
|
|
REGISTER_CVAR(sys_LocalMemoryGeometryStreamingSpeedLimit, 10, VF_NULL, "LocalMemoryUsage tool: Stat object geometry streaming speed limit (approx, Mb/sec)");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryWarningRatio, 0.8f, VF_NULL, "LocalMemoryUsage tool: Warning ratio for streaming");
|
|
REGISTER_CVAR(sys_LocalMemoryOuterViewDistance, 500.f, VF_NULL, "LocalMemoryUsage tool: View distance for debug draw");
|
|
REGISTER_CVAR(sys_LocalMemoryInnerViewDistance, 100.f, VF_NULL, "LocalMemoryUsage tool: View distance for detailed debug draw");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryStreamingSpeedObjectLength, 10.f, VF_NULL, "LocalMemoryUsage tool: Length of the streaming speed debug object");
|
|
REGISTER_CVAR(sys_LocalMemoryStreamingSpeedObjectWidth, 1.5f, VF_NULL, "LocalMemoryUsage tool: Width of the streaming speed debug object");
|
|
REGISTER_CVAR(sys_LocalMemoryObjectWidth, 6.f, VF_NULL, "LocalMemoryUsage tool: Width of the streaming buffer debug object");
|
|
REGISTER_CVAR(sys_LocalMemoryObjectHeight, 2.f, VF_NULL, "LocalMemoryUsage tool: Height of the streaming buffer debug object");
|
|
REGISTER_CVAR(sys_LocalMemoryObjectAlpha, 128, VF_NULL, "LocalMemoryUsage tool: Color alpha of the debug objects");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramWidth, 0.5f, VF_NULL, "LocalMemoryUsage tool: Width of the diagrams OBSOLATE");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramRadius, 2.5f, VF_NULL, "LocalMemoryUsage tool: Radius of the diagram");
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramDistance, -5.5f, VF_NULL, "LocalMemoryUsage tool: Distance of the diagram from the main debug object");
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramStreamingSpeedRadius, 1.0f, VF_NULL, "LocalMemoryUsage tool: Radius of the streaming speed diagram");
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramStreamingSpeedDistance, 2.2f, VF_NULL, "LocalMemoryUsage tool: Distance of the streaming speed diagram from the streaming speed debug line");
|
|
REGISTER_CVAR(sys_LocalMemoryDiagramAlpha, 255, VF_NULL, "LocalMemoryUsage tool: Color alpha of the diagrams");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryDrawText, 0, VF_NULL, "LocalMemoryUsage tool: If != 0, it will draw the numeric values");
|
|
REGISTER_CVAR(sys_LocalMemoryLogText, 0, VF_NULL, "LocalMemoryUsage tool: If != 0, it will log the numeric values");
|
|
|
|
REGISTER_CVAR(sys_LocalMemoryOptimalMSecPerSec, 100, VF_NULL, "LocalMemoryUsage tool: Optimal calculation time (MSec) per secundum");
|
|
REGISTER_CVAR(sys_LocalMemoryMaxMSecBetweenCalls, 1000, VF_NULL, "LocalMemoryUsage tool: Maximal time difference (MSec) between calls");
|
|
|
|
m_pStreamCgfPredicitionDistance = 0;
|
|
m_pDebugDraw = 0;
|
|
if (gEnv->pConsole)
|
|
{
|
|
m_pStreamCgfPredicitionDistance = gEnv->pConsole->GetCVar("e_StreamCgfPredicitionDistance");
|
|
m_pDebugDraw = gEnv->pConsole->GetCVar("e_DebugDraw");
|
|
}
|
|
|
|
m_sectorNr.zero();
|
|
|
|
m_actProcessedSectors = RectI(0, 0, 0, 0);
|
|
m_actDrawedSectors = RectI(0, 0, 0, 0);
|
|
|
|
m_AverageUpdateTime = 0.01f;
|
|
|
|
m_sectorNr.x = LOCALMEMORY_SECTOR_NR_X; //TODO Check size of the world
|
|
m_sectorNr.y = LOCALMEMORY_SECTOR_NR_Y;
|
|
}
|
|
|
|
CLocalMemoryUsage::~CLocalMemoryUsage()
|
|
{
|
|
DeleteGlobalData();
|
|
}
|
|
|
|
void CLocalMemoryUsage::DeleteGlobalData()
|
|
{
|
|
m_globalTextures.clear();
|
|
m_globalMaterials.clear();
|
|
m_globalStatObjs.clear();
|
|
}
|
|
|
|
void CLocalMemoryUsage::OnRender(IRenderer* pRenderer, const CCamera* camera)
|
|
{
|
|
if (!m_pDebugDraw || (m_pDebugDraw->GetIVal() != 17))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const Matrix34& mat = camera->GetMatrix();
|
|
Vec3 pos;
|
|
Vec3 projectedPos;
|
|
SSector* sector;
|
|
|
|
SAuxGeomRenderFlags auxGeomRenderFlagsClose(e_Mode3D | e_AlphaBlended | e_DrawInFrontOn | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOff);
|
|
SAuxGeomRenderFlags auxGeomRenderFlagsFar(e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOn);
|
|
|
|
IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom();
|
|
|
|
Vec3 cameraPos = mat.GetTranslation();
|
|
|
|
int xMin = max(0, int((cameraPos.x - sys_LocalMemoryOuterViewDistance) / LOCALMEMORY_SECTOR_SIZE));
|
|
int xMax = min(LOCALMEMORY_SECTOR_PER_PASS - 1, int((cameraPos.x + sys_LocalMemoryOuterViewDistance) / LOCALMEMORY_SECTOR_SIZE + 1));
|
|
int yMin = max(0, int((cameraPos.y - sys_LocalMemoryOuterViewDistance) / LOCALMEMORY_SECTOR_SIZE));
|
|
int yMax = min(LOCALMEMORY_SECTOR_PER_PASS - 1, int((cameraPos.y + sys_LocalMemoryOuterViewDistance) / LOCALMEMORY_SECTOR_SIZE + 1));
|
|
m_actDrawedSectors.x = xMin;
|
|
m_actDrawedSectors.y = yMin;
|
|
m_actDrawedSectors.w = xMax - xMin + 1;
|
|
m_actDrawedSectors.h = yMax - yMin + 1;
|
|
|
|
CTimeValue actTime = gEnv->pTimer->GetAsyncTime();
|
|
float timeSin = sin_tpl(actTime.GetSeconds() * 10.0f) * 0.5f + 0.5f;
|
|
|
|
ColorB color;
|
|
ColorB colorOK(LOCALMEMORY_COLOR_OK, sys_LocalMemoryObjectAlpha);
|
|
ColorB colorWarning(LOCALMEMORY_COLOR_WARNING, sys_LocalMemoryObjectAlpha);
|
|
ColorB colorError(LOCALMEMORY_COLOR_ERROR, uint8(sys_LocalMemoryObjectAlpha * timeSin));
|
|
ColorB colorTexture(LOCALMEMORY_COLOR_TEXTURE, sys_LocalMemoryDiagramAlpha);
|
|
ColorB colorGeometry(LOCALMEMORY_COLOR_GEOMETRY, sys_LocalMemoryDiagramAlpha);
|
|
ColorB colorBlack(LOCALMEMORY_COLOR_BLACK);
|
|
f32 fColorOK[4] = {LOCALMEMORY_FCOLOR_OK, 1};
|
|
f32 fColorWarning[4] = {LOCALMEMORY_FCOLOR_WARNING, 1};
|
|
f32 fColorError[4] = {LOCALMEMORY_FCOLOR_ERROR, 1};
|
|
f32 fColorOther[4] = {LOCALMEMORY_FCOLOR_OTHER, 1};
|
|
|
|
f32* pColor;
|
|
Vec3 v0, v1, v2, v3, v4, vTextureDiagram, vTextureDiagram2, vGeometryDiagram, vGeometryDiagram2;
|
|
|
|
float localMemoryTextureLimit = sys_LocalMemoryTextureLimit * 1024.f * 1024.f;
|
|
float localMemoryGeometryLimit = sys_LocalMemoryGeometryLimit * 1024.f * 1024.f;
|
|
|
|
//The assumption is that this is called on Main Thread, otherwise the loop
|
|
//Should be wrapped inside a EnumerateHandlers lambda.
|
|
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
|
const float defaultTerrainHeight = AzFramework::Terrain::TerrainDataRequests::GetDefaultTerrainHeight();
|
|
|
|
for (int y = yMin; y < yMax; y++)
|
|
{
|
|
sector = &m_arrSectors[xMin + y * LOCALMEMORY_SECTOR_NR_X];
|
|
for (int x = xMin; x < xMax; x++)
|
|
{
|
|
pos.x = (x + 0.5f) * LOCALMEMORY_SECTOR_SIZE;
|
|
pos.y = (y + 0.5f) * LOCALMEMORY_SECTOR_SIZE;
|
|
pos.z = terrain ? terrain->GetHeightFromFloats(pos.x, pos.y) : defaultTerrainHeight;
|
|
|
|
if (m_pDebugDraw->GetIVal() == 17)
|
|
{
|
|
float textureRatio = sector->m_memoryUsage_Textures / localMemoryTextureLimit;
|
|
float geometryRatio = sector->m_memoryUsage_Geometry / localMemoryGeometryLimit;
|
|
float maxRatio = max(textureRatio, geometryRatio);
|
|
|
|
v0 = pos;
|
|
v1 = pos + Vec3(-sys_LocalMemoryObjectWidth, -sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectHeight);
|
|
v2 = pos + Vec3(sys_LocalMemoryObjectWidth, -sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectHeight);
|
|
v3 = pos + Vec3(sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectHeight);
|
|
v4 = pos + Vec3(-sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectWidth, sys_LocalMemoryObjectHeight);
|
|
|
|
if (camera->Project(v1, projectedPos) || camera->Project(v2, projectedPos) || camera->Project(v3, projectedPos) || camera->Project(v4, projectedPos))
|
|
{
|
|
vTextureDiagram = pos + Vec3(0.f, sys_LocalMemoryObjectWidth + sys_LocalMemoryDiagramDistance + sys_LocalMemoryDiagramRadius, sys_LocalMemoryObjectHeight);
|
|
vGeometryDiagram = pos + Vec3(0.f, -sys_LocalMemoryObjectWidth - sys_LocalMemoryDiagramDistance - sys_LocalMemoryDiagramRadius, sys_LocalMemoryObjectHeight);
|
|
|
|
if (maxRatio < sys_LocalMemoryWarningRatio)
|
|
{
|
|
color = colorOK;
|
|
pColor = fColorOK;
|
|
}
|
|
else if (maxRatio < 1.0f)
|
|
{
|
|
color = colorWarning;
|
|
pColor = fColorWarning;
|
|
}
|
|
else
|
|
{
|
|
color = colorError;
|
|
pColor = fColorError;
|
|
}
|
|
|
|
bool close = (Distance::Point_Point2D(cameraPos, pos) < sys_LocalMemoryInnerViewDistance);
|
|
if (close)
|
|
{
|
|
pRenderAuxGeom->SetRenderFlags(auxGeomRenderFlagsClose);
|
|
|
|
static int xDebug = 14;
|
|
static int yDebug = 19;
|
|
|
|
if (sys_LocalMemoryDrawText)
|
|
{
|
|
camera->Project(pos, projectedPos);
|
|
|
|
pRenderer->Draw2dLabel(projectedPos.x, projectedPos.y, 1.2f, pColor, true, "Text: %.2fMb Geom: %.2fMb", sector->m_memoryUsage_Textures / (1024.f * 1024.f), sector->m_memoryUsage_Geometry / (1024.f * 1024.f));
|
|
/* For sector debugging
|
|
pRenderer->Draw2dLabel(projectedPos.x, projectedPos.y, 1.2f, pColor, true, "Text: %.1fMb Geom: %.1fMb - %d : %d", sector->m_memoryUsage_Textures/(1024.f*1024.f), sector->m_memoryUsage_Geometry/(1024.f*1024.f), x, y);
|
|
|
|
if( xDebug == x && yDebug == y )
|
|
{
|
|
float sx = projectedPos.x-80;
|
|
float sy = projectedPos.y;
|
|
|
|
for( TStatObjMap::iterator it = m_globalStatObjs.begin(); it != m_globalStatObjs.end(); ++it )
|
|
{
|
|
SStatObjInfo *statObjInfo = &it->second;
|
|
IStatObj* pStatObj = statObjInfo->m_pStatObj;
|
|
|
|
int memoryUsage = 0;
|
|
float mipFactor = statObjInfo->m_arrMipFactor[y * m_actProcessedSectors.w + x];
|
|
if( mipFactor != BIG_NUMBER )
|
|
{
|
|
memoryUsage = statObjInfo->m_streamableContentMemoryUsage;
|
|
}
|
|
sy+=15.f;
|
|
pRenderer->Draw2dLabel(sx, sy, 1.2f, pColor, false, "Geom: %.2fMb %.4f Act:%s Orig:%s %s", memoryUsage/(1024.f*1024.f), mipFactor, pStatObj->GetFilePath(), statObjInfo->m_filePath, statObjInfo->m_bSubObject ? " SUBOBJECT" : "");
|
|
//pRenderer->Draw2dLabel(sx, sy, 1.2f, pColor, false, "Geom: %.2fMb %.4f", memoryUsage/(1024.f*1024.f), mipFactor);
|
|
}
|
|
}
|
|
//*/
|
|
}
|
|
if (sys_LocalMemoryLogText)
|
|
{
|
|
if (xDebug == x && yDebug == y)
|
|
{
|
|
for (TTextureMap::iterator it = m_globalTextures.begin(); it != m_globalTextures.end(); ++it)
|
|
{
|
|
STextureInfo* textureObjInfo = &it->second;
|
|
ITexture* pTexture = textureObjInfo->m_pTexture;
|
|
|
|
float mipFactor = textureObjInfo->m_arrMipFactor[y * m_actProcessedSectors.w + x];
|
|
if (mipFactor != BIG_NUMBER)
|
|
{
|
|
CryLog("Texture: %s %dX%d mipfactor:%.4f", pTexture->GetName(), pTexture->GetWidth(), pTexture->GetHeight(), mipFactor);
|
|
}
|
|
}
|
|
sys_LocalMemoryLogText = false; //Log only once!
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRenderAuxGeom->SetRenderFlags(auxGeomRenderFlagsFar);
|
|
}
|
|
|
|
pRenderAuxGeom->DrawTriangle(v1, color, v2, color, v3, color);
|
|
pRenderAuxGeom->DrawTriangle(v3, color, v4, color, v1, color);
|
|
|
|
pRenderAuxGeom->DrawTriangle(v0, color, v1, color, v4, color);
|
|
pRenderAuxGeom->DrawTriangle(v0, color, v2, color, v1, color);
|
|
pRenderAuxGeom->DrawTriangle(v0, color, v3, color, v2, color);
|
|
pRenderAuxGeom->DrawTriangle(v0, color, v4, color, v3, color);
|
|
|
|
if (close)
|
|
{
|
|
LocalMemoryUsageDrawHelper::DrawCircle(pRenderer, camera, vTextureDiagram, sys_LocalMemoryDiagramRadius, textureRatio, colorTexture, colorBlack);
|
|
LocalMemoryUsageDrawHelper::DrawCircle(pRenderer, camera, vGeometryDiagram, sys_LocalMemoryDiagramRadius, geometryRatio, colorGeometry, colorBlack);
|
|
}
|
|
}
|
|
}
|
|
|
|
sector++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::OnUpdate()
|
|
{
|
|
if (!m_pDebugDraw || (m_pDebugDraw->GetIVal() != 17))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//CryLogAlways("OnUpdate start-----------------------------------------");
|
|
CTimeValue actTime = gEnv->pTimer->GetAsyncTime();
|
|
|
|
float callTimeDiff = (actTime - m_LastCallTime).GetSeconds();
|
|
float neededCallTimeDiff = m_AverageUpdateTime / (sys_LocalMemoryOptimalMSecPerSec / 1000.f);
|
|
|
|
if (callTimeDiff < neededCallTimeDiff && callTimeDiff < sys_LocalMemoryMaxMSecBetweenCalls / 1000.f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DeleteUnusedResources();
|
|
|
|
m_LastCallTime = actTime;
|
|
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - Start", GetISystem(), PROFILE_SYSTEM);
|
|
//StartChecking(RectI(0,0,m_sectorNr.x, m_sectorNr.y));
|
|
StartChecking(m_actDrawedSectors);
|
|
}
|
|
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - CollectGeometry P1", GetISystem(), PROFILE_SYSTEM);
|
|
CollectGeometryP1();
|
|
}
|
|
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - Materials P2", GetISystem(), PROFILE_SYSTEM);
|
|
//We must iterate on materials first
|
|
for (TMaterialMap::iterator it = m_globalMaterials.begin(); it != m_globalMaterials.end(); ++it)
|
|
{
|
|
it->second.CheckOnAllSectorsP2();
|
|
}
|
|
}
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - Textures P2", GetISystem(), PROFILE_SYSTEM);
|
|
for (TTextureMap::iterator it = m_globalTextures.begin(); it != m_globalTextures.end(); ++it)
|
|
{
|
|
it->second.CheckOnAllSectorsP2();
|
|
}
|
|
}
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - StatObjects P2", GetISystem(), PROFILE_SYSTEM);
|
|
for (TStatObjMap::iterator it = m_globalStatObjs.begin(); it != m_globalStatObjs.end(); ++it)
|
|
{
|
|
it->second.CheckOnAllSectorsP2();
|
|
}
|
|
}
|
|
|
|
CTimeValue endTime = gEnv->pTimer->GetAsyncTime();
|
|
m_AverageUpdateTime = LERP(m_AverageUpdateTime, (endTime - actTime).GetSeconds(), 0.5f);
|
|
|
|
//CryLogAlways("OnUpdate end***");
|
|
}
|
|
|
|
void CLocalMemoryUsage::DeleteUnusedResources()
|
|
{
|
|
FRAME_PROFILER("! LocalMemoryUsege::Update - Deleting unused resources", GetISystem(), PROFILE_SYSTEM);
|
|
|
|
// Clear the used flags
|
|
for (TStatObjMap::iterator it = m_globalStatObjs.begin(); it != m_globalStatObjs.end(); ++it)
|
|
{
|
|
it->second.m_used = false;
|
|
}
|
|
|
|
// Iterate on used StatObjs
|
|
int nCount;
|
|
gEnv->p3DEngine->GetLoadedStatObjArray(NULL, nCount);
|
|
std::vector<IStatObj*> objectsArray;
|
|
objectsArray.resize(nCount);
|
|
if (nCount > 0)
|
|
{
|
|
gEnv->p3DEngine->GetLoadedStatObjArray(&objectsArray[0], nCount);
|
|
}
|
|
|
|
for (std::vector<IStatObj*>::iterator it = objectsArray.begin(); it != objectsArray.end(); ++it)
|
|
{
|
|
IStatObj* pStatObj = *it;
|
|
TStatObjMap::iterator findIt = m_globalStatObjs.find((INT_PTR)pStatObj);
|
|
|
|
if (findIt != m_globalStatObjs.end() && strcmp(pStatObj->GetFilePath(), findIt->second.m_filePath) == 0 && !findIt->second.m_bSubObject)
|
|
{
|
|
findIt->second.m_used = true;
|
|
}
|
|
|
|
if (pStatObj->GetFlags() & STATIC_OBJECT_COMPOUND)
|
|
{
|
|
for (int k = 0; k < pStatObj->GetSubObjectCount(); k++)
|
|
{
|
|
if (!pStatObj->GetSubObject(k))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
IStatObj* pSubStatObj = pStatObj->GetSubObject(k)->pStatObj;
|
|
|
|
if (pSubStatObj)
|
|
{
|
|
findIt = m_globalStatObjs.find((INT_PTR)pSubStatObj);
|
|
|
|
if (findIt != m_globalStatObjs.end() && strcmp(pSubStatObj->GetFilePath(), findIt->second.m_filePath) == 0 && findIt->second.m_bSubObject)
|
|
{
|
|
findIt->second.m_used = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Erase non-used StatObjs
|
|
bool changed = true;
|
|
while (changed)
|
|
{
|
|
changed = false;
|
|
for (TStatObjMap::iterator it = m_globalStatObjs.begin(); it != m_globalStatObjs.end(); ++it)
|
|
{
|
|
if (!it->second.m_used)
|
|
{
|
|
m_globalStatObjs.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
for( TTextureMap::iterator it = m_globalTextures.begin(); it != m_globalTextures.end(); ++it )
|
|
it->second.m_used = false;
|
|
|
|
bool changed = true;
|
|
while( changed )
|
|
{
|
|
changed = false;
|
|
for( TTextureMap::iterator it = m_globalTextures.begin(); it != m_globalTextures.end(); ++it )
|
|
{
|
|
if( !it->second.m_used )
|
|
{
|
|
m_globalTextures.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for( TMaterialMap::iterator it = m_globalMaterials.begin(); it != m_globalMaterials.end(); ++it )
|
|
it->second.m_used = false;
|
|
|
|
changed = true;
|
|
while( changed )
|
|
{
|
|
changed = false;
|
|
for( TMaterialMap::iterator it = m_globalMaterials.begin(); it != m_globalMaterials.end(); ++it )
|
|
{
|
|
if( !it->second.m_used )
|
|
{
|
|
m_globalMaterials.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//*/
|
|
}
|
|
void CLocalMemoryUsage::StartChecking(const RectI& actProcessedSectors)
|
|
{
|
|
m_actProcessedSectors = actProcessedSectors;
|
|
|
|
for (int y = 0; y < m_sectorNr.y; y++)
|
|
{
|
|
SSector* sector = &m_arrSectors[y * LOCALMEMORY_SECTOR_NR_X];
|
|
for (int x = 0; x < m_sectorNr.x; x++)
|
|
{
|
|
sector->StartChecking();
|
|
sector++;
|
|
}
|
|
}
|
|
|
|
{
|
|
for (TTextureMap::iterator it = m_globalTextures.begin(); it != m_globalTextures.end(); ++it)
|
|
{
|
|
//FRAME_PROFILER("! LocalMemoryUsege::StartChecking - Textures", GetISystem(), PROFILE_SYSTEM);
|
|
it->second.StartChecking();
|
|
}
|
|
}
|
|
{
|
|
for (TMaterialMap::iterator it = m_globalMaterials.begin(); it != m_globalMaterials.end(); ++it)
|
|
{
|
|
//FRAME_PROFILER("! LocalMemoryUsege::StartChecking - Materials", GetISystem(), PROFILE_SYSTEM);
|
|
it->second.StartChecking();
|
|
}
|
|
}
|
|
{
|
|
for (TStatObjMap::iterator it = m_globalStatObjs.begin(); it != m_globalStatObjs.end(); ++it)
|
|
{
|
|
//FRAME_PROFILER("! LocalMemoryUsege::StartChecking - StatObjects", GetISystem(), PROFILE_SYSTEM);
|
|
it->second.StartChecking();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::CollectGeometryP1()
|
|
{
|
|
ISystem* pSystem = GetISystem();
|
|
I3DEngine* p3DEngine = pSystem->GetI3DEngine();
|
|
|
|
// iterate through all instances
|
|
std::vector<IRenderNode*> renderNodes;
|
|
|
|
uint32 dwCount = 0;
|
|
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_Light);
|
|
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_RenderComponent);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_SkinnedMeshRenderComponent);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_StaticMeshRenderComponent);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_DynamicMeshRenderComponent);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_Decal);
|
|
|
|
if (dwCount > 0)
|
|
{
|
|
renderNodes.resize(dwCount + 1);
|
|
dwCount = 0;
|
|
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_Light, &renderNodes[dwCount]);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_RenderComponent, &renderNodes[dwCount]);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_StaticMeshRenderComponent, &renderNodes[dwCount]);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_DynamicMeshRenderComponent, &renderNodes[dwCount]);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_SkinnedMeshRenderComponent, &renderNodes[dwCount]);
|
|
dwCount += p3DEngine->GetObjectsByType(eERType_Decal, &renderNodes[dwCount]);
|
|
|
|
AABB objBox;
|
|
|
|
for (uint32 dwI = 0; dwI < dwCount; ++dwI)
|
|
{
|
|
IRenderNode* pRenderNode = renderNodes[dwI];
|
|
|
|
if (pRenderNode->m_fWSMaxViewDist < 0.01f)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float objScale = 1.f;
|
|
if (pRenderNode->GetRenderNodeType() == eERType_Decal)
|
|
{
|
|
IDecalRenderNode* pDecal = (IDecalRenderNode*)pRenderNode;
|
|
objScale = max(0.001f, pDecal->GetMatrix().GetColumn0().GetLength());
|
|
}
|
|
else if (pRenderNode->GetRenderNodeType() == eERType_FogVolume)
|
|
{
|
|
objScale = max(0.001f, ((IFogVolumeRenderNode*)pRenderNode)->GetMatrix().GetColumn0().GetLength());
|
|
}
|
|
|
|
float maxViewDist = pRenderNode->m_fWSMaxViewDist;
|
|
pRenderNode->FillBBox(objBox);
|
|
|
|
_smart_ptr<IMaterial> pRenderNodeMat = pRenderNode->GetMaterialOverride();
|
|
|
|
{
|
|
IStatObj* pStatObj = pRenderNode->GetEntityStatObj();
|
|
|
|
if (pStatObj != NULL)
|
|
{
|
|
CheckStatObjMaterialP1(pStatObj, pRenderNodeMat, objBox, maxViewDist, objScale);
|
|
}
|
|
else
|
|
{
|
|
CheckMeshMaterialP1(pRenderNode->GetRenderMesh(0), pRenderNodeMat, objBox, maxViewDist, objScale);
|
|
}
|
|
}
|
|
|
|
for (int dwSlot = 0; dwSlot < pRenderNode->GetSlotCount(); ++dwSlot)
|
|
{
|
|
_smart_ptr<IMaterial> pSlotMat = pRenderNode->GetEntitySlotMaterial(dwSlot);
|
|
if (!pSlotMat)
|
|
{
|
|
pSlotMat = pRenderNodeMat;
|
|
}
|
|
|
|
Matrix34A matParent;
|
|
|
|
if (IStatObj* pStatObj = pRenderNode->GetEntityStatObj(dwSlot, 0, &matParent, true))
|
|
{
|
|
CheckStatObjP1(pStatObj, pRenderNode, objBox, maxViewDist, objScale);
|
|
|
|
_smart_ptr<IMaterial> pStatObjMat = pStatObj->GetMaterial();
|
|
CheckStatObjMaterialP1(pStatObj, pSlotMat ? pSlotMat : pStatObjMat, objBox, maxViewDist, objScale);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
PREFAST_SUPPRESS_WARNING(6262);
|
|
CLocalMemoryUsage::SStatObjInfo* CLocalMemoryUsage::CheckStatObjP1(IStatObj* pStatObj, [[maybe_unused]] IRenderNode* pRenderNode, AABB bounding, float maxViewDist, float scale)
|
|
{
|
|
if (!pStatObj)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (strncmp(pStatObj->GetFilePath(), "%level%", 7) == 0) //HACK %LEVEL% brushes
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
SStatObjInfo* pStatObjInfo = NULL;
|
|
|
|
TStatObjMap::iterator iter = m_globalStatObjs.find((INT_PTR)pStatObj);
|
|
if (iter != m_globalStatObjs.end())
|
|
{
|
|
pStatObjInfo = &iter->second;
|
|
pStatObjInfo->m_streamableContentMemoryUsage = pStatObj->GetStreamableContentMemoryUsage(); //TODO TEMP
|
|
}
|
|
else
|
|
{
|
|
{
|
|
FRAME_PROFILER("! CLocalMemoryUsage::CheckStatObjP1 HASH", GetISystem(), PROFILE_SYSTEM);
|
|
PREFAST_SUPPRESS_WARNING(6262)
|
|
pStatObjInfo = &m_globalStatObjs[(INT_PTR)pStatObj];
|
|
}
|
|
|
|
pStatObjInfo->Init(this);
|
|
pStatObjInfo->m_streamableContentMemoryUsage = pStatObj->GetStreamableContentMemoryUsage();
|
|
//pStatObjInfo->m_pStatObj = pStatObj;
|
|
pStatObjInfo->m_filePath = pStatObj->GetFilePath();
|
|
pStatObjInfo->m_bSubObject = pStatObj->IsSubObject();
|
|
//CollectStatObjInfo_Recursive( pStatObjInfo, pStatObj );
|
|
}
|
|
|
|
pStatObjInfo->CheckOnAllSectorsP1(bounding, maxViewDist, scale, 1.0f);
|
|
|
|
return pStatObjInfo;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
PREFAST_SUPPRESS_WARNING(6262);
|
|
void CLocalMemoryUsage::CheckMaterialP1(_smart_ptr<IMaterial> pMaterial, AABB bounding, float maxViewDist, float scale, float mipFactor)
|
|
{
|
|
if (pMaterial)
|
|
{
|
|
SMaterialInfo* pMaterialInfo = NULL;
|
|
|
|
TMaterialMap::iterator iter = m_globalMaterials.find((INT_PTR)pMaterial.get());
|
|
if (iter != m_globalMaterials.end())
|
|
{
|
|
pMaterialInfo = &iter->second;
|
|
}
|
|
else
|
|
{
|
|
{
|
|
FRAME_PROFILER("! CLocalMemoryUsage::CheckMaterialP1 HASH", GetISystem(), PROFILE_SYSTEM);
|
|
PREFAST_SUPPRESS_WARNING(6262)
|
|
pMaterialInfo = &m_globalMaterials[(INT_PTR)pMaterial.get()];
|
|
}
|
|
pMaterialInfo->Init(this);
|
|
//pMaterialInfo->m_pMaterial=pMaterial;
|
|
CollectMaterialInfo_Recursive(pMaterialInfo, pMaterial);
|
|
}
|
|
|
|
pMaterialInfo->CheckOnAllSectorsP1(bounding, maxViewDist, scale, mipFactor);
|
|
}
|
|
}
|
|
|
|
PREFAST_SUPPRESS_WARNING(6262);
|
|
void CLocalMemoryUsage::CheckChunkMaterialP1(_smart_ptr<IMaterial> pMaterial, AABB bounding, float maxViewDist, float scale, CRenderChunk* pRenderChunk)
|
|
{
|
|
_smart_ptr<IMaterial> pCurrentMaterial = pMaterial;
|
|
|
|
if (pRenderChunk != NULL)
|
|
{
|
|
if (pRenderChunk->m_nMatID < pMaterial->GetSubMtlCount())
|
|
{
|
|
pCurrentMaterial = pMaterial->GetSubMtl(pRenderChunk->m_nMatID);
|
|
}
|
|
|
|
if (pCurrentMaterial != NULL)
|
|
{
|
|
CheckMaterialP1(pCurrentMaterial, bounding, maxViewDist, scale, pRenderChunk->m_texelAreaDensity);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CheckMaterialP1(pCurrentMaterial, bounding, maxViewDist, scale, 1.f);
|
|
}
|
|
}
|
|
|
|
PREFAST_SUPPRESS_WARNING(6262);
|
|
void CLocalMemoryUsage::CheckMeshMaterialP1(IRenderMesh* pRenderMesh, _smart_ptr<IMaterial> pMaterial, AABB bounding, float maxViewDist, float scale)
|
|
{
|
|
if (pRenderMesh)
|
|
{
|
|
if (pMaterial)
|
|
{
|
|
TRenderChunkArray* pChunks = &pRenderMesh->GetChunks();
|
|
|
|
if (pChunks != NULL)
|
|
{
|
|
for (unsigned int i = 0; i < pChunks->size(); i++)
|
|
{
|
|
CheckChunkMaterialP1(pMaterial, bounding, maxViewDist, scale, &(*pChunks)[i]);
|
|
}
|
|
}
|
|
|
|
pChunks = &pRenderMesh->GetChunksSkinned();
|
|
for (unsigned int i = 0; i < pChunks->size(); i++)
|
|
{
|
|
CheckChunkMaterialP1(pMaterial, bounding, maxViewDist, scale, &(*pChunks)[i]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pMaterial)
|
|
{
|
|
CheckChunkMaterialP1(pMaterial, bounding, maxViewDist, scale, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::CheckStatObjMaterialP1(IStatObj* pStatObj, _smart_ptr<IMaterial> pMaterial, AABB bounding, float maxViewDist, float scale)
|
|
{
|
|
if (pStatObj)
|
|
{
|
|
for (int i = 0; i < pStatObj->GetSubObjectCount(); i++)
|
|
{
|
|
CheckStatObjMaterialP1(pStatObj->GetSubObject(i)->pStatObj, pMaterial, bounding, scale, maxViewDist);
|
|
}
|
|
|
|
CheckMeshMaterialP1(pStatObj->GetRenderMesh(), pMaterial, bounding, maxViewDist, scale);
|
|
}
|
|
}
|
|
|
|
void CLocalMemoryUsage::CollectMaterialInfo_Recursive(SMaterialInfo* materialInfo, _smart_ptr<IMaterial> pMaterial)
|
|
{
|
|
SShaderItem& rItem = pMaterial->GetShaderItem();
|
|
|
|
uint32 dwSubMatCount = pMaterial->GetSubMtlCount();
|
|
|
|
for (uint32 dwSubMat = 0; dwSubMat < dwSubMatCount; ++dwSubMat)
|
|
{
|
|
_smart_ptr<IMaterial> pSub = pMaterial->GetSubMtl(dwSubMat);
|
|
|
|
if (pSub)
|
|
{
|
|
CollectMaterialInfo_Recursive(materialInfo, pSub);
|
|
}
|
|
}
|
|
|
|
// this pMaterial
|
|
if (rItem.m_pShaderResources)
|
|
{
|
|
for (auto iter = rItem.m_pShaderResources->GetTexturesResourceMap()->begin();
|
|
iter != rItem.m_pShaderResources->GetTexturesResourceMap()->end(); ++iter)
|
|
{
|
|
const SEfResTexture* pTextureRes = &iter->second;
|
|
|
|
if (pTextureRes->m_Sampler.m_pITex)
|
|
{
|
|
ITexture* pTexture = pTextureRes->m_Sampler.m_pITex;
|
|
if (pTexture && pTexture->GetStreamableMipNumber() > 0)
|
|
{
|
|
STextureInfoAndTilingFactor textureInfo;
|
|
|
|
textureInfo.m_pTextureInfo = GetTextureInfo(pTexture);
|
|
textureInfo.m_tilingFactor = pTextureRes->GetTiling(0) * pTextureRes->GetTiling(1);
|
|
|
|
materialInfo->AddTextureInfo(textureInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
PREFAST_SUPPRESS_WARNING(6262)
|
|
CLocalMemoryUsage::STextureInfo * CLocalMemoryUsage::GetTextureInfo(ITexture * pTexture)
|
|
{
|
|
if (!pTexture)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
TTextureMap::iterator iter = m_globalTextures.find((INT_PTR)pTexture);
|
|
if (iter != m_globalTextures.end())
|
|
{
|
|
return &iter->second;
|
|
}
|
|
|
|
//FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM);
|
|
STextureInfo* pTextureInfo;
|
|
{
|
|
FRAME_PROFILER("! CLocalMemoryUsage::CheckStatObjP1 HASH", GetISystem(), PROFILE_SYSTEM);
|
|
PREFAST_SUPPRESS_WARNING(6262)
|
|
pTextureInfo = &m_globalTextures[(INT_PTR)pTexture];
|
|
}
|
|
pTextureInfo->Init(this);
|
|
pTextureInfo->m_pTexture = pTexture;
|
|
pTexture->AddRef();
|
|
|
|
//Collect informations
|
|
//pTextureInfo->m_size = pTexture->GetDeviceDataSize();
|
|
//pTextureInfo->m_xSize = pTexture->GetWidth();
|
|
//pTextureInfo->m_ySize = pTexture->GetHeight();
|
|
//pTextureInfo->m_numMips = pTexture->GetNumMips();
|
|
|
|
return pTextureInfo;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|