mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-22 09:01:57 -05:00
Dreamcast: Simplify texture management
This commit is contained in:
parent
fb5d022a76
commit
c9abbde679
5 changed files with 79 additions and 287 deletions
|
@ -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----------------------------------------------------*
|
||||
|
|
44
third_party/gldc/src/gldc.h
vendored
44
third_party/gldc/src/gldc.h
vendored
|
@ -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);
|
||||
|
|
5
third_party/gldc/src/state.c
vendored
5
third_party/gldc/src/state.c
vendored
|
@ -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;
|
||||
|
||||
|
|
206
third_party/gldc/src/texture.c
vendored
206
third_party/gldc/src/texture.c
vendored
|
@ -4,194 +4,57 @@
|
|||
#include <string.h>
|
||||
#include <kos.h>
|
||||
#include <dc/pvr.h>
|
||||
|
||||
#include "gldc.h"
|
||||
#include "yalloc/yalloc.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* We're debugging, use normal assert */
|
||||
#include <assert.h>
|
||||
#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);
|
||||
}
|
||||
|
|
39
third_party/gldc/src/yalloc/yalloc_dump.c
vendored
39
third_party/gldc/src/yalloc/yalloc_dump.c
vendored
|
@ -1,39 +0,0 @@
|
|||
#include "yalloc_internals.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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);
|
||||
}
|
Loading…
Reference in a new issue