Makes TextRenderer allocates using LinearAllocator

Also replaces DynamicArena for model and terrain rendering by
LinearAllocator.
This commit is contained in:
Vladislav Belov 2025-10-12 00:53:12 +02:00
parent e4de94415e
commit 893f192eaa
No known key found for this signature in database
GPG key ID: 353545E45DB9CCB3
7 changed files with 102 additions and 70 deletions

View file

@ -52,6 +52,7 @@ constexpr size_t MAX_CHAR_COUNT_PER_BATCH = 65536 / 4;
} // anonymous namespace
CTextRenderer::CTextRenderer()
: m_ScopedLinearAllocator{g_Renderer.GetLinearAllocator()}, m_Batches(m_ScopedLinearAllocator)
{
ResetTranslate();
SetCurrentColor(CColor(1.0f, 1.0f, 1.0f, 1.0f));
@ -174,7 +175,7 @@ void CTextRenderer::PutString(float x, float y, const std::wstring* buf, bool ow
// If any state has changed since the last batch, start a new batch
if (m_Dirty)
{
SBatch batch;
SBatch batch{m_ScopedLinearAllocator};
batch.chars = 0;
batch.translate = m_Translate;
batch.color = m_Color;
@ -210,16 +211,16 @@ void CTextRenderer::Render(
const CVector2D& transformScale, const CVector2D& translation,
const bool debugFontBox, const CColor& debugBoxColor)
{
std::vector<u16> indices;
std::vector<CVector2D> positions;
std::vector<CVector2D> uvs;
std::vector<u16, ProxyAllocator<u16, PS::Memory::ScopedLinearAllocator>> indices{m_ScopedLinearAllocator};
std::vector<CVector2D, ProxyAllocator<CVector2D, PS::Memory::ScopedLinearAllocator>> positions{m_ScopedLinearAllocator};
std::vector<CVector2D, ProxyAllocator<CVector2D, PS::Memory::ScopedLinearAllocator>> uvs{m_ScopedLinearAllocator};
// Try to merge non-consecutive batches that share the same font/color/translate:
// sort the batch list by font, then merge the runs of adjacent compatible batches
m_Batches.sort(SBatchCompare());
for (std::list<SBatch>::iterator it = m_Batches.begin(); it != m_Batches.end(); )
for (SBatchList::iterator it = m_Batches.begin(); it != m_Batches.end(); )
{
std::list<SBatch>::iterator next = std::next(it);
SBatchList::iterator next = std::next(it);
if (next != m_Batches.end() && it->chars + next->chars <= MAX_CHAR_COUNT_PER_BATCH && it->font == next->font && it->color == next->color && it->translate == next->translate)
{
it->chars += next->chars;
@ -238,10 +239,8 @@ void CTextRenderer::Render(
bool translationChanged = false;
CTexture* lastTexture = nullptr;
for (std::list<SBatch>::iterator it = m_Batches.begin(); it != m_Batches.end(); ++it)
for (SBatch& batch : m_Batches)
{
SBatch& batch = *it;
if (lastTexture != batch.font->GetTexture().get())
{
batch.font->InitalizeAtlasTextureIfNeeded(deviceCommandContext);
@ -294,9 +293,8 @@ void CTextRenderer::Render(
idx = 0;
};
for (std::list<SBatchRun>::iterator runit = batch.runs.begin(); runit != batch.runs.end(); ++runit)
for (SBatchRun& run : batch.runs)
{
SBatchRun& run = *runit;
float x{std::ceil(run.x)};
float y{std::ceil(run.y)};
for (size_t i = 0; i < run.text->size(); ++i)

View file

@ -19,9 +19,11 @@
#define INCLUDED_TEXTRENDERER
#include "graphics/Color.h"
#include "lib/allocators/STLAllocators.h"
#include "maths/Rect.h"
#include "maths/Vector2D.h"
#include "ps/CStrIntern.h"
#include "ps/memory/LinearAllocator.h"
#include <cstddef>
#include <list>
@ -159,11 +161,16 @@ private:
CVector2D translate;
CColor color;
CFont* font;
std::list<SBatchRun> runs;
using SBatchRunList = std::list<SBatchRun, ProxyAllocator<SBatchRun, PS::Memory::ScopedLinearAllocator>>;
SBatchRunList runs;
SBatch(PS::Memory::ScopedLinearAllocator& allocator) : runs{allocator} {}
};
void PutString(float x, float y, const std::wstring* buf, bool owned);
PS::Memory::ScopedLinearAllocator m_ScopedLinearAllocator;
CVector2D m_Translate;
CRect m_Clipping;
@ -173,7 +180,8 @@ private:
bool m_Dirty = true;
std::list<SBatch> m_Batches;
using SBatchList = std::list<SBatch, ProxyAllocator<SBatch, PS::Memory::ScopedLinearAllocator>>;
SBatchList m_Batches;
};
#endif // INCLUDED_TEXTRENDERER

View file

@ -29,7 +29,6 @@
#include "graphics/Terrain.h"
#include "graphics/TextureManager.h"
#include "lib/alignment.h"
#include "lib/allocators/DynamicArena.h"
#include "lib/allocators/STLAllocators.h"
#include "lib/debug.h"
#include "lib/posix/posix_types.h"
@ -38,6 +37,7 @@
#include "ps/CLogger.h"
#include "ps/CStrIntern.h"
#include "ps/CStrInternStatic.h"
#include "ps/memory/LinearAllocator.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
#include "renderer/TerrainRenderer.h"
@ -143,12 +143,10 @@ void CDecalRData::RenderDecals(
PROFILE3("render terrain decals");
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain decals");
using Arena = Allocators::DynamicArena<256 * KiB>;
PS::Memory::ScopedLinearAllocator scopedLinearAllocator{g_Renderer.GetLinearAllocator()};
Arena arena;
using Batches = std::vector<SDecalBatch, ProxyAllocator<SDecalBatch, Arena>>;
Batches batches((Batches::allocator_type(arena)));
using Batches = std::vector<SDecalBatch, ProxyAllocator<SDecalBatch, PS::Memory::ScopedLinearAllocator>>;
Batches batches((Batches::allocator_type(scopedLinearAllocator)));
batches.reserve(decals.size());
CShaderDefines contextDecal = context;

View file

@ -31,7 +31,6 @@
#include "graphics/Texture.h"
#include "graphics/TextureManager.h"
#include "lib/alignment.h"
#include "lib/allocators/DynamicArena.h"
#include "lib/allocators/STLAllocators.h"
#include "lib/debug.h"
#include "lib/hash.h"
@ -41,6 +40,7 @@
#include "ps/CLogger.h"
#include "ps/CStrIntern.h"
#include "ps/CStrInternStatic.h"
#include "ps/memory/LinearAllocator.h"
#include "ps/Profile.h"
#include "renderer/MikktspaceWrap.h"
#include "renderer/ModelRenderer.h"
@ -441,10 +441,9 @@ void ShaderModelRenderer::Render(
* list in each, rebinding the GL state whenever it changes.
*/
using Arena = Allocators::DynamicArena<256 * KiB>;
PS::Memory::ScopedLinearAllocator scopedLinearAllocator{g_Renderer.GetLinearAllocator()};
Arena arena;
using ModelListAllocator = ProxyAllocator<CModel*, Arena>;
using ModelListAllocator = ProxyAllocator<CModel*, PS::Memory::ScopedLinearAllocator>;
using ModelList_t = std::vector<CModel*, ModelListAllocator>;
using MaterialBuckets_t = std::unordered_map<
SMRMaterialBucketKey,
@ -453,9 +452,9 @@ void ShaderModelRenderer::Render(
std::equal_to<SMRMaterialBucketKey>,
ProxyAllocator<
std::pair<const SMRMaterialBucketKey, ModelList_t>,
Arena> >;
PS::Memory::ScopedLinearAllocator>>;
MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena)));
MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(scopedLinearAllocator)));
{
PROFILE3("bucketing by material");
@ -470,7 +469,7 @@ void ShaderModelRenderer::Render(
if (it == materialBuckets.end())
{
std::pair<MaterialBuckets_t::iterator, bool> inserted = materialBuckets.insert(
std::make_pair(key, ModelList_t(ModelList_t::allocator_type(arena))));
std::make_pair(key, ModelList_t(ModelList_t::allocator_type(scopedLinearAllocator))));
inserted.first->second.reserve(32);
inserted.first->second.push_back(model);
}
@ -481,19 +480,19 @@ void ShaderModelRenderer::Render(
}
}
using SortByDistItemsAllocator = ProxyAllocator<SMRSortByDistItem, Arena>;
std::vector<SMRSortByDistItem, SortByDistItemsAllocator> sortByDistItems((SortByDistItemsAllocator(arena)));
using SortByDistItemsAllocator = ProxyAllocator<SMRSortByDistItem, PS::Memory::ScopedLinearAllocator>;
std::vector<SMRSortByDistItem, SortByDistItemsAllocator> sortByDistItems((SortByDistItemsAllocator(scopedLinearAllocator)));
using SortByTechItemsAllocator = ProxyAllocator<CShaderTechniquePtr, Arena>;
std::vector<CShaderTechniquePtr, SortByTechItemsAllocator> sortByDistTechs((SortByTechItemsAllocator(arena)));
using SortByTechItemsAllocator = ProxyAllocator<CShaderTechniquePtr, PS::Memory::ScopedLinearAllocator>;
std::vector<CShaderTechniquePtr, SortByTechItemsAllocator> sortByDistTechs((SortByTechItemsAllocator(scopedLinearAllocator)));
// indexed by sortByDistItems[i].techIdx
// (which stores indexes instead of CShaderTechniquePtr directly
// to avoid the shared_ptr copy cost when sorting; maybe it'd be better
// if we just stored raw CShaderTechnique* and assumed the shader manager
// will keep it alive long enough)
using TechBucketsAllocator = ProxyAllocator<SMRTechBucket, Arena>;
std::vector<SMRTechBucket, TechBucketsAllocator> techBuckets((TechBucketsAllocator(arena)));
using TechBucketsAllocator = ProxyAllocator<SMRTechBucket, PS::Memory::ScopedLinearAllocator>;
std::vector<SMRTechBucket, TechBucketsAllocator> techBuckets((TechBucketsAllocator(scopedLinearAllocator)));
{
PROFILE3("processing material buckets");
@ -555,7 +554,7 @@ void ShaderModelRenderer::Render(
// (This exists primarily because techBuckets wants a CModel**;
// we could avoid the cost of copying into this list by adding
// a stride length into techBuckets and not requiring contiguous CModel*s)
std::vector<CModel*, ModelListAllocator> sortByDistModels((ModelListAllocator(arena)));
std::vector<CModel*, ModelListAllocator> sortByDistModels((ModelListAllocator(scopedLinearAllocator)));
if (!sortByDistItems.empty())
{
@ -608,19 +607,19 @@ void ShaderModelRenderer::Render(
// This vector keeps track of texture changes during rendering. It is kept outside the
// loops to avoid excessive reallocations. The token allocation of 64 elements
// should be plenty, though it is reallocated below (at a cost) if necessary.
using TextureListAllocator = ProxyAllocator<CTexture*, Arena>;
std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena)));
using TextureListAllocator = ProxyAllocator<CTexture*, PS::Memory::ScopedLinearAllocator>;
std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(scopedLinearAllocator)));
currentTexs.reserve(64);
// texBindings holds the identifier bindings in the shader, which can no longer be defined
// statically in the ShaderRenderModifier class. texBindingNames uses interned strings to
// keep track of when bindings need to be reevaluated.
using BindingListAllocator = ProxyAllocator<int32_t, Arena>;
std::vector<int32_t, BindingListAllocator> texBindings((BindingListAllocator(arena)));
using BindingListAllocator = ProxyAllocator<int32_t, PS::Memory::ScopedLinearAllocator>;
std::vector<int32_t, BindingListAllocator> texBindings((BindingListAllocator(scopedLinearAllocator)));
texBindings.reserve(64);
using BindingNamesListAllocator = ProxyAllocator<CStrIntern, Arena>;
std::vector<CStrIntern, BindingNamesListAllocator> texBindingNames((BindingNamesListAllocator(arena)));
using BindingNamesListAllocator = ProxyAllocator<CStrIntern, PS::Memory::ScopedLinearAllocator>;
std::vector<CStrIntern, BindingNamesListAllocator> texBindingNames((BindingNamesListAllocator(scopedLinearAllocator)));
texBindingNames.reserve(64);
while (idxTechStart < techBuckets.size())

View file

@ -35,7 +35,6 @@
#include "graphics/TextRenderer.h"
#include "graphics/TextureManager.h"
#include "lib/alignment.h"
#include "lib/allocators/DynamicArena.h"
#include "lib/allocators/STLAllocators.h"
#include "lib/code_generation.h"
#include "lib/debug.h"
@ -45,6 +44,7 @@
#include "ps/CStrIntern.h"
#include "ps/CStrInternStatic.h"
#include "ps/Game.h"
#include "ps/memory/LinearAllocator.h"
#include "ps/Profile.h"
#include "renderer/AlphaMapCalculator.h"
#include "renderer/BlendShapes.h"
@ -841,16 +841,14 @@ void CPatchRData::Update(CSimulation2* simulation)
// batches uses a arena allocator. (All allocations are short-lived so we can
// just throw away the whole arena at the end of each frame.)
using Arena = Allocators::DynamicArena<1 * MiB>;
// std::map types with appropriate arena allocators and default comparison operator
template<class Key, class Value>
using PooledBatchMap = std::map<Key, Value, std::less<Key>, ProxyAllocator<std::pair<Key const, Value>, Arena>>;
using PooledBatchMap = std::map<Key, Value, std::less<Key>, ProxyAllocator<std::pair<Key const, Value>, PS::Memory::ScopedLinearAllocator>>;
// Equivalent to "m[k]", when it returns a arena-allocated std::map (since we can't
// use the default constructor in that case)
template<typename M>
typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, Arena& arena)
typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, PS::Memory::ScopedLinearAllocator& arena)
{
return m.insert(std::make_pair(k,
typename M::mapped_type(typename M::mapped_type::key_compare(), typename M::mapped_type::allocator_type(arena))
@ -859,7 +857,7 @@ typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, Arena
// Equivalent to "m[k]", when it returns a std::pair of arena-allocated std::vectors
template<typename M>
typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, Arena& arena)
typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, PS::Memory::ScopedLinearAllocator& arena)
{
return m.insert(std::make_pair(k, std::make_pair(
typename M::mapped_type::first_type(typename M::mapped_type::first_type::allocator_type(arena)),
@ -868,7 +866,7 @@ typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, Aren
}
// Each multidraw batch has a list of index counts, and a list of pointers-to-first-indexes
using BatchElements = std::pair<std::vector<u32, ProxyAllocator<u32, Arena>>, std::vector<u32, ProxyAllocator<u32, Arena>>>;
using BatchElements = std::pair<std::vector<u32, ProxyAllocator<u32, PS::Memory::ScopedLinearAllocator>>, std::vector<u32, ProxyAllocator<u32, PS::Memory::ScopedLinearAllocator>>>;
// Group batches by index buffer
using IndexBufferBatches = PooledBatchMap<CVertexBuffer*, BatchElements>;
@ -890,9 +888,9 @@ void CPatchRData::RenderBases(
PROFILE3("render terrain bases");
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain bases");
Arena arena;
PS::Memory::ScopedLinearAllocator scopedLinearAllocator{g_Renderer.GetLinearAllocator()};
ShaderTechniqueBatches batches(ShaderTechniqueBatches::key_compare(), (ShaderTechniqueBatches::allocator_type(arena)));
ShaderTechniqueBatches batches(ShaderTechniqueBatches::key_compare(), (ShaderTechniqueBatches::allocator_type(scopedLinearAllocator)));
PROFILE_START("compute batches");
@ -913,12 +911,12 @@ void CPatchRData::RenderBases(
BatchElements& batch = PooledPairGet(
PooledMapGet(
PooledMapGet(
PooledMapGet(batches, std::make_pair(material.GetShaderEffect(), material.GetShaderDefines()), arena),
splat.m_Texture, arena
PooledMapGet(batches, std::make_pair(material.GetShaderEffect(), material.GetShaderDefines()), scopedLinearAllocator),
splat.m_Texture, scopedLinearAllocator
),
patch->m_VBBase->m_Owner, arena
patch->m_VBBase->m_Owner, scopedLinearAllocator
),
patch->m_VBBaseIndices->m_Owner, arena
patch->m_VBBaseIndices->m_Owner, scopedLinearAllocator
);
batch.first.push_back(splat.m_IndexCount);
@ -1015,8 +1013,8 @@ void CPatchRData::RenderBases(
*/
struct SBlendBatch
{
SBlendBatch(Arena& arena) :
m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(arena))
SBlendBatch(PS::Memory::ScopedLinearAllocator& allocator) :
m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(allocator))
{
}
@ -1031,12 +1029,12 @@ struct SBlendBatch
struct SBlendStackItem
{
SBlendStackItem(CVertexBuffer::VBChunk* v, CVertexBuffer::VBChunk* i,
const std::vector<CPatchRData::SSplat>& s, Arena& arena) :
vertices(v), indices(i), splats(s.begin(), s.end(), SplatStack::allocator_type(arena))
const std::vector<CPatchRData::SSplat>& s, PS::Memory::ScopedLinearAllocator& allocator) :
vertices(v), indices(i), splats(s.begin(), s.end(), SplatStack::allocator_type(allocator))
{
}
using SplatStack = std::vector<CPatchRData::SSplat, ProxyAllocator<CPatchRData::SSplat, Arena>>;
using SplatStack = std::vector<CPatchRData::SSplat, ProxyAllocator<CPatchRData::SSplat, PS::Memory::ScopedLinearAllocator>>;
CVertexBuffer::VBChunk* vertices;
CVertexBuffer::VBChunk* indices;
SplatStack splats;
@ -1050,10 +1048,10 @@ void CPatchRData::RenderBlends(
PROFILE3("render terrain blends");
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain blends");
Arena arena;
PS::Memory::ScopedLinearAllocator scopedLinearAllocator{g_Renderer.GetLinearAllocator()};
using BatchesStack = std::vector<SBlendBatch, ProxyAllocator<SBlendBatch, Arena>>;
BatchesStack batches((BatchesStack::allocator_type(arena)));
using BatchesStack = std::vector<SBlendBatch, ProxyAllocator<SBlendBatch, PS::Memory::ScopedLinearAllocator>>;
BatchesStack batches((BatchesStack::allocator_type(scopedLinearAllocator)));
CShaderDefines contextBlend = context;
contextBlend.Add(str_BLEND, str_1);
@ -1064,8 +1062,8 @@ void CPatchRData::RenderBlends(
// to avoid heavy reallocations
batches.reserve(256);
using BlendStacks = std::vector<SBlendStackItem, ProxyAllocator<SBlendStackItem, Arena>>;
BlendStacks blendStacks((BlendStacks::allocator_type(arena)));
using BlendStacks = std::vector<SBlendStackItem, ProxyAllocator<SBlendStackItem, PS::Memory::ScopedLinearAllocator>>;
BlendStacks blendStacks((BlendStacks::allocator_type(scopedLinearAllocator)));
blendStacks.reserve(patches.size());
// Extract all the blend splats from each patch
@ -1074,8 +1072,7 @@ void CPatchRData::RenderBlends(
CPatchRData* patch = patches[i];
if (!patch->m_BlendSplats.empty())
{
blendStacks.push_back(SBlendStackItem(patch->m_VBBlends.Get(), patch->m_VBBlendIndices.Get(), patch->m_BlendSplats, arena));
blendStacks.push_back(SBlendStackItem(patch->m_VBBlends.Get(), patch->m_VBBlendIndices.Get(), patch->m_BlendSplats, scopedLinearAllocator));
// Reverse the splats so the first to be rendered is at the back of the list
std::reverse(blendStacks.back().splats.begin(), blendStacks.back().splats.end());
}
@ -1100,7 +1097,7 @@ void CPatchRData::RenderBlends(
CVertexBuffer::VBChunk* vertices = blendStacks[k].vertices;
CVertexBuffer::VBChunk* indices = blendStacks[k].indices;
BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, arena), indices->m_Owner, arena);
BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, scopedLinearAllocator), indices->m_Owner, scopedLinearAllocator);
batch.first.push_back(splats.back().m_IndexCount);
batch.second.push_back(indices->m_Index + splats.back().m_IndexStart);
@ -1126,7 +1123,7 @@ void CPatchRData::RenderBlends(
if (bestStackSize == 0)
break;
SBlendBatch layer(arena);
SBlendBatch layer(scopedLinearAllocator);
layer.m_Texture = bestTex;
if (!bestTex->GetMaterial().GetSamplers().empty())
{

View file

@ -53,6 +53,7 @@
#include "ps/Game.h"
#include "ps/GameSetup/Config.h"
#include "ps/Globals.h"
#include "ps/memory/LinearAllocator.h"
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "ps/Profiler2.h"
@ -99,7 +100,7 @@ class CRendererStatsTable : public AbstractProfileTable
{
NONCOPYABLE(CRendererStatsTable);
public:
CRendererStatsTable(const CRenderer::Stats& st);
CRendererStatsTable(const CRenderer::Stats& st, const PS::Memory::LinearAllocator& linearAllocator);
// Implementation of AbstractProfileTable interface
CStr GetName() override;
@ -112,6 +113,7 @@ public:
private:
/// Reference to the renderer singleton's stats
const CRenderer::Stats& Stats;
const PS::Memory::LinearAllocator& m_LinearAllocator;
/// Column descriptions
std::vector<ProfileColumn> columnDescriptions;
@ -129,6 +131,7 @@ private:
Row_VBAllocated,
Row_TextureMemory,
Row_ShadersLoaded,
Row_LinearAllocator,
// Must be last to count number of rows
NumberRows
@ -136,8 +139,8 @@ private:
};
// Construction
CRendererStatsTable::CRendererStatsTable(const CRenderer::Stats& st)
: Stats(st)
CRendererStatsTable::CRendererStatsTable(const CRenderer::Stats& st, const PS::Memory::LinearAllocator& linearAllocator)
: Stats(st), m_LinearAllocator(linearAllocator)
{
columnDescriptions.push_back(ProfileColumn("Name", 230));
columnDescriptions.push_back(ProfileColumn("Value", 100));
@ -236,6 +239,12 @@ CStr CRendererStatsTable::GetCellText(size_t row, size_t col)
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)g_Renderer.GetShaderManager().GetNumEffectsLoaded());
return buf;
case Row_LinearAllocator:
if (col == 0)
return "linear allocator";
sprintf_s(buf, sizeof(buf), "%lu", static_cast<unsigned long>(m_LinearAllocator.GetCapacity()));
return buf;
default:
return "???";
}
@ -292,6 +301,13 @@ public:
CFontManager fontManager;
// During rendering we need to collect and sort many objects. To reduce
// the allocation cost and increase cache locality we use the
// LinearAllocator.
// If we need to have more than 16MiB of continious memory then we're doing
// a lot of unnecessary work.
PS::Memory::LinearAllocator linearAllocator{1 * MiB, 16 * MiB};
struct VertexAttributesHash
{
size_t operator()(const std::vector<Renderer::Backend::SVertexAttributeFormat>& attributes) const;
@ -304,7 +320,7 @@ public:
Internals(Renderer::Backend::IDevice* device) :
device(device),
deviceCommandContext(device->CreateCommandContext()),
IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats),
IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats, linearAllocator),
shaderManager(device), textureManager(g_VFS, false, device), vertexBufferManager(device),
postprocManager(device), sceneRenderer(device)
{
@ -623,6 +639,8 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
PROFILE2_ATTR("particles: %zu", stats.m_Particles);
g_Profiler2.RecordGPUFrameEnd(m->deviceCommandContext.get());
m->linearAllocator.Release();
}
void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger)
@ -858,6 +876,8 @@ void CRenderer::EndFrame()
PROFILE3("end frame");
m->sceneRenderer.EndFrame();
m->linearAllocator.Release();
}
void CRenderer::MakeShadersDirty()
@ -930,3 +950,8 @@ Renderer::Backend::IVertexInputLayout* CRenderer::GetVertexInputLayout(
it->second = m->device->CreateVertexInputLayout(attributes);
return it->second.get();
}
PS::Memory::LinearAllocator& CRenderer::GetLinearAllocator()
{
return m->linearAllocator;
}

View file

@ -33,6 +33,7 @@ class CShaderManager;
class CTextureManager;
class CTimeManager;
class CVertexBufferManager;
namespace PS::Memory { class LinearAllocator; }
namespace Renderer::Backend { class IDevice; }
namespace Renderer::Backend { class IDeviceCommandContext; }
namespace Renderer::Backend { class IVertexInputLayout; }
@ -144,6 +145,12 @@ public:
Renderer::Backend::IVertexInputLayout* GetVertexInputLayout(
const std::span<const Renderer::Backend::SVertexAttributeFormat> attributes);
/**
* Currently using the linear allocated is allowed in small scopes to avoid
* high memory overhead. To validate that use PS::Memory::ScopedLinearAllocator.
*/
PS::Memory::LinearAllocator& GetLinearAllocator();
protected:
friend class CDecalRData;
friend class CPatchRData;