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