Switch to the new allocator
This commit is contained in:
parent
fd9a9d1c25
commit
3248499d5a
|
@ -41,6 +41,7 @@
|
|||
* FIXME:
|
||||
*
|
||||
* - Allocations < 2048 can still cross boundaries
|
||||
* - Only operates on one pool (ignores what you pass)
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -73,6 +74,7 @@ typedef struct {
|
|||
size_t pool_size; // Size of the memory pool
|
||||
uint8_t* base_address; // First 2k aligned address in the pool
|
||||
size_t block_count; // Number of 2k blocks in the pool
|
||||
bool defrag_in_progress;
|
||||
|
||||
/* It's frustrating that we need to do this dynamically
|
||||
* but we need to know the size allocated when we free()...
|
||||
|
@ -86,7 +88,7 @@ typedef struct {
|
|||
|
||||
|
||||
static PoolHeader pool_header = {
|
||||
{0}, NULL, 0, NULL, 0, NULL
|
||||
{0}, NULL, 0, NULL, 0, false, NULL
|
||||
};
|
||||
|
||||
void* alloc_base_address(void* pool) {
|
||||
|
@ -100,6 +102,8 @@ size_t alloc_block_count(void* pool) {
|
|||
}
|
||||
|
||||
void* alloc_next_available(void* pool, size_t required_size) {
|
||||
(void) pool;
|
||||
|
||||
uint8_t* it = pool_header.block_usage;
|
||||
uint32_t required_subblocks = (required_size / 256);
|
||||
if(required_size % 256) required_subblocks += 1;
|
||||
|
@ -301,6 +305,8 @@ void* alloc_malloc(void* pool, size_t size) {
|
|||
}
|
||||
|
||||
void alloc_free(void* pool, void* p) {
|
||||
(void) pool;
|
||||
|
||||
struct AllocEntry* it = pool_header.allocations;
|
||||
struct AllocEntry* last = NULL;
|
||||
while(it) {
|
||||
|
@ -354,17 +360,73 @@ void alloc_free(void* pool, void* p) {
|
|||
}
|
||||
|
||||
void alloc_defrag_start(void* pool) {
|
||||
|
||||
(void) pool;
|
||||
pool_header.defrag_in_progress = true;
|
||||
}
|
||||
|
||||
void* alloc_defrag_address(void* pool, void* p) {
|
||||
|
||||
(void) pool;
|
||||
return p;
|
||||
}
|
||||
|
||||
void alloc_defrag_commit(void* pool) {
|
||||
|
||||
(void) pool;
|
||||
pool_header.defrag_in_progress = false;
|
||||
}
|
||||
|
||||
bool alloc_defrag_in_progress(void* pool) {
|
||||
|
||||
(void) pool;
|
||||
return pool_header.defrag_in_progress;
|
||||
}
|
||||
|
||||
static inline uint8_t count_ones(uint8_t byte) {
|
||||
static const uint8_t NIBBLE_LOOKUP [16] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4
|
||||
};
|
||||
return NIBBLE_LOOKUP[byte & 0x0F] + NIBBLE_LOOKUP[byte >> 4];
|
||||
}
|
||||
|
||||
size_t alloc_count_free(void* pool) {
|
||||
uint8_t* it = pool_header.block_usage;
|
||||
uint8_t* end = it + pool_header.block_count;
|
||||
|
||||
size_t total_free = 0;
|
||||
|
||||
while(it < end) {
|
||||
total_free += count_ones(*it) * 256;
|
||||
++it;
|
||||
}
|
||||
|
||||
return total_free;
|
||||
}
|
||||
|
||||
size_t alloc_count_continuous(void* pool) {
|
||||
(void) pool;
|
||||
|
||||
size_t largest_block = 0;
|
||||
|
||||
uint8_t* it = pool_header.block_usage;
|
||||
uint8_t* end = it + pool_header.block_count;
|
||||
|
||||
size_t current_block = 0;
|
||||
while(it < end) {
|
||||
uint8_t t = *it++;
|
||||
if(!t) {
|
||||
current_block += 2048;
|
||||
} else {
|
||||
for(int i = 7; i >= 0; --i) {
|
||||
bool bitset = (t & (1 << i));
|
||||
if(bitset) {
|
||||
current_block += (7 - i) * 256;
|
||||
if(largest_block < current_block) {
|
||||
largest_block = current_block;
|
||||
current_block = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return largest_block;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ void* alloc_defrag_address(void* pool, void* p);
|
|||
void alloc_defrag_commit(void* pool);
|
||||
bool alloc_defrag_in_progress(void* pool);
|
||||
|
||||
size_t alloc_count_free(void* pool);
|
||||
size_t alloc_count_continuous(void* pool);
|
||||
|
||||
void* alloc_next_available(void* pool, size_t required_size);
|
||||
void* alloc_base_address(void* pool);
|
||||
size_t alloc_block_count(void* pool);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#define CLIP_DEBUG 0
|
||||
#define ZNEAR_CLIPPING_ENABLED 1
|
||||
|
||||
static size_t AVAILABLE_VRAM = 16 * 1024 * 1024;
|
||||
static size_t AVAILABLE_VRAM = 8 * 1024 * 1024;
|
||||
static Matrix4x4 MATRIX;
|
||||
|
||||
static SDL_Window* WINDOW = NULL;
|
||||
|
|
46
GL/texture.c
46
GL/texture.c
|
@ -8,7 +8,7 @@
|
|||
#include "config.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include "yalloc/yalloc.h"
|
||||
#include "alloc/alloc.h"
|
||||
|
||||
/* We always leave this amount of vram unallocated to prevent
|
||||
* issues with the allocator */
|
||||
|
@ -31,8 +31,8 @@ static GLboolean SUBBANKS_USED[MAX_GLDC_PALETTE_SLOTS][MAX_GLDC_4BPP_PALETTE_SLO
|
|||
static GLenum INTERNAL_PALETTE_FORMAT = GL_RGBA8;
|
||||
static GLboolean TEXTURE_TWIDDLE_ENABLED = GL_FALSE;
|
||||
|
||||
static void* YALLOC_BASE = NULL;
|
||||
static size_t YALLOC_SIZE = 0;
|
||||
static void* ALLOC_BASE = NULL;
|
||||
static size_t ALLOC_SIZE = 0;
|
||||
|
||||
static const unsigned short MortonTable256[256] =
|
||||
{
|
||||
|
@ -84,15 +84,15 @@ GL_FORCE_INLINE uint32_t twid_location(uint32_t i, uint32_t w, uint32_t h) {
|
|||
}
|
||||
|
||||
|
||||
static void* yalloc_alloc_and_defrag(size_t size) {
|
||||
void* ret = yalloc_alloc(YALLOC_BASE, size);
|
||||
static void* alloc_malloc_and_defrag(size_t size) {
|
||||
void* ret = alloc_malloc(ALLOC_BASE, size);
|
||||
|
||||
if(!ret) {
|
||||
/* Tried to allocate, but out of room, let's try defragging
|
||||
* and repeating the alloc */
|
||||
fprintf(stderr, "Ran out of memory, defragmenting\n");
|
||||
glDefragmentTextureMemory_KOS();
|
||||
ret = yalloc_alloc(YALLOC_BASE, size);
|
||||
ret = alloc_malloc(ALLOC_BASE, size);
|
||||
}
|
||||
|
||||
gl_assert(ret && "Out of PVR memory!");
|
||||
|
@ -505,15 +505,15 @@ GLubyte _glInitTextures() {
|
|||
//memset((void*) SUBBANKS_USED, 0x0, sizeof(SUBBANKS_USED));
|
||||
|
||||
size_t vram_free = GPUMemoryAvailable();
|
||||
YALLOC_SIZE = vram_free - PVR_MEM_BUFFER_SIZE; /* Take all but 64kb VRAM */
|
||||
YALLOC_BASE = GPUMemoryAlloc(YALLOC_SIZE);
|
||||
ALLOC_SIZE = vram_free - PVR_MEM_BUFFER_SIZE; /* Take all but 64kb VRAM */
|
||||
ALLOC_BASE = GPUMemoryAlloc(ALLOC_SIZE);
|
||||
|
||||
#ifdef __DREAMCAST__
|
||||
/* Ensure memory is aligned */
|
||||
gl_assert((uintptr_t) YALLOC_BASE % 32 == 0);
|
||||
#endif
|
||||
|
||||
yalloc_init(YALLOC_BASE, YALLOC_SIZE);
|
||||
alloc_init(ALLOC_BASE, ALLOC_SIZE);
|
||||
|
||||
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
||||
return 1;
|
||||
|
@ -610,7 +610,7 @@ void APIENTRY glDeleteTextures(GLsizei n, GLuint *textures) {
|
|||
}
|
||||
|
||||
if(txr->data) {
|
||||
yalloc_free(YALLOC_BASE, txr->data);
|
||||
alloc_free(ALLOC_BASE, txr->data);
|
||||
txr->data = NULL;
|
||||
}
|
||||
|
||||
|
@ -858,10 +858,10 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target,
|
|||
|
||||
/* Odds are slim new data is same size as old, so free always */
|
||||
if(active->data) {
|
||||
yalloc_free(YALLOC_BASE, active->data);
|
||||
alloc_free(ALLOC_BASE, active->data);
|
||||
}
|
||||
|
||||
active->data = yalloc_alloc_and_defrag(imageSize);
|
||||
active->data = alloc_malloc_and_defrag(imageSize);
|
||||
|
||||
gl_assert(active->data); // Debug assert
|
||||
|
||||
|
@ -1242,14 +1242,14 @@ void _glAllocateSpaceForMipmaps(TextureObject* active) {
|
|||
memcpy(temp, active->data, size);
|
||||
|
||||
/* Free the PVR data */
|
||||
yalloc_free(YALLOC_BASE, active->data);
|
||||
alloc_free(ALLOC_BASE, active->data);
|
||||
active->data = NULL;
|
||||
}
|
||||
|
||||
/* Figure out how much room to allocate for mipmaps */
|
||||
GLuint bytes = _glGetMipmapDataSize(active);
|
||||
|
||||
active->data = yalloc_alloc_and_defrag(bytes);
|
||||
active->data = alloc_malloc_and_defrag(bytes);
|
||||
|
||||
gl_assert(active->data);
|
||||
|
||||
|
@ -1389,7 +1389,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
active->height != height ||
|
||||
active->internalFormat != cleanInternalFormat) {
|
||||
/* changed - free old texture memory */
|
||||
yalloc_free(YALLOC_BASE, active->data);
|
||||
alloc_free(ALLOC_BASE, active->data);
|
||||
active->data = NULL;
|
||||
active->mipmap = 0;
|
||||
active->mipmapCount = 0;
|
||||
|
@ -1434,7 +1434,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
/* If we're uploading a mipmap level, we need to allocate the full amount of space */
|
||||
_glAllocateSpaceForMipmaps(active);
|
||||
} else {
|
||||
active->data = yalloc_alloc_and_defrag(active->baseDataSize);
|
||||
active->data = alloc_malloc_and_defrag(active->baseDataSize);
|
||||
}
|
||||
|
||||
active->isCompressed = GL_FALSE;
|
||||
|
@ -1856,23 +1856,23 @@ GLAPI void APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height
|
|||
gl_assert(0 && "Not Implemented");
|
||||
}
|
||||
GLuint _glMaxTextureMemory() {
|
||||
return YALLOC_SIZE;
|
||||
return ALLOC_SIZE;
|
||||
}
|
||||
|
||||
GLuint _glFreeTextureMemory() {
|
||||
return yalloc_count_free(YALLOC_BASE);
|
||||
return alloc_count_free(ALLOC_BASE);
|
||||
}
|
||||
|
||||
GLuint _glUsedTextureMemory() {
|
||||
return YALLOC_SIZE - _glFreeTextureMemory();
|
||||
return ALLOC_SIZE - _glFreeTextureMemory();
|
||||
}
|
||||
|
||||
GLuint _glFreeContiguousTextureMemory() {
|
||||
return yalloc_count_continuous(YALLOC_BASE);
|
||||
return alloc_count_continuous(ALLOC_BASE);
|
||||
}
|
||||
|
||||
GLAPI GLvoid APIENTRY glDefragmentTextureMemory_KOS(void) {
|
||||
yalloc_defrag_start(YALLOC_BASE);
|
||||
alloc_defrag_start(ALLOC_BASE);
|
||||
|
||||
GLuint id;
|
||||
|
||||
|
@ -1881,11 +1881,11 @@ GLAPI GLvoid APIENTRY glDefragmentTextureMemory_KOS(void) {
|
|||
TextureObject* txr = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, id);
|
||||
if(txr){
|
||||
gl_assert(txr->index == id);
|
||||
txr->data = yalloc_defrag_address(YALLOC_BASE, txr->data);
|
||||
txr->data = alloc_defrag_address(ALLOC_BASE, txr->data);
|
||||
}
|
||||
}
|
||||
|
||||
yalloc_defrag_commit(YALLOC_BASE);
|
||||
alloc_defrag_commit(ALLOC_BASE);
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY glGetTexImage(GLenum tex, GLint lod, GLenum format, GLenum type, GLvoid* img) {
|
||||
|
|
|
@ -16,7 +16,7 @@ static inline int round_up(int n, int multiple)
|
|||
|
||||
class AllocatorTests : public test::TestCase {
|
||||
public:
|
||||
uint8_t pool[16 * 2048];
|
||||
uint8_t __attribute__((aligned(2048))) pool[16 * 2048];
|
||||
|
||||
void set_up() {
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
|||
assert_equal(alloc_next_available(pool, 16), expected_base_address);
|
||||
assert_equal(alloc_base_address(pool), expected_base_address);
|
||||
|
||||
int expected_blocks = (
|
||||
size_t expected_blocks = (
|
||||
uintptr_t(pool + sizeof(pool)) -
|
||||
uintptr_t(expected_base_address)
|
||||
) / 2048;
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
void test_alloc_malloc() {
|
||||
alloc_init(pool, sizeof(pool));
|
||||
|
||||
void* base_address = alloc_base_address(pool);
|
||||
uint8_t* base_address = (uint8_t*) alloc_base_address(pool);
|
||||
void* a1 = alloc_malloc(pool, 1024);
|
||||
|
||||
/* First alloc should always be the base address */
|
||||
|
|
Loading…
Reference in New Issue
Block a user