mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-15 05:29:51 +01:00
f691b4b4b0
Renames previous METRICS to COUNTERS. These are still reset to zero every frame. Adds new METRICS which are preserved, maintained externally to speeds, and only sampled by speeds code once per frame. Also adds new metrics: - `studio.cached_submodels` -- number of submodels in cache - `geom.used` -- memory used by long allocations - `geom.{vertices,indices}` -- counts of vertices/indices for long allocations - `geom.dyn_{vertices,indices}` -- counts of vertices/indices for single-frame dynamic allocations
117 lines
3.6 KiB
C
117 lines
3.6 KiB
C
#include "r_block.h"
|
|
|
|
#include "vk_common.h" // ASSERT
|
|
#include "vk_core.h" // vk_core.pool
|
|
|
|
typedef struct r_blocks_block_s {
|
|
int long_index;
|
|
uint32_t refcount;
|
|
} r_blocks_block_t;
|
|
|
|
// logical blocks
|
|
// <---- lifetime long -><-- once -->
|
|
// [.....................|............]
|
|
// <--- pool --><-- ring --->
|
|
// offset ? --->
|
|
|
|
int allocMetablock(r_blocks_t *blocks) {
|
|
return aloIntPoolAlloc(&blocks->blocks.freelist);
|
|
// TODO grow if needed
|
|
}
|
|
|
|
r_block_t R_BlockAllocLong(r_blocks_t *blocks, uint32_t size, uint32_t alignment) {
|
|
r_block_t ret = {
|
|
.offset = ALO_ALLOC_FAILED,
|
|
.size = 0,
|
|
.impl_ = {-1}
|
|
};
|
|
|
|
const alo_block_t ablock = aloPoolAllocate(blocks->long_pool, size, alignment);
|
|
if (ablock.offset == ALO_ALLOC_FAILED) {
|
|
gEngine.Con_Reportf(S_ERROR "aloPoolAllocate failed\n");
|
|
return ret;
|
|
}
|
|
|
|
const int metablock_index = allocMetablock(blocks);
|
|
if (metablock_index < 0) {
|
|
gEngine.Con_Reportf(S_ERROR "allocMetablock failed\n");
|
|
aloPoolFree(blocks->long_pool, ablock.index);
|
|
return ret;
|
|
}
|
|
|
|
ret.offset = ablock.offset;
|
|
ret.size = ablock.size;
|
|
ret.impl_.index = metablock_index;
|
|
ret.impl_.blocks = blocks;
|
|
|
|
r_blocks_block_t *metablock = blocks->blocks.storage + metablock_index;
|
|
metablock->long_index = ablock.index;
|
|
metablock->refcount = 1;
|
|
|
|
/* gEngine.Con_Reportf("block alloc %dKiB => index=%d offset=%u\n", (int)size/1024, metablock_index, (int)ret.offset); */
|
|
|
|
blocks->allocated_long += size;
|
|
return ret;
|
|
}
|
|
|
|
uint32_t R_BlockAllocOnce(r_blocks_t *blocks, uint32_t size, uint32_t alignment) {
|
|
const uint32_t offset = R_FlippingBuffer_Alloc(&blocks->once.flipping, size, alignment);
|
|
if (offset == ALO_ALLOC_FAILED)
|
|
return ALO_ALLOC_FAILED;
|
|
|
|
return offset + blocks->once.ring_offset;
|
|
}
|
|
|
|
void R_BlocksCreate(r_blocks_t *blocks, uint32_t size, uint32_t once_size, int expected_allocs) {
|
|
memset(blocks, 0, sizeof(*blocks));
|
|
|
|
blocks->size = size;
|
|
blocks->allocated_long = 0;
|
|
|
|
blocks->long_pool = aloPoolCreate(size - once_size, expected_allocs, 4);
|
|
aloIntPoolGrow(&blocks->blocks.freelist, expected_allocs);
|
|
blocks->blocks.storage = Mem_Malloc(vk_core.pool, expected_allocs * sizeof(blocks->blocks.storage[0]));
|
|
|
|
blocks->once.ring_offset = size - once_size;
|
|
R_FlippingBuffer_Init(&blocks->once.flipping, once_size);
|
|
}
|
|
|
|
void R_BlockRelease(const r_block_t *block) {
|
|
r_blocks_t *const blocks = block->impl_.blocks;
|
|
if (!blocks || !block->size)
|
|
return;
|
|
|
|
ASSERT(block->impl_.index >= 0);
|
|
ASSERT(block->impl_.index < blocks->blocks.freelist.capacity);
|
|
|
|
r_blocks_block_t *const metablock = blocks->blocks.storage + block->impl_.index;
|
|
|
|
/* gEngine.Con_Reportf("block release index=%d offset=%u refcount=%d\n", block->impl_.index, (int)block->offset, (int)metablock->refcount); */
|
|
|
|
ASSERT (metablock->refcount > 0);
|
|
if (--metablock->refcount)
|
|
return;
|
|
|
|
/* gEngine.Con_Reportf("block free index=%d offset=%u\n", block->impl_.index, (int)block->offset); */
|
|
|
|
aloPoolFree(blocks->long_pool, metablock->long_index);
|
|
aloIntPoolFree(&blocks->blocks.freelist, block->impl_.index);
|
|
blocks->allocated_long -= block->size;
|
|
}
|
|
|
|
void R_BlocksDestroy(r_blocks_t *blocks) {
|
|
for (int i = blocks->blocks.freelist.free; i < blocks->blocks.freelist.capacity; ++i) {
|
|
r_blocks_block_t *b = blocks->blocks.storage + blocks->blocks.freelist.free_list[i];
|
|
ASSERT(b->refcount == 0);
|
|
}
|
|
|
|
aloPoolDestroy(blocks->long_pool);
|
|
aloIntPoolDestroy(&blocks->blocks.freelist);
|
|
Mem_Free(blocks->blocks.storage);
|
|
}
|
|
|
|
// Clear all LifetimeOnce blocks, checking that they are not referenced by anything
|
|
void R_BlocksClearOnce(r_blocks_t *blocks) {
|
|
R_FlippingBuffer_Flip(&blocks->once.flipping);
|
|
}
|