From c9abbde679cd5345388a1e4184dfd40ec45e3aba Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 30 Sep 2024 20:38:11 +1000 Subject: [PATCH] Dreamcast: Simplify texture management --- src/Graphics_Dreamcast.c | 72 +++++--- third_party/gldc/src/gldc.h | 44 ++--- third_party/gldc/src/state.c | 5 +- third_party/gldc/src/texture.c | 206 +++------------------- third_party/gldc/src/yalloc/yalloc_dump.c | 39 ---- 5 files changed, 79 insertions(+), 287 deletions(-) delete mode 100644 third_party/gldc/src/yalloc/yalloc_dump.c diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index a2abec4ca..aada72a13 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -227,18 +227,6 @@ void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); } /*########################################################################################################################* *---------------------------------------------------------Textures--------------------------------------------------------* *#########################################################################################################################*/ -void Gfx_BindTexture(GfxResourceID texId) { - gldcBindTexture((GLuint)texId); - STATE_DIRTY = true; -} - -void Gfx_DeleteTexture(GfxResourceID* texId) { - GLuint id = (GLuint)(*texId); - if (!id) return; - gldcDeleteTexture(id); - *texId = 0; -} - void Gfx_EnableMipmaps(void) { } void Gfx_DisableMipmaps(void) { } @@ -332,18 +320,31 @@ static void ConvertTexture(cc_uint16* dst, struct Bitmap* bmp, int rowWidth) { } } +static TextureObject* FindFreeTexture(void) { + unsigned int id; + + // ID 0 is reserved for default texture + for (int i = 1; i < MAX_TEXTURE_COUNT; i++) + { + TextureObject* tex = &TEXTURE_LIST[i]; + if (tex->data == NULL) return tex; + } + return NULL; +} + static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { - GLuint texId = gldcGenTexture(); - gldcBindTexture(texId); - - int res = gldcAllocTexture(bmp->width, bmp->height, PVR_TXRFMT_ARGB4444); - if (res) { Platform_LogConst("Out of PVR VRAM!"); return 0; } - - void* pixels; - int width, height; - gldcGetTexture(&pixels, &width, &height); - ConvertTexture(pixels, bmp, rowWidth); - return (GfxResourceID)texId; + TextureObject* tex = FindFreeTexture(); + if (!tex) return NULL; + + tex->width = bmp->width; + tex->height = bmp->height; + tex->color = PVR_TXRFMT_ARGB4444; + + tex->data = texmem_alloc(bmp->width * bmp->height * 2); + if (!tex->data) { Platform_LogConst("Out of PVR VRAM!"); return NULL; } + + ConvertTexture(tex->data, bmp, rowWidth); + return tex; } // TODO: struct GPUTexture ?? @@ -373,17 +374,30 @@ static void ConvertSubTexture(cc_uint16* dst, int texWidth, int texHeight, } void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) { - gldcBindTexture((GLuint)texId); - - void* pixels; - int width, height; - gldcGetTexture(&pixels, &width, &height); + TextureObject* tex = (TextureObject*)texId; - ConvertSubTexture(pixels, width, height, + ConvertSubTexture(tex->data, tex->width, tex->height, x, y, part, rowWidth); // TODO: Do we need to flush VRAM? } +void Gfx_BindTexture(GfxResourceID texId) { + if (!texId) texId = &TEXTURE_LIST[0]; + + TEXTURE_ACTIVE = (TextureObject*)texId; + STATE_DIRTY = true; +} + +void Gfx_DeleteTexture(GfxResourceID* texId) { + TextureObject* tex = (TextureObject*)(*texId); + if (!tex) return; + + texmem_free(tex->data); + tex->data = NULL; + *texId = 0; +} + + /*########################################################################################################################* *-----------------------------------------------------State management----------------------------------------------------* diff --git a/third_party/gldc/src/gldc.h b/third_party/gldc/src/gldc.h index 810c8ce73..52995c869 100644 --- a/third_party/gldc/src/gldc.h +++ b/third_party/gldc/src/gldc.h @@ -6,25 +6,11 @@ #define MAX_TEXTURE_COUNT 768 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_OUT_OF_MEMORY 0x0505 - -#define GLushort unsigned short #define GLuint unsigned int #define GLenum unsigned int -#define GLubyte unsigned char #define GLboolean unsigned char -GLuint gldcGenTexture(void); -void gldcDeleteTexture(GLuint texture); -void gldcBindTexture(GLuint texture); - -/* Loads texture from SH4 RAM into PVR VRAM */ -int gldcAllocTexture(int w, int h, int format); -void gldcGetTexture(void** data, int* width, int* height); - void glKosInit(); void glKosSwapBuffers(); @@ -45,24 +31,23 @@ typedef struct { #define GL_FORCE_INLINE static __attribute__((always_inline)) inline typedef struct { - //0 - GLuint index; - GLuint color; /* This is the PVR texture format */ - //8 - GLenum minFilter; - GLenum magFilter; - //16 - void *data; - //20 - GLushort width; - GLushort height; -} __attribute__((aligned(32))) TextureObject; + uint32_t color; /* This is the PVR texture format */ + void *data; + uint16_t width; + uint16_t height; +} TextureObject; void _glInitTextures(); +void* texmem_alloc(size_t size); +void texmem_free(void* ptr); + +GLuint _glFreeTextureMemory(void); +GLuint _glUsedTextureMemory(void); extern TextureObject* TEXTURE_ACTIVE; extern GLboolean TEXTURES_ENABLED; +extern TextureObject TEXTURE_LIST[MAX_TEXTURE_COUNT]; extern GLboolean DEPTH_TEST_ENABLED; extern GLboolean DEPTH_MASK_ENABLED; @@ -89,13 +74,6 @@ GL_FORCE_INLINE AlignedVector* _glActivePolyList() { return &OP_LIST; } -/* Memory allocation extension (GL_KOS_texture_memory_management) */ -void glDefragmentTextureMemory_KOS(void); - -GLuint _glFreeTextureMemory(void); -GLuint _glUsedTextureMemory(void); -GLuint _glFreeContiguousTextureMemory(void); - extern GLboolean STATE_DIRTY; void SceneListSubmit(Vertex* v2, int n, int type); diff --git a/third_party/gldc/src/state.c b/third_party/gldc/src/state.c index e02144e7e..f0ef0092a 100644 --- a/third_party/gldc/src/state.c +++ b/third_party/gldc/src/state.c @@ -141,11 +141,8 @@ void apply_poly_header(pvr_poly_hdr_t* dst, int list_type) { if (txr_enable == PVR_TEXTURE_DISABLE) { dst->mode3 = 0; } else { - GLuint filter = PVR_FILTER_NEAREST; - if (tx1->minFilter == GL_LINEAR && tx1->magFilter == GL_LINEAR) filter = PVR_FILTER_BILINEAR; - dst->mode2 |= (txr_alpha << PVR_TA_PM2_TXRALPHA_SHIFT) & PVR_TA_PM2_TXRALPHA_MASK; - dst->mode2 |= (filter << PVR_TA_PM2_FILTER_SHIFT) & PVR_TA_PM2_FILTER_MASK; + dst->mode2 |= (PVR_FILTER_NEAREST << PVR_TA_PM2_FILTER_SHIFT) & PVR_TA_PM2_FILTER_MASK; dst->mode2 |= (DEFAULT_MIPMAP_BIAS << PVR_TA_PM2_MIPBIAS_SHIFT) & PVR_TA_PM2_MIPBIAS_MASK; dst->mode2 |= (PVR_TXRENV_MODULATEALPHA << PVR_TA_PM2_TXRENV_SHIFT) & PVR_TA_PM2_TXRENV_MASK; diff --git a/third_party/gldc/src/texture.c b/third_party/gldc/src/texture.c index 5f8e1af13..35180a52e 100644 --- a/third_party/gldc/src/texture.c +++ b/third_party/gldc/src/texture.c @@ -4,194 +4,57 @@ #include #include #include - #include "gldc.h" #include "yalloc/yalloc.h" -#ifndef NDEBUG -/* We're debugging, use normal assert */ -#include -#define gl_assert assert -#else -/* Release mode, use our custom assert */ - -#define gl_assert(x) \ - do {\ - if(!(x)) {\ - fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\ - exit(1);\ - }\ - } while(0); \ - -#endif - - /* We always leave this amount of vram unallocated to prevent * issues with the allocator */ #define PVR_MEM_BUFFER_SIZE (64 * 1024) TextureObject* TEXTURE_ACTIVE = NULL; -static TextureObject TEXTURE_LIST[MAX_TEXTURE_COUNT]; -static unsigned char TEXTURE_USED[MAX_TEXTURE_COUNT / 8]; +TextureObject TEXTURE_LIST[MAX_TEXTURE_COUNT]; +static void* YALLOC_BASE; +static size_t YALLOC_SIZE; -static int texture_id_map_used(unsigned int id) { - unsigned int i = id / 8; - unsigned int j = id % 8; +static void glDefragmentTextureMemory_KOS(void) { + yalloc_defrag_start(YALLOC_BASE); - return TEXTURE_USED[i] & (unsigned char)(1 << j); -} + /* Replace all texture pointers */ + for(int i = 1; i < MAX_TEXTURE_COUNT; i++) + { + TextureObject* txr = &TEXTURE_LIST[i]; + if (!txr->data) continue; -static void texture_id_map_reserve(unsigned int id) { - unsigned int i = id / 8; - unsigned int j = id % 8; - TEXTURE_USED[i] |= (unsigned char)(1 << j); -} - -static void texture_id_map_release(unsigned int id) { - unsigned int i = id / 8; - unsigned int j = id % 8; - TEXTURE_USED[i] &= (unsigned char)~(1 << j); -} - -unsigned int texture_id_map_alloc(void) { - unsigned int id; - - // ID 0 is reserved for default texture - for(id = 1; id < MAX_TEXTURE_COUNT; ++id) { - if(!texture_id_map_used(id)) { - texture_id_map_reserve(id); - return id; - } - } - return 0; -} - - -static void* YALLOC_BASE = NULL; -static size_t YALLOC_SIZE = 0; - -static void* yalloc_alloc_and_defrag(size_t size) { - void* ret = yalloc_alloc(YALLOC_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); + txr->data = yalloc_defrag_address(YALLOC_BASE, txr->data); } - gl_assert(ret && "Out of PVR memory!"); - - return ret; -} - -static void _glInitializeTextureObject(TextureObject* txr, unsigned int id) { - txr->index = id; - txr->width = txr->height = 0; - txr->data = NULL; - txr->minFilter = GL_NEAREST; - txr->magFilter = GL_NEAREST; + yalloc_defrag_commit(YALLOC_BASE); } void _glInitTextures() { - memset(TEXTURE_USED, 0, sizeof(TEXTURE_USED)); - - // Initialize zero as an actual texture object though because apparently it is! - TextureObject* default_tex = &TEXTURE_LIST[0]; - _glInitializeTextureObject(default_tex, 0); - texture_id_map_reserve(0); - TEXTURE_ACTIVE = default_tex; + TEXTURE_ACTIVE = &TEXTURE_LIST[0]; size_t vram_free = pvr_mem_available(); YALLOC_SIZE = vram_free - PVR_MEM_BUFFER_SIZE; /* Take all but 64kb VRAM */ YALLOC_BASE = pvr_mem_malloc(YALLOC_SIZE); -#ifdef __DREAMCAST__ - /* Ensure memory is aligned */ - gl_assert((uintptr_t) YALLOC_BASE % 32 == 0); -#endif - yalloc_init(YALLOC_BASE, YALLOC_SIZE); } -GLuint gldcGenTexture(void) { - GLuint id = texture_id_map_alloc(); - gl_assert(id); // Generated IDs must never be zero - - TextureObject* txr = &TEXTURE_LIST[id]; - _glInitializeTextureObject(txr, id); +void* texmem_alloc(size_t size) { + void* ret = yalloc_alloc(YALLOC_BASE, size); + if(ret) return ret; - gl_assert(txr->index == id); - - return id; + /* 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); + return ret; } -void gldcDeleteTexture(GLuint id) { - if(id == 0) return; - /* Zero is the "default texture" and we never allow deletion of it */ - - if(texture_id_map_used(id)) { - TextureObject* txr = &TEXTURE_LIST[id]; - gl_assert(txr->index == id); - - if(txr == TEXTURE_ACTIVE) { - // Reset to the default texture - TEXTURE_ACTIVE = &TEXTURE_LIST[0]; - } - - if(txr->data) { - yalloc_free(YALLOC_BASE, txr->data); - txr->data = NULL; - } - - texture_id_map_release(id); - } -} - -void gldcBindTexture(GLuint id) { - gl_assert(texture_id_map_used(id)); - TextureObject* txr = &TEXTURE_LIST[id]; - - TEXTURE_ACTIVE = txr; - gl_assert(TEXTURE_ACTIVE->index == id); -} - -int gldcAllocTexture(int w, int h, int format) { - TextureObject* active = TEXTURE_ACTIVE; - - if (active->data) { - /* pre-existing texture - check if changed */ - if (active->width != w || active->height != h) { - /* changed - free old texture memory */ - yalloc_free(YALLOC_BASE, active->data); - active->data = NULL; - } - } - - /* All colour formats are represented as shorts internally. */ - GLuint bytes = w * h * 2; - active->width = w; - active->height = h; - active->color = format; - - if(!active->data) { - /* need texture memory */ - active->data = yalloc_alloc_and_defrag(bytes); - } - if (!active->data) return GL_OUT_OF_MEMORY; - return 0; -} - -void gldcGetTexture(void** data, int* width, int* height) { - TextureObject* active = TEXTURE_ACTIVE; - *data = active->data; - *width = active->width; - *height = active->height; -} - -GLuint _glMaxTextureMemory() { - return YALLOC_SIZE; +void texmem_free(void* ptr) { + yalloc_free(YALLOC_BASE, ptr); } GLuint _glFreeTextureMemory() { @@ -201,24 +64,3 @@ GLuint _glFreeTextureMemory() { GLuint _glUsedTextureMemory() { return YALLOC_SIZE - _glFreeTextureMemory(); } - -GLuint _glFreeContiguousTextureMemory() { - return yalloc_count_continuous(YALLOC_BASE); -} - -void glDefragmentTextureMemory_KOS(void) { - yalloc_defrag_start(YALLOC_BASE); - - GLuint id; - - /* Replace all texture pointers */ - for(id = 0; id < MAX_TEXTURE_COUNT; id++){ - if(texture_id_map_used(id)){ - TextureObject* txr = &TEXTURE_LIST[id]; - gl_assert(txr->index == id); - txr->data = yalloc_defrag_address(YALLOC_BASE, txr->data); - } - } - - yalloc_defrag_commit(YALLOC_BASE); -} diff --git a/third_party/gldc/src/yalloc/yalloc_dump.c b/third_party/gldc/src/yalloc/yalloc_dump.c deleted file mode 100644 index f0dfdcbcd..000000000 --- a/third_party/gldc/src/yalloc/yalloc_dump.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "yalloc_internals.h" - -#include - -static void printOffset(void * pool, char * name, uint16_t offset) -{ - if (isNil(offset)) - printf(" %s: nil\n", name); - else - printf(" %s: %td\n", name, (char*)HDR_PTR(offset) - (char*)pool); -} - -void yalloc_dump(void * pool, char * name) -{ - printf("---- %s ----\n", name); - Header * cur = (Header*)pool; - for (;;) - { - printf(isFree(cur) ? "%td: free @%p\n" : "%td: used @%p\n", (char*)cur - (char*)pool, cur); - printOffset(pool, cur == pool ? "first free" : "prev", cur->prev); - printOffset(pool, "next", cur->next); - if (isFree(cur)) - { - printOffset(pool, "prevFree", cur[1].prev); - printOffset(pool, "nextFree", cur[1].next); - } - else - printf(" payload includes padding: %i\n", isPadded(cur)); - - if (isNil(cur->next)) - break; - - printf(" %td bytes payload\n", (char*)HDR_PTR(cur->next) - (char*)cur - sizeof(Header)); - - cur = HDR_PTR(cur->next); - } - - fflush(stdout); -}