diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 8222db6..45e2ebc 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -41,6 +41,7 @@ * FIXME: * * - Allocations < 2048 can still cross boundaries + * - Only operates on one pool (ignores what you pass) */ #include @@ -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; } diff --git a/GL/alloc/alloc.h b/GL/alloc/alloc.h index 466c80a..d69bb9f 100644 --- a/GL/alloc/alloc.h +++ b/GL/alloc/alloc.h @@ -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); diff --git a/GL/platforms/software.c b/GL/platforms/software.c index d9d7fc8..4245930 100644 --- a/GL/platforms/software.c +++ b/GL/platforms/software.c @@ -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; diff --git a/GL/texture.c b/GL/texture.c index 13f7605..aebfde5 100644 --- a/GL/texture.c +++ b/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) { diff --git a/tests/test_allocator.h b/tests/test_allocator.h index 3f2b762..32ac1cc 100644 --- a/tests/test_allocator.h +++ b/tests/test_allocator.h @@ -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 */