forked from 0ad/0ad
no message
This was SVN commit r27.
This commit is contained in:
parent
b27731c9cc
commit
88bbb5148a
@ -119,9 +119,9 @@ int build_font(const char* in_ttf, const char* out_fnt, const char* out_raw, int
|
||||
#endif
|
||||
|
||||
|
||||
static void font_dtor(HDATA* hd)
|
||||
static void font_dtor(void* p)
|
||||
{
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
FONT* font = (FONT*)p;
|
||||
glDeleteLists(font->list_base, 96);
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ u32 font_load(const char* fn)
|
||||
void* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, RES_FONT, font_dtor, p, size, hd);
|
||||
Handle h = res_load(fn, H_FONT, font_dtor, p, size, hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
@ -191,7 +191,7 @@ u32 font_load(const char* fn)
|
||||
u = 0.f, v += th;
|
||||
}
|
||||
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
FONT* font = (FONT*)hd->user;
|
||||
font->tex = tex;
|
||||
font->list_base = list_base;
|
||||
|
||||
@ -201,10 +201,10 @@ u32 font_load(const char* fn)
|
||||
|
||||
int font_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_FONT);
|
||||
HDATA* hd = h_data(h, H_FONT);
|
||||
if(!hd)
|
||||
return -1;
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
FONT* font = (FONT*)hd->user;
|
||||
|
||||
tex_bind(font->tex);
|
||||
glListBase(font->list_base);
|
||||
|
@ -14,15 +14,20 @@
|
||||
struct MEM
|
||||
{
|
||||
uint type;
|
||||
void* org_p; // MEM_HEAP only
|
||||
size_t size; // MEM_POOL only
|
||||
|
||||
// MEM_HEAP only
|
||||
void* org_p;
|
||||
|
||||
// MEM_POOL only
|
||||
size_t ofs;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void heap_dtor(HDATA* hd)
|
||||
static void heap_dtor(void* p)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
MEM* mem = (MEM*)p;
|
||||
free(mem->org_p);
|
||||
}
|
||||
|
||||
@ -43,13 +48,12 @@ static size_t pool_pos;
|
||||
static const size_t POOL_CAP = 64*MB; // TODO: user editable
|
||||
|
||||
|
||||
static void pool_dtor(HDATA* hd)
|
||||
static void pool_dtor(void* p)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
MEM* mem = (MEM*)p;
|
||||
|
||||
ssize_t pool_ofs = (u8*)hd->p - (u8*)pool;
|
||||
// at end of pool? if so, 'free' it
|
||||
if(pool_ofs + mem->size == pool_pos)
|
||||
if(mem->ofs + mem->size == pool_pos)
|
||||
pool_pos -= mem->size;
|
||||
}
|
||||
|
||||
@ -70,6 +74,7 @@ static void* pool_alloc(const size_t size, const uint align, MEM& mem)
|
||||
void* p = (u8*)pool + ofs;
|
||||
|
||||
mem.size = size;
|
||||
mem.ofs = ofs;
|
||||
|
||||
pool_pos = ofs+size;
|
||||
return p;
|
||||
@ -77,13 +82,13 @@ static void* pool_alloc(const size_t size, const uint align, MEM& mem)
|
||||
|
||||
|
||||
|
||||
static void mem_dtor(HDATA* hd)
|
||||
static void mem_dtor(void* p)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
MEM* mem = (MEM*)p;
|
||||
if(mem->type == MEM_HEAP)
|
||||
heap_dtor(hd);
|
||||
heap_dtor(p);
|
||||
else if(mem->type == MEM_POOL)
|
||||
pool_dtor(hd);
|
||||
pool_dtor(p);
|
||||
}
|
||||
|
||||
|
||||
@ -93,11 +98,11 @@ void* mem_alloc(size_t size, const MemType type, const uint align, Handle* ph)
|
||||
size = 1;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(0, RES_MEM, mem_dtor, &hd);
|
||||
Handle h = h_alloc(0, H_MEM, mem_dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
MEM& mem = (MEM&)hd->internal;
|
||||
MEM& mem = (MEM&)hd->user;
|
||||
|
||||
void* p;
|
||||
if(type == MEM_HEAP)
|
||||
@ -106,7 +111,7 @@ void* mem_alloc(size_t size, const MemType type, const uint align, Handle* ph)
|
||||
p = pool_alloc(size, align, mem);
|
||||
else
|
||||
{
|
||||
h_free(h, RES_MEM);
|
||||
h_free(h, H_MEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -123,8 +128,8 @@ int mem_free(void* p)
|
||||
return 1;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_find(p, RES_MEM, &hd);
|
||||
Handle h = h_find(p, H_MEM, &hd);
|
||||
if(h)
|
||||
return h_free(h, RES_MEM);
|
||||
return h_free(h, H_MEM);
|
||||
return -1;
|
||||
}
|
@ -40,6 +40,35 @@
|
||||
#define ONCE(code) { static bool done; if(!done) { code; }; done = true; }
|
||||
|
||||
|
||||
|
||||
|
||||
template<bool>
|
||||
struct cassert_checker
|
||||
{
|
||||
cassert_checker(...) { }
|
||||
};
|
||||
|
||||
template<> struct cassert_checker<false> { };
|
||||
|
||||
#define cassert(expr, id) {\
|
||||
struct CASSERT_##id { };\
|
||||
typedef cassert_checker<(expr)> type;\
|
||||
type temp = type(CASSERT_##id());\
|
||||
(void)sizeof(temp);\
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const u32 KB = 1 << 10;
|
||||
const u32 MB = 1 << 20;
|
||||
|
||||
|
@ -26,67 +26,30 @@
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "mem.h"
|
||||
#include "vfs.h"
|
||||
|
||||
// handle (32 bits)
|
||||
// .. make sure this is the same handle we opened
|
||||
static const uint TAG_BITS = 16;
|
||||
// .. index into array => = log2(max open handles)
|
||||
static const uint IDX_BITS = 12;
|
||||
|
||||
static const uint OWNER_BITS = 4;
|
||||
static const uint TYPE_BITS = 4;
|
||||
static const uint REF_BITS = 8;
|
||||
|
||||
struct Res
|
||||
{
|
||||
u32 key;
|
||||
u32 tag : TAG_BITS;
|
||||
u32 type : TYPE_BITS;
|
||||
u32 owner : OWNER_BITS;
|
||||
u32 refs : REF_BITS;
|
||||
};
|
||||
|
||||
static const ulong res_array_cap = 1ul << IDX_BITS;
|
||||
static const uint owner_cap = 1ul << OWNER_BITS;
|
||||
|
||||
// static allocation for simplicity; mem usage isn't significant
|
||||
static Res res_array[res_array_cap];
|
||||
static int first_free = -1;
|
||||
static int max_idx = -1; // index of last in-use entry
|
||||
static const ulong hdata_cap = 1ul << HIDX_BITS;
|
||||
static const uint type_cap = 1ul << HTYPE_BITS;
|
||||
|
||||
// array of pages for better locality, less fragmentation
|
||||
static const uint PAGE_SIZE = 4096;
|
||||
static const uint hdata_per_page = PAGE_SIZE / sizeof(HDATA);
|
||||
static const uint num_pages = res_array_cap / hdata_per_page;
|
||||
static const uint num_pages = hdata_cap / hdata_per_page;
|
||||
static HDATA* pages[num_pages];
|
||||
|
||||
static void(*dtors[owner_cap])(HDATA*);
|
||||
static int first_free = -1; // don't want to scan array every h_alloc
|
||||
static int last_in_use = -1; // don't search unused entries
|
||||
|
||||
|
||||
|
||||
static Handle handle(const int idx)
|
||||
{
|
||||
const Res& r = res_array[idx];
|
||||
return (r.tag) << IDX_BITS | (u32)idx;
|
||||
}
|
||||
|
||||
|
||||
static int h_idx(const Handle h, const uint owner)
|
||||
{
|
||||
int idx = h & ((1 << IDX_BITS)-1);
|
||||
const Res& r = res_array[idx];
|
||||
|
||||
u32 tag = h >> IDX_BITS;
|
||||
if(!tag || r.tag != tag || r.owner != owner)
|
||||
return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
static void(*dtors[type_cap])(void*);
|
||||
|
||||
|
||||
// get pointer to handle data (non-contiguous array)
|
||||
static HDATA* h_data(const int idx)
|
||||
{
|
||||
if(idx > hdata_cap)
|
||||
return 0;
|
||||
HDATA*& page = pages[idx / hdata_per_page];
|
||||
if(!page)
|
||||
{
|
||||
@ -99,21 +62,62 @@ static HDATA* h_data(const int idx)
|
||||
}
|
||||
|
||||
|
||||
// get array index from handle
|
||||
static int h_idx(const Handle h, const uint type)
|
||||
{
|
||||
const int idx = h & ((1 << HIDX_BITS)-1);
|
||||
if(idx > last_in_use)
|
||||
return -1;
|
||||
|
||||
const HDATA* hd = h_data(idx);
|
||||
// cannot fail - it was successfully allocated
|
||||
|
||||
const u32 tag = h >> HIDX_BITS;
|
||||
// note: tag = 0 marks unused entries => is invalid
|
||||
if(!tag || hd->tag != tag || hd->type != type)
|
||||
return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
static Handle handle(const int idx)
|
||||
{
|
||||
const HDATA* hd = h_data(idx);
|
||||
if(!hd) // out of memory
|
||||
return 0;
|
||||
return (hd->tag) << HIDX_BITS | (u32)idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int h_free(const int idx)
|
||||
{
|
||||
Res& r = res_array[idx];
|
||||
if(--r.refs)
|
||||
HDATA* hd = h_data(idx);
|
||||
if(!hd)
|
||||
return -1;
|
||||
|
||||
// not the last reference
|
||||
if(--hd->refs)
|
||||
return 0;
|
||||
|
||||
HDATA* hd = h_data(idx);
|
||||
if(hd)
|
||||
// free its pointer
|
||||
switch(hd->ptype)
|
||||
{
|
||||
if(dtors[r.owner])
|
||||
dtors[r.owner](hd);
|
||||
memset(hd, 0, sizeof(HDATA));
|
||||
case PT_MEM:
|
||||
mem_free(hd->p);
|
||||
break;
|
||||
|
||||
case PT_MAP:
|
||||
munmap(hd->p, hd->size);
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
// call its type's destructor
|
||||
if(dtors[hd->type])
|
||||
dtors[hd->type](hd);
|
||||
|
||||
memset(hd, 0, sizeof(HDATA));
|
||||
|
||||
if(first_free == -1 || idx < first_free)
|
||||
first_free = idx;
|
||||
@ -127,10 +131,10 @@ static void cleanup(void)
|
||||
int i;
|
||||
|
||||
// close open handles
|
||||
for(i = 0; i < max_idx; i++)
|
||||
for(i = 0; i < last_in_use; i++)
|
||||
h_free(i);
|
||||
|
||||
// free internal data space
|
||||
// free hdata array
|
||||
for(i = 0; i < (int)num_pages; i++)
|
||||
{
|
||||
free(pages[i]);
|
||||
@ -139,20 +143,16 @@ static void cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const void* p, uint owner, HDATA** phd)
|
||||
Handle h_find(const void* p, uint type, HDATA** puser)
|
||||
{
|
||||
const Res* r = res_array;
|
||||
|
||||
for(int idx = 0; idx <= max_idx; idx++, r++)
|
||||
for(int idx = 0; idx <= last_in_use; idx++)
|
||||
{
|
||||
if(r->owner != owner)
|
||||
continue;
|
||||
HDATA* hd = h_data(idx); // guaranteed valid
|
||||
|
||||
HDATA* hd = h_data(idx);
|
||||
if(hd && hd->p == p)
|
||||
if(hd->p == p && hd->type == type)
|
||||
{
|
||||
if(phd)
|
||||
*phd = hd;
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
return handle(idx);
|
||||
}
|
||||
}
|
||||
@ -161,26 +161,32 @@ Handle h_find(const void* p, uint owner, HDATA** phd)
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const u32 key, uint owner, HDATA** phd)
|
||||
Handle h_find(const u32 key, uint type, HDATA** puser)
|
||||
{
|
||||
int idx;
|
||||
const Res* r = res_array;
|
||||
HDATA* hd;
|
||||
|
||||
// already have first free entry cached - just search
|
||||
if(first_free != -1)
|
||||
{
|
||||
for(idx = 0; idx <= max_idx; idx++, r++)
|
||||
if(r->key == key && r->owner == owner)
|
||||
for(idx = 0; idx <= last_in_use; idx++)
|
||||
{
|
||||
hd = h_data(idx); // guaranteed valid
|
||||
if(hd->key == key && hd->type == type)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
// search and remember first free entry (slower)
|
||||
else
|
||||
{
|
||||
for(idx = 0; idx <= max_idx; idx++, r++)
|
||||
if(!r->tag && first_free == -1)
|
||||
for(idx = 0; idx <= last_in_use; idx++)
|
||||
{
|
||||
hd = h_data(idx); // guaranteed valid
|
||||
if(!hd->tag && first_free == -1)
|
||||
first_free = idx;
|
||||
else if(r->key == key && r->owner == owner)
|
||||
else if(hd->key == key && hd->type == type)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
@ -188,54 +194,77 @@ Handle h_find(const u32 key, uint owner, HDATA** phd)
|
||||
|
||||
found:
|
||||
Handle h = handle(idx);
|
||||
if(phd)
|
||||
{
|
||||
HDATA* hd = h_data(h, owner);
|
||||
if(!hd)
|
||||
return 0;
|
||||
*phd = hd;
|
||||
}
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
Handle h_alloc(const u32 key, const uint owner, DTOR dtor, HDATA** phd)
|
||||
int h_assign(Handle h, u8* p, size_t size, bool mem)
|
||||
{
|
||||
HDATA* hd = h_data(h);
|
||||
if(!hd)
|
||||
return -1;
|
||||
|
||||
if(hd->p || hd->size || hd->ptype != PT_NONE)
|
||||
{
|
||||
assert(!"h_assign: field(s) already assigned");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
hd->ptype = mem? PT_MEM : PT_MAP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR dtor, HDATA** puser)
|
||||
{
|
||||
ONCE(atexit(cleanup))
|
||||
|
||||
if(owner >= owner_cap)
|
||||
/*
|
||||
if(user_size > HDATA_USER_SIZE)
|
||||
{
|
||||
assert(!"h_alloc: not enough space in entry for user data");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
if(type >= type_cap)
|
||||
{
|
||||
assert(!"h_alloc: invalid type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dtor)
|
||||
{
|
||||
// registering a second dtor for owner
|
||||
// if(dtors[owner] && dtors[owner] != dtor)
|
||||
// return 0;
|
||||
dtors[owner] = dtor;
|
||||
// registering a second dtor for type
|
||||
if(dtors[type] && dtors[type] != dtor)
|
||||
{
|
||||
assert(!"h_alloc: registering a second, different dtor for type");
|
||||
return 0;
|
||||
}
|
||||
dtors[type] = dtor;
|
||||
}
|
||||
|
||||
int idx;
|
||||
Res* r = res_array;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h;
|
||||
|
||||
if(key)
|
||||
{
|
||||
h = h_find(key, owner, &hd);
|
||||
// object already loaded?
|
||||
Handle h = h_find(key, type, &hd);
|
||||
if(h)
|
||||
{
|
||||
idx = h_idx(h, owner);
|
||||
r = &res_array[idx];
|
||||
|
||||
// only way to decide whether this handle is new, or a reference
|
||||
assert(hd->size != 0);
|
||||
|
||||
if(r->refs == (1ul << REF_BITS))
|
||||
if(hd->refs == (1ul << HREF_BITS))
|
||||
{
|
||||
assert(!"h_alloc: too many references to a handle - increase REF_BITS");
|
||||
return 0;
|
||||
}
|
||||
r->refs++;
|
||||
|
||||
hd->refs++;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
@ -244,62 +273,57 @@ Handle h_alloc(const u32 key, const uint owner, DTOR dtor, HDATA** phd)
|
||||
if(first_free != -1)
|
||||
{
|
||||
idx = first_free;
|
||||
r = &res_array[idx];
|
||||
hd = h_data(idx);
|
||||
}
|
||||
// search res_array for first entry
|
||||
// search handle data for first free entry
|
||||
else
|
||||
for(idx = 0; idx < res_array_cap; idx++, r++)
|
||||
if(!r->tag)
|
||||
for(idx = 0; idx < hdata_cap; idx++)
|
||||
{
|
||||
hd = h_data(idx);
|
||||
// not enough memory - abort (don't leave a hole in the array)
|
||||
if(!hd)
|
||||
return 0;
|
||||
// found an empty entry - done
|
||||
if(!hd->tag)
|
||||
break;
|
||||
}
|
||||
|
||||
// check if next entry is free
|
||||
if(idx+1 < res_array_cap && !(r+1)->key)
|
||||
first_free = idx+1;
|
||||
else
|
||||
first_free = -1;
|
||||
|
||||
if(idx >= res_array_cap)
|
||||
if(idx >= hdata_cap)
|
||||
{
|
||||
assert(!"h_alloc: too many open handles (increase IDX_BITS)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(idx > max_idx)
|
||||
max_idx = idx;
|
||||
// check if next entry is free
|
||||
HDATA* hd2 = h_data(idx+1);
|
||||
if(hd2 && hd2->tag == 0)
|
||||
first_free = idx+1;
|
||||
else
|
||||
first_free = -1;
|
||||
|
||||
if(idx > last_in_use)
|
||||
last_in_use = idx;
|
||||
|
||||
static u32 tag;
|
||||
if(++tag >= (1 << TAG_BITS))
|
||||
if(++tag >= (1 << HTAG_BITS))
|
||||
{
|
||||
assert(!"h_alloc: tag overflow - may not notice stale handle reuse (increase TAG_BITS)");
|
||||
tag = 1;
|
||||
}
|
||||
|
||||
r->key = key;
|
||||
r->tag = tag;
|
||||
r->owner = owner;
|
||||
hd->key = key;
|
||||
hd->tag = tag;
|
||||
hd->type = type;
|
||||
|
||||
h = handle(idx);
|
||||
|
||||
// caller wants HDATA* returned
|
||||
if(phd)
|
||||
{
|
||||
HDATA* hd = h_data(h, owner);
|
||||
// not enough mem - fail
|
||||
if(!hd)
|
||||
{
|
||||
h_free(h, owner);
|
||||
return 0;
|
||||
}
|
||||
*phd = hd;
|
||||
}
|
||||
|
||||
return h;
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
return handle(idx);
|
||||
}
|
||||
|
||||
|
||||
int h_free(const Handle h, const uint owner)
|
||||
int h_free(const Handle h, const uint type)
|
||||
{
|
||||
int idx = h_idx(h, owner);
|
||||
int idx = h_idx(h, type);
|
||||
if(idx >= 0)
|
||||
return h_free(idx);
|
||||
return -1;
|
||||
@ -307,9 +331,9 @@ int h_free(const Handle h, const uint owner)
|
||||
|
||||
|
||||
|
||||
HDATA* h_data(const Handle h, const uint owner)
|
||||
HDATA* h_data(const Handle h, const uint type)
|
||||
{
|
||||
int idx = h_idx(h, owner);
|
||||
int idx = h_idx(h, type);
|
||||
if(idx >= 0)
|
||||
return h_data(idx);
|
||||
return 0;
|
||||
@ -317,15 +341,16 @@ HDATA* h_data(const Handle h, const uint owner)
|
||||
|
||||
|
||||
|
||||
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& hd)
|
||||
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
hd = 0;
|
||||
user = 0;
|
||||
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
// TODO: fn is usually a constant; pass fn len if too slow
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(fn_hash, type, dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
@ -348,7 +373,7 @@ Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HD
|
||||
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
|
||||
user=hd;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
@ -22,50 +22,98 @@
|
||||
#include "types.h"
|
||||
|
||||
|
||||
// handle type (for 'type safety' - can't use a texture handle as a sound)
|
||||
enum
|
||||
{
|
||||
RES_TEX = 1,
|
||||
RES_FONT,
|
||||
RES_SOUND,
|
||||
RES_ZFILE,
|
||||
RES_ZARCHIVE,
|
||||
RES_VFILE,
|
||||
|
||||
RES_MMAP,
|
||||
RES_MEM
|
||||
// handle type (for 'type safety' - can't use a texture handle as a sound)
|
||||
//
|
||||
// rationale: we could use the destructor passed to res_load to identify
|
||||
// the handle, but it's good to have a list of all types, and we avoid having
|
||||
// to create empty destructors for handle types that wouldn't need them.
|
||||
// finally, we save memory - this fits in a few bits, vs. needing a pointer.
|
||||
enum HType
|
||||
{
|
||||
H_TEX = 1,
|
||||
H_FONT = 2,
|
||||
H_SOUND = 3,
|
||||
H_ZFILE = 4,
|
||||
H_ZARCHIVE = 5,
|
||||
H_VFILE = 6,
|
||||
H_MEM = 7,
|
||||
|
||||
NUM_HANDLE_TYPES
|
||||
};
|
||||
|
||||
// handle's pointer type
|
||||
enum PType
|
||||
{
|
||||
PT_NONE,
|
||||
PT_MEM, // allocated by mem_alloc
|
||||
PT_MAP // mapped by mmap
|
||||
};
|
||||
|
||||
typedef unsigned long Handle;
|
||||
// handle (32 bits)
|
||||
// .. make sure this is the same handle we opened
|
||||
const uint HTAG_BITS = 16;
|
||||
// .. index into array => = log2(max open handles)
|
||||
const uint HIDX_BITS = 12;
|
||||
|
||||
const int HDATA_INTERNAL_SIZE = 24;
|
||||
// <= 32-TAG_BITS bits
|
||||
const uint HTYPE_BITS = 4;
|
||||
const uint PTYPE_BITS = 4;
|
||||
const uint HREF_BITS = 8;
|
||||
|
||||
const int HDATA_USER_SIZE = 16;
|
||||
|
||||
// 32 bytes
|
||||
struct HDATA
|
||||
{
|
||||
u32 key;
|
||||
u32 tag : HTAG_BITS;
|
||||
u32 type : HTYPE_BITS; // handle's type (e.g. texture, sound)
|
||||
u32 ptype : PTYPE_BITS; // what does p point to?
|
||||
u32 refs : HREF_BITS;
|
||||
|
||||
void* p;
|
||||
size_t size;
|
||||
u8 internal[HDATA_INTERNAL_SIZE];
|
||||
|
||||
u8 user[HDATA_USER_SIZE];
|
||||
};
|
||||
|
||||
typedef void(*DTOR)(HDATA*);
|
||||
|
||||
extern Handle h_alloc(u32 key, uint type, DTOR dtor = 0, HDATA** phd = 0);
|
||||
// 0 = invalid handle value.
|
||||
typedef u32 Handle;
|
||||
|
||||
|
||||
// destructor, registered by h_alloc for a given handle type.
|
||||
// receives the user data associated with the handle.
|
||||
typedef void(*DTOR)(void*);
|
||||
|
||||
|
||||
// all functions check the passed tag (part of the handle) and type against
|
||||
// the internal values. if they differ, an error is returned.
|
||||
|
||||
|
||||
// allocate a new handle.
|
||||
// if key is 0, or a (key, type) handle doesn't exist,
|
||||
// the first free entry is used.
|
||||
// otherwise, a handle to the existing object is returned,
|
||||
// and HDATA.size != 0.
|
||||
//// user_size is checked to make sure the user data fits in the handle data space.
|
||||
// dtor is associated with type and called when the object is freed.
|
||||
// handle data is initialized to 0; optionally, a pointer to it is returned.
|
||||
extern Handle h_alloc(u32 key, uint type,/* size_t user_size,*/ DTOR dtor = 0, HDATA** puser = 0);
|
||||
extern int h_free(Handle h, uint type);
|
||||
|
||||
// find and return a handle by type and associated key (typically filename hash)
|
||||
// find and return a handle by type and key (typically filename hash)
|
||||
// currently O(n).
|
||||
extern Handle h_find(u32 key, uint type, HDATA** phd = 0);
|
||||
extern Handle h_find(u32 key, uint type, HDATA** puser = 0);
|
||||
|
||||
// same as above, but search for a pointer the handle references
|
||||
extern Handle h_find(const void* p, uint type, HDATA** phd = 0);
|
||||
// same as above, but search for the handle's associated pointer
|
||||
extern Handle h_find(const void* p, uint type, HDATA** puser = 0);
|
||||
|
||||
// get a handle's associated data.
|
||||
// returns 0 if the handle is invalid, or <type> doesn't match
|
||||
// return a pointer to handle data
|
||||
extern HDATA* h_data(Handle h, uint type);
|
||||
|
||||
extern Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& hd);
|
||||
extern Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user);
|
||||
|
||||
|
||||
#endif // #ifndef __RES_H__
|
||||
|
@ -153,8 +153,7 @@ static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->fmt = fmt;
|
||||
tex->bpp = 0;
|
||||
tex->s3tc_img_size = img_size;
|
||||
tex->bpp = img_size / (w * h);
|
||||
tex->ptr = img;
|
||||
|
||||
if(sizeof(DDSURFACEDESC2) != ddsd_size)
|
||||
@ -589,9 +588,9 @@ static int jp2_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
|
||||
|
||||
|
||||
static void tex_dtor(HDATA* hd)
|
||||
static void tex_dtor(void* p)
|
||||
{
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
TEX* tex = (TEX*)p;
|
||||
glDeleteTextures(1, &tex->id);
|
||||
}
|
||||
|
||||
@ -603,11 +602,11 @@ Handle tex_load(const char* fn, TEX* ptex)
|
||||
const u8* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, RES_TEX, tex_dtor, (void*&)p, size, hd);
|
||||
Handle h = res_load(fn, H_TEX, tex_dtor, (void*&)p, size, hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
if(!p)
|
||||
goto already_loaded;
|
||||
if(size < 4) // guarantee xxx_valid routines 4 bytes
|
||||
@ -670,13 +669,13 @@ already_loaded:
|
||||
|
||||
int tex_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_TEX);
|
||||
HDATA* hd = h_data(h, H_TEX);
|
||||
if(!hd)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return -1;
|
||||
}
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
return 0;
|
||||
}
|
||||
@ -687,10 +686,10 @@ uint tex_bpp = 32; // 16 or 32
|
||||
|
||||
int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_TEX);
|
||||
HDATA* hd = h_data(h, H_TEX);
|
||||
if(!hd)
|
||||
return -1;
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
|
||||
// greater than max supported tex dimension?
|
||||
// no-op if oglInit not yet called
|
||||
@ -726,7 +725,10 @@ int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
// S3TC compressed
|
||||
if(tex->fmt >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
|
||||
tex->fmt <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, tex->s3tc_img_size, tex->ptr);
|
||||
{
|
||||
int img_size = tex->width * tex->height * tex->bpp;
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, img_size, tex->ptr);
|
||||
}
|
||||
// normal
|
||||
else
|
||||
{
|
||||
|
@ -21,20 +21,21 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "res.h"
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
struct TEX
|
||||
{
|
||||
u32 width : 16;
|
||||
u32 height : 16;
|
||||
u32 fmt : 16;
|
||||
u32 bpp : 8; // 0 if S3TC
|
||||
u32 s3tc_img_size;
|
||||
u32 bpp : 16;
|
||||
const u8* ptr;
|
||||
uint id;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// load and return a handle to the texture given in <fn>.
|
||||
// supports RAW, BMP, JP2, PNG, TGA, DDS
|
||||
// optionally returns a copy of information about the texture.
|
||||
|
@ -39,7 +39,7 @@ static const char cdfh_id[] = "PK\1\2"; // Central File Header identifier
|
||||
static const char lfh_id[] = "PK\3\4"; // Local File Header identifier
|
||||
|
||||
|
||||
// RES_ZFILE handle
|
||||
// H_ZFILE handle
|
||||
// location and size of an archived file
|
||||
// no destructor
|
||||
struct ZFILE
|
||||
@ -50,11 +50,11 @@ struct ZFILE
|
||||
};
|
||||
|
||||
|
||||
// RES_ZARCHIVE handle
|
||||
// H_ZARCHIVE handle
|
||||
// information about a ZIP archive
|
||||
struct ZARCHIVE
|
||||
{
|
||||
Handle hf; // actual ZIP file (RES_VFILE)
|
||||
Handle hf; // actual ZIP file (H_VFILE)
|
||||
|
||||
// file lookup
|
||||
u32 num_files;
|
||||
@ -64,12 +64,12 @@ struct ZARCHIVE
|
||||
};
|
||||
|
||||
|
||||
static void zarchive_dtor(HDATA* hd)
|
||||
static void zarchive_dtor(void* p)
|
||||
{
|
||||
ZARCHIVE* z = (ZARCHIVE*)hd->internal;
|
||||
ZARCHIVE* za = (ZARCHIVE*)p;
|
||||
|
||||
vfs_close(z->hf);
|
||||
z->hf = 0;
|
||||
vfs_close(za->hf);
|
||||
za->hf = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ Handle zopen(const char* const fn)
|
||||
|
||||
// already loaded?
|
||||
HDATA* hd;
|
||||
Handle h = h_find(fn_hash, RES_ZFILE, &hd);
|
||||
Handle h = h_find(fn_hash, H_ZFILE, &hd);
|
||||
if(h)
|
||||
return h;
|
||||
|
||||
@ -127,11 +127,11 @@ found_ecdr:
|
||||
if(!mem)
|
||||
goto fail;
|
||||
|
||||
h = h_alloc(fn_hash, RES_ZFILE, zarchive_dtor, &hd);
|
||||
h = h_alloc(fn_hash, H_ZFILE, zarchive_dtor, &hd);
|
||||
if(!h)
|
||||
goto fail;
|
||||
|
||||
ZARCHIVE* const za = (ZARCHIVE*)hd->internal;
|
||||
ZARCHIVE* const za = (ZARCHIVE*)hd->user;
|
||||
za->hf = hf;
|
||||
za->fn_hashs = (u32*)mem;
|
||||
za->files = (ZFILE*)((u8*)mem + 4*num_files);
|
||||
@ -186,19 +186,19 @@ found_ecdr:
|
||||
|
||||
void zclose(const Handle h)
|
||||
{
|
||||
if(h_data(h, RES_ZFILE))
|
||||
h_free(h, RES_ZFILE);
|
||||
if(h_data(h, H_ZFILE))
|
||||
h_free(h, H_ZFILE);
|
||||
else
|
||||
h_free(h, RES_ZARCHIVE);
|
||||
h_free(h, H_ZARCHIVE);
|
||||
}
|
||||
|
||||
|
||||
Handle zopen(Handle hz, const char* fn)
|
||||
{
|
||||
HDATA* hzd = h_data(hz, RES_ZFILE);
|
||||
HDATA* hzd = h_data(hz, H_ZFILE);
|
||||
if(!hzd)
|
||||
return 0;
|
||||
ZARCHIVE* za = (ZARCHIVE*)hzd->internal;
|
||||
ZARCHIVE* za = (ZARCHIVE*)hzd->user;
|
||||
|
||||
// find its File descriptor
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
@ -217,7 +217,7 @@ Handle zopen(Handle hz, const char* fn)
|
||||
|
||||
//
|
||||
HDATA* hfd;
|
||||
Handle hf = h_alloc(fn_hash, RES_ZFILE, 0, &hfd);
|
||||
Handle hf = h_alloc(fn_hash, H_ZFILE, 0, &hfd);
|
||||
return hf;
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ int zread(Handle hf, void*& p, size_t& size, size_t ofs)
|
||||
if(!hfd)
|
||||
return -1;
|
||||
|
||||
ZFILE* zf = (ZFILE*)hfd->internal;
|
||||
ZFILE* zf = (ZFILE*)hfd->user;
|
||||
const size_t ucsize = zf->ucsize;
|
||||
const size_t csize = zf->csize;
|
||||
|
||||
|
@ -31,20 +31,9 @@ struct PATH
|
||||
static PATH* path_list;
|
||||
|
||||
|
||||
static void vfile_dtor(HDATA* hd)
|
||||
static void vfile_dtor(void* p)
|
||||
{
|
||||
VFILE* vf = (VFILE*)hd->internal;
|
||||
|
||||
// normal file
|
||||
if(vf->fd != -1)
|
||||
{
|
||||
munmap(hd->p, hd->size);
|
||||
hd->p = 0;
|
||||
hd->size = 0;
|
||||
|
||||
close(vf->fd);
|
||||
vf->fd = -1;
|
||||
}
|
||||
VFILE* vf = (VFILE*)p;
|
||||
|
||||
// in archive
|
||||
if(vf->ha && vf->hz)
|
||||
@ -232,12 +221,12 @@ u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
{
|
||||
HDATA* hfd = h_data(hf, 0);
|
||||
if(!hfd)
|
||||
return -1;
|
||||
VFILE* vf = (VFILE*)hfd->internal;
|
||||
return 0;
|
||||
VFILE* vf = (VFILE*)hfd->user;
|
||||
|
||||
ssize_t bytes_left = hfd->size - ofs;
|
||||
if(bytes_left < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
// TODO: thread safety
|
||||
|
||||
@ -250,7 +239,7 @@ u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
if(i == NUM_SLOTS)
|
||||
{
|
||||
assert(!"vfs_start_read: too many active reads; increase NUM_SLOTS");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// mark it in use
|
||||
@ -273,7 +262,7 @@ u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
{
|
||||
cb->aio_buf = mem_alloc(64*KB, MEM_HEAP, 64*KB);
|
||||
if(!cb->aio_buf)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// align to 64 KB for speed
|
||||
@ -328,7 +317,7 @@ int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
|
||||
p = 0;
|
||||
size = 0;
|
||||
|
||||
HDATA* hd = h_data(h, RES_VFILE);
|
||||
HDATA* hd = h_data(h, H_VFILE);
|
||||
if(hd)
|
||||
{
|
||||
if(ofs+size > hd->size)
|
||||
@ -338,7 +327,7 @@ int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
|
||||
size = hd->size - ofs;
|
||||
return 0;
|
||||
}
|
||||
// RES_ZFILE
|
||||
// H_ZFILE
|
||||
else
|
||||
return zread(h, p, size, ofs);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user