forked from 0ad/0ad
allocator: add single_calloc (generalization of code previously in wposix for WDIR); add da_reserve; expand pool allocator to allow variable size entries
byte_order: add FOURCC_BE and _LE versions (needed for zip) ogl: quick hack: prevent crash on laptop by providing a pglDrawRangeElementsEXT stub file, h_mgr: update pool_alloc call site tex: fix incorrect indexing/stride for mipmap generation vfs_mount: disable archives (zip code is WIP) zip: heavy WIP. add support for writing archives (needed for thesis); revised Zip read code. sped up archive open. further major changes pending. wposix: moved allocator code (see above) This was SVN commit r3298.
This commit is contained in:
parent
f8f81aa7d9
commit
32aca79221
@ -16,11 +16,69 @@
|
|||||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
|
#include "sysdep/cpu.h" // CAS
|
||||||
|
|
||||||
#include "allocators.h"
|
#include "allocators.h"
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// allocator optimized for single instances
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// intended for applications that frequently alloc/free a single
|
||||||
|
// fixed-size object. caller provides static storage and an in-use flag;
|
||||||
|
// we use that memory if available and otherwise fall back to the heap.
|
||||||
|
// if the application only has one object in use at a time, malloc is
|
||||||
|
// avoided; this is faster and avoids heap fragmentation.
|
||||||
|
//
|
||||||
|
// thread-safe.
|
||||||
|
|
||||||
|
void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_t size)
|
||||||
|
{
|
||||||
|
// sanity check
|
||||||
|
debug_assert(*in_use_flag == 0 || *in_use_flag == 1);
|
||||||
|
|
||||||
|
void* p;
|
||||||
|
|
||||||
|
// successfully reserved the single instance
|
||||||
|
if(CAS(in_use_flag, 0, 1))
|
||||||
|
p = storage;
|
||||||
|
// already in use (rare) - allocate from heap
|
||||||
|
else
|
||||||
|
p = malloc(size);
|
||||||
|
|
||||||
|
memset(p, 0, size);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void single_free(void* storage, volatile uintptr_t* in_use_flag, void* p)
|
||||||
|
{
|
||||||
|
// sanity check
|
||||||
|
debug_assert(*in_use_flag == 0 || *in_use_flag == 1);
|
||||||
|
|
||||||
|
if(p == storage)
|
||||||
|
{
|
||||||
|
if(CAS(in_use_flag, 1, 0))
|
||||||
|
{
|
||||||
|
// ok, flag has been reset to 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug_warn("in_use_flag out of sync (double free?)");
|
||||||
|
}
|
||||||
|
// was allocated from heap
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// single instance may have been freed by now - cannot assume
|
||||||
|
// anything about in_use_flag.
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// dynamic (expandable) array
|
// dynamic (expandable) array
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -224,6 +282,20 @@ LibError da_set_size(DynArray* da, size_t new_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// make sure at least <size> bytes starting at <pos> are committed and
|
||||||
|
// ready for use.
|
||||||
|
LibError da_reserve(DynArray* da, size_t size)
|
||||||
|
{
|
||||||
|
// default to page size (the OS won't commit less anyway);
|
||||||
|
// grab more if request requires it.
|
||||||
|
const size_t expand_amount = MIN(4*KiB, size);
|
||||||
|
|
||||||
|
if(da->pos + size > da->cur_size)
|
||||||
|
return da_set_size(da, da->cur_size + expand_amount);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// change access rights of the array memory; used to implement
|
// change access rights of the array memory; used to implement
|
||||||
// write-protection. affects the currently committed pages as well as
|
// write-protection. affects the currently committed pages as well as
|
||||||
// all subsequently added pages.
|
// all subsequently added pages.
|
||||||
@ -266,7 +338,7 @@ LibError da_read(DynArray* da, void* data, size_t size)
|
|||||||
// starts at offset DynArray.pos and advances this.
|
// starts at offset DynArray.pos and advances this.
|
||||||
LibError da_append(DynArray* da, const void* data, size_t size)
|
LibError da_append(DynArray* da, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
RETURN_ERR(da_set_size(da, da->pos+size));
|
RETURN_ERR(da_reserve(da, size));
|
||||||
memcpy2(da->base+da->pos, data, size);
|
memcpy2(da->base+da->pos, data, size);
|
||||||
da->pos += size;
|
da->pos += size;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
@ -279,7 +351,7 @@ LibError da_append(DynArray* da, const void* data, size_t size)
|
|||||||
|
|
||||||
// design parameters:
|
// design parameters:
|
||||||
// - O(1) alloc and free;
|
// - O(1) alloc and free;
|
||||||
// - fixed-size blocks;
|
// - fixed XOR variable size blocks;
|
||||||
// - doesn't preallocate the entire pool;
|
// - doesn't preallocate the entire pool;
|
||||||
// - returns sequential addresses.
|
// - returns sequential addresses.
|
||||||
|
|
||||||
@ -308,15 +380,18 @@ static void* freelist_pop(void** pfreelist)
|
|||||||
static const size_t POOL_CHUNK = 4*KiB;
|
static const size_t POOL_CHUNK = 4*KiB;
|
||||||
|
|
||||||
|
|
||||||
// ready <p> for use. pool_alloc will return chunks of memory that
|
// ready <p> for use. <max_size> is the upper limit [bytes] on
|
||||||
// are exactly <el_size> bytes. <max_size> is the upper limit [bytes] on
|
|
||||||
// pool size (this is how much address space is reserved).
|
// pool size (this is how much address space is reserved).
|
||||||
//
|
//
|
||||||
// note: el_size must at least be enough for a pointer (due to freelist
|
// <el_size> can be 0 to allow variable-sized allocations
|
||||||
// implementation) but not exceed the expand-by amount.
|
// (which cannot be freed individually);
|
||||||
|
// otherwise, it specifies the number of bytes that will be
|
||||||
|
// returned by pool_alloc (whose size parameter is then ignored).
|
||||||
|
// in the latter case, size must at least be enough for a pointer
|
||||||
|
// (due to freelist implementation).
|
||||||
LibError pool_create(Pool* p, size_t max_size, size_t el_size)
|
LibError pool_create(Pool* p, size_t max_size, size_t el_size)
|
||||||
{
|
{
|
||||||
if(el_size < sizeof(void*) || el_size > POOL_CHUNK)
|
if(el_size != 0 && el_size < sizeof(void*))
|
||||||
CHECK_ERR(ERR_INVALID_PARAM);
|
CHECK_ERR(ERR_INVALID_PARAM);
|
||||||
|
|
||||||
RETURN_ERR(da_alloc(&p->da, max_size));
|
RETURN_ERR(da_alloc(&p->da, max_size));
|
||||||
@ -355,8 +430,17 @@ bool pool_contains(Pool* p, void* el)
|
|||||||
// return an entry from the pool, or 0 if it would have to be expanded and
|
// return an entry from the pool, or 0 if it would have to be expanded and
|
||||||
// there isn't enough memory to do so.
|
// there isn't enough memory to do so.
|
||||||
// exhausts the freelist before returning new entries to improve locality.
|
// exhausts the freelist before returning new entries to improve locality.
|
||||||
void* pool_alloc(Pool* p)
|
//
|
||||||
|
// if the pool was set up with fixed-size elements, <size> is ignored;
|
||||||
|
// otherwise, <size> bytes are allocated.
|
||||||
|
void* pool_alloc(Pool* p, size_t size)
|
||||||
{
|
{
|
||||||
|
// if pool allows variable sizes, go with the size parameter,
|
||||||
|
// otherwise the pool el_size setting.
|
||||||
|
const size_t el_size = p->el_size? p->el_size : size;
|
||||||
|
|
||||||
|
// note: this can never happen in pools with variable-sized elements
|
||||||
|
// because they disallow pool_free.
|
||||||
void* el = freelist_pop(&p->freelist);
|
void* el = freelist_pop(&p->freelist);
|
||||||
if(el)
|
if(el)
|
||||||
goto have_el;
|
goto have_el;
|
||||||
@ -364,12 +448,11 @@ void* pool_alloc(Pool* p)
|
|||||||
// alloc a new entry
|
// alloc a new entry
|
||||||
{
|
{
|
||||||
// expand, if necessary
|
// expand, if necessary
|
||||||
if(p->pos + p->el_size > p->da.cur_size)
|
if(da_reserve(&p->da, el_size) < 0)
|
||||||
if(da_set_size(&p->da, p->da.cur_size + POOL_CHUNK) < 0)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
el = p->da.base + p->pos;
|
el = p->da.base + p->pos;
|
||||||
p->pos += p->el_size;
|
p->pos += el_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
have_el:
|
have_el:
|
||||||
@ -379,8 +462,19 @@ have_el:
|
|||||||
|
|
||||||
|
|
||||||
// make <el> available for reuse in the given pool.
|
// make <el> available for reuse in the given pool.
|
||||||
|
//
|
||||||
|
// this is not allowed if the pool was set up for variable-size elements.
|
||||||
|
// (copying with fragmentation would defeat the point of a pool - simplicity)
|
||||||
|
// we could allow this, but instead warn and bail to make sure it
|
||||||
|
// never happens inadvertently (leaking memory in the pool).
|
||||||
void pool_free(Pool* p, void* el)
|
void pool_free(Pool* p, void* el)
|
||||||
{
|
{
|
||||||
|
if(p->el_size == 0)
|
||||||
|
{
|
||||||
|
debug_warn("pool is set up for variable-size items");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(pool_contains(p, el))
|
if(pool_contains(p, el))
|
||||||
freelist_push(&p->freelist, el);
|
freelist_push(&p->freelist, el);
|
||||||
else
|
else
|
||||||
@ -388,6 +482,16 @@ void pool_free(Pool* p, void* el)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// "free" all allocations that ensued from the given Pool.
|
||||||
|
// this resets it as if freshly pool_create-d, but doesn't release the
|
||||||
|
// underlying memory.
|
||||||
|
void pool_free_all(Pool* p)
|
||||||
|
{
|
||||||
|
p->pos = 0;
|
||||||
|
p->freelist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// bucket allocator
|
// bucket allocator
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -396,6 +500,7 @@ void pool_free(Pool* p, void* el)
|
|||||||
// - variable-size allocations;
|
// - variable-size allocations;
|
||||||
// - no reuse of allocations, can only free all at once;
|
// - no reuse of allocations, can only free all at once;
|
||||||
// - no init necessary;
|
// - no init necessary;
|
||||||
|
// - never relocates;
|
||||||
// - no fixed limit.
|
// - no fixed limit.
|
||||||
|
|
||||||
// must be constant and power-of-2 to allow fast modulo.
|
// must be constant and power-of-2 to allow fast modulo.
|
||||||
|
@ -22,6 +22,23 @@
|
|||||||
#include "lib/posix.h" // PROT_* constants for da_set_prot
|
#include "lib/posix.h" // PROT_* constants for da_set_prot
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocator optimized for single instances
|
||||||
|
//
|
||||||
|
|
||||||
|
// intended for applications that frequently alloc/free a single
|
||||||
|
// fixed-size object. caller provides static storage and an in-use flag;
|
||||||
|
// we use that memory if available and otherwise fall back to the heap.
|
||||||
|
// if the application only has one object in use at a time, malloc is
|
||||||
|
// avoided; this is faster and avoids heap fragmentation.
|
||||||
|
//
|
||||||
|
// thread-safe.
|
||||||
|
|
||||||
|
extern void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_t size);
|
||||||
|
|
||||||
|
extern void single_free(void* storage, volatile uintptr_t* in_use_flag, void* p);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// dynamic (expandable) array
|
// dynamic (expandable) array
|
||||||
//
|
//
|
||||||
@ -57,6 +74,10 @@ extern LibError da_free(DynArray* da);
|
|||||||
// new_size (rounded up to the next page size multiple) is met.
|
// new_size (rounded up to the next page size multiple) is met.
|
||||||
extern LibError da_set_size(DynArray* da, size_t new_size);
|
extern LibError da_set_size(DynArray* da, size_t new_size);
|
||||||
|
|
||||||
|
// make sure at least <size> bytes starting at <pos> are committed and
|
||||||
|
// ready for use.
|
||||||
|
extern LibError da_reserve(DynArray* da, size_t size);
|
||||||
|
|
||||||
// change access rights of the array memory; used to implement
|
// change access rights of the array memory; used to implement
|
||||||
// write-protection. affects the currently committed pages as well as
|
// write-protection. affects the currently committed pages as well as
|
||||||
// all subsequently added pages.
|
// all subsequently added pages.
|
||||||
@ -85,7 +106,7 @@ extern LibError da_append(DynArray* da, const void* data_src, size_t size);
|
|||||||
|
|
||||||
// design parameters:
|
// design parameters:
|
||||||
// - O(1) alloc and free;
|
// - O(1) alloc and free;
|
||||||
// - fixed-size blocks;
|
// - fixed XOR variable size blocks;
|
||||||
// - doesn't preallocate the entire pool;
|
// - doesn't preallocate the entire pool;
|
||||||
// - returns sequential addresses.
|
// - returns sequential addresses.
|
||||||
|
|
||||||
@ -93,21 +114,27 @@ extern LibError da_append(DynArray* da, const void* data_src, size_t size);
|
|||||||
struct Pool
|
struct Pool
|
||||||
{
|
{
|
||||||
DynArray da;
|
DynArray da;
|
||||||
|
|
||||||
|
// size of elements; see pool_create.
|
||||||
size_t el_size;
|
size_t el_size;
|
||||||
|
|
||||||
// all bytes in da up to this mark are in circulation or freelist.
|
// all bytes in da up to this mark are in circulation or freelist.
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
|
||||||
// pointer to freelist (opaque); see freelist_*.
|
// pointer to freelist (opaque); see freelist_*.
|
||||||
|
// never used (remains 0) if elements are of variable size.
|
||||||
void* freelist;
|
void* freelist;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ready <p> for use. pool_alloc will return chunks of memory that
|
// ready <p> for use. <max_size> is the upper limit [bytes] on
|
||||||
// are exactly <el_size> bytes. <max_size> is the upper limit [bytes] on
|
|
||||||
// pool size (this is how much address space is reserved).
|
// pool size (this is how much address space is reserved).
|
||||||
//
|
//
|
||||||
// note: el_size must at least be enough for a pointer (due to freelist
|
// <el_size> can be 0 to allow variable-sized allocations
|
||||||
// implementation) but not exceed the expand-by amount.
|
// (which cannot be freed individually);
|
||||||
|
// otherwise, it specifies the number of bytes that will be
|
||||||
|
// returned by pool_alloc (whose size parameter is then ignored).
|
||||||
|
// in the latter case, size must at least be enough for a pointer
|
||||||
|
// (due to freelist implementation).
|
||||||
extern LibError pool_create(Pool* p, size_t max_size, size_t el_size);
|
extern LibError pool_create(Pool* p, size_t max_size, size_t el_size);
|
||||||
|
|
||||||
// free all memory that ensued from <p>. all elements are made unusable
|
// free all memory that ensued from <p>. all elements are made unusable
|
||||||
@ -122,11 +149,24 @@ extern bool pool_contains(Pool* p, void* el);
|
|||||||
// return an entry from the pool, or 0 if it would have to be expanded and
|
// return an entry from the pool, or 0 if it would have to be expanded and
|
||||||
// there isn't enough memory to do so.
|
// there isn't enough memory to do so.
|
||||||
// exhausts the freelist before returning new entries to improve locality.
|
// exhausts the freelist before returning new entries to improve locality.
|
||||||
extern void* pool_alloc(Pool* p);
|
//
|
||||||
|
// if the pool was set up with fixed-size elements, <size> is ignored;
|
||||||
|
// otherwise, <size> bytes are allocated.
|
||||||
|
extern void* pool_alloc(Pool* p, size_t size);
|
||||||
|
|
||||||
// make <el> available for reuse in the given pool.
|
// make <el> available for reuse in the given pool.
|
||||||
|
//
|
||||||
|
// this is not allowed if the pool was set up for variable-size elements.
|
||||||
|
// (copying with fragmentation would defeat the point of a pool - simplicity)
|
||||||
|
// we could allow this, but instead warn and bail to make sure it
|
||||||
|
// never happens inadvertently (leaking memory in the pool).
|
||||||
extern void pool_free(Pool* p, void* el);
|
extern void pool_free(Pool* p, void* el);
|
||||||
|
|
||||||
|
// "free" all allocations that ensued from the given Pool.
|
||||||
|
// this resets it as if freshly pool_create-d, but doesn't release the
|
||||||
|
// underlying memory.
|
||||||
|
extern void pool_free_all(Pool* p);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// bucket allocator
|
// bucket allocator
|
||||||
@ -136,6 +176,7 @@ extern void pool_free(Pool* p, void* el);
|
|||||||
// - variable-size allocations;
|
// - variable-size allocations;
|
||||||
// - no reuse of allocations, can only free all at once;
|
// - no reuse of allocations, can only free all at once;
|
||||||
// - no init necessary;
|
// - no init necessary;
|
||||||
|
// - never relocates;
|
||||||
// - no fixed limit.
|
// - no fixed limit.
|
||||||
|
|
||||||
// opaque! do not read/write any fields!
|
// opaque! do not read/write any fields!
|
||||||
|
@ -9,12 +9,15 @@
|
|||||||
// the additional u8 cast ensures each character is treated as unsigned
|
// the additional u8 cast ensures each character is treated as unsigned
|
||||||
// (otherwise, they'd be promoted to signed int before the u32 cast,
|
// (otherwise, they'd be promoted to signed int before the u32 cast,
|
||||||
// which would break things).
|
// which would break things).
|
||||||
|
#define FOURCC_BE(a,b,c,d) ( ((u32)(u8)a) << 24 | ((u32)(u8)b) << 16 | \
|
||||||
|
((u32)(u8)c) << 8 | ((u32)(u8)d) << 0 )
|
||||||
|
#define FOURCC_LE(a,b,c,d) ( ((u32)(u8)a) << 0 | ((u32)(u8)b) << 8 | \
|
||||||
|
((u32)(u8)c) << 16 | ((u32)(u8)d) << 24 )
|
||||||
|
|
||||||
#if BYTE_ORDER == BIG_ENDIAN
|
#if BYTE_ORDER == BIG_ENDIAN
|
||||||
#define FOURCC(a,b,c,d) ( ((u32)(u8)a) << 24 | ((u32)(u8)b) << 16 | \
|
# define FOURCC FOURCC_BE
|
||||||
((u32)(u8)c) << 8 | ((u32)(u8)d) << 0 )
|
|
||||||
#else
|
#else
|
||||||
#define FOURCC(a,b,c,d) ( ((u32)(u8)a) << 0 | ((u32)(u8)b) << 8 | \
|
# define FOURCC FOURCC_LE
|
||||||
((u32)(u8)c) << 16 | ((u32)(u8)d) << 24 )
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -351,6 +351,10 @@ LibError ogl_get_gfx_info()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void __stdcall emu_glDrawRangeElementsEXT(GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// call after each video mode change, since thereafter extension functions
|
// call after each video mode change, since thereafter extension functions
|
||||||
// may have changed [address].
|
// may have changed [address].
|
||||||
void oglInit()
|
void oglInit()
|
||||||
@ -368,6 +372,9 @@ void oglInit()
|
|||||||
|
|
||||||
importExtensionFunctions();
|
importExtensionFunctions();
|
||||||
|
|
||||||
|
if(!pglDrawRangeElementsEXT)
|
||||||
|
pglDrawRangeElementsEXT = emu_glDrawRangeElementsEXT;
|
||||||
|
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &ogl_max_tex_size);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &ogl_max_tex_size);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units);
|
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units);
|
||||||
}
|
}
|
||||||
|
@ -726,7 +726,7 @@ static inline void aiocb_pool_shutdown()
|
|||||||
static inline aiocb* aiocb_pool_alloc()
|
static inline aiocb* aiocb_pool_alloc()
|
||||||
{
|
{
|
||||||
ONCE(aiocb_pool_init());
|
ONCE(aiocb_pool_init());
|
||||||
return (aiocb*)pool_alloc(&aiocb_pool);
|
return (aiocb*)pool_alloc(&aiocb_pool, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void aiocb_pool_free(void* cb)
|
static inline void aiocb_pool_free(void* cb)
|
||||||
|
@ -247,6 +247,8 @@ typedef Archives::const_iterator ArchiveCIt;
|
|||||||
// was successfully added to the list. see comments below.
|
// was successfully added to the list. see comments below.
|
||||||
static LibError enqueue_archive(const char* name, const char* P_archive_dir, Archives* archives)
|
static LibError enqueue_archive(const char* name, const char* P_archive_dir, Archives* archives)
|
||||||
{
|
{
|
||||||
|
archives=0;// HACK HACK HACK: disables zip files (WIP)
|
||||||
|
|
||||||
// caller doesn't want us to check if this is a Zip file. this is the
|
// caller doesn't want us to check if this is a Zip file. this is the
|
||||||
// case in all subdirectories of the mount point, since checking for all
|
// case in all subdirectories of the mount point, since checking for all
|
||||||
// mounted files would be slow. see mount_dir_tree.
|
// mounted files would be slow. see mount_dir_tree.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -116,6 +116,8 @@ static void create_level(uint level, uint level_w, uint level_h,
|
|||||||
const u8* restrict level_data, size_t level_data_size, void* restrict ctx)
|
const u8* restrict level_data, size_t level_data_size, void* restrict ctx)
|
||||||
{
|
{
|
||||||
CreateLevelData* cld = (CreateLevelData*)ctx;
|
CreateLevelData* cld = (CreateLevelData*)ctx;
|
||||||
|
const size_t src_w = cld->prev_level_w;
|
||||||
|
const size_t src_h = cld->prev_level_h;
|
||||||
const u8* src = cld->prev_level_data;
|
const u8* src = cld->prev_level_data;
|
||||||
u8* dst = (u8*)level_data;
|
u8* dst = (u8*)level_data;
|
||||||
|
|
||||||
@ -128,36 +130,42 @@ static void create_level(uint level, uint level_w, uint level_h,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
const uint num_components = cld->num_components;
|
const uint num_components = cld->num_components;
|
||||||
const size_t dx = num_components, dy = dx*level_w*2;
|
const size_t dx = num_components, dy = dx*src_w;
|
||||||
|
|
||||||
// special case: image is too small for 2x2 filter
|
// special case: image is too small for 2x2 filter
|
||||||
if(cld->prev_level_w == 1 || cld->prev_level_h == 1)
|
if(cld->prev_level_w == 1 || cld->prev_level_h == 1)
|
||||||
{
|
{
|
||||||
for(uint y = 0; y < level_h; y++)
|
// image is either a horizontal or vertical line.
|
||||||
|
// their memory layout is the same (packed pixels), so no special
|
||||||
|
// handling is needed; just pick max dimension.
|
||||||
|
for(uint y = 0; y < MAX(src_w, src_h); y += 2)
|
||||||
{
|
{
|
||||||
for(uint i = 0; i < num_components; i++)
|
for(uint i = 0; i < num_components; i++)
|
||||||
{
|
{
|
||||||
*dst++ = (src[0]+src[dy]+1)/2;
|
*dst++ = (src[0]+src[dx]+1)/2;
|
||||||
src += 1;
|
src += 1;
|
||||||
}
|
}
|
||||||
src += dy;
|
|
||||||
|
src += dx; // skip to next pixel (since box is 2x2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// normal
|
// normal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(uint y = 0; y < level_h; y++)
|
for(uint y = 0; y < src_h; y += 2)
|
||||||
{
|
{
|
||||||
for(uint x = 0; x < level_w; x++)
|
for(uint x = 0; x < src_w; x += 2)
|
||||||
{
|
{
|
||||||
for(uint i = 0; i < num_components; i++)
|
for(uint i = 0; i < num_components; i++)
|
||||||
{
|
{
|
||||||
*dst++ = (src[0]+src[dx]+src[dy]+src[dx+dy]+2)/4;
|
*dst++ = (src[0]+src[dx]+src[dy]+src[dx+dy]+2)/4;
|
||||||
src += 1;
|
src += 1;
|
||||||
}
|
}
|
||||||
src += dx;
|
|
||||||
|
src += dx; // skip to next pixel (since box is 2x2)
|
||||||
}
|
}
|
||||||
src += dy;
|
|
||||||
|
src += dy; // skip to next row (since box is 2x2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ static void fn_store(HDATA* hd, const char* fn)
|
|||||||
if(hd->type->user_size+size <= HDATA_USER_SIZE)
|
if(hd->type->user_size+size <= HDATA_USER_SIZE)
|
||||||
hd->fn = (const char*)hd->user + hd->type->user_size;
|
hd->fn = (const char*)hd->user + hd->type->user_size;
|
||||||
else if(size <= FN_POOL_EL_SIZE)
|
else if(size <= FN_POOL_EL_SIZE)
|
||||||
hd->fn = (const char*)pool_alloc(&fn_pool);
|
hd->fn = (const char*)pool_alloc(&fn_pool, 0);
|
||||||
|
|
||||||
// in case none of the above applied and/or were successful:
|
// in case none of the above applied and/or were successful:
|
||||||
// fall back to heap alloc.
|
// fall back to heap alloc.
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
#include "win_internal.h"
|
#include "win_internal.h"
|
||||||
#include "sysdep/cpu.h"
|
#include "allocators.h"
|
||||||
|
|
||||||
|
|
||||||
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding
|
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding
|
||||||
@ -332,11 +332,9 @@ struct WDIR
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// suballocator - satisfies most requests with a reusable static instance.
|
// suballocator - satisfies most requests with a reusable static instance,
|
||||||
// this avoids hundreds of alloc/free which would fragment the heap.
|
// thus speeding up allocation and avoiding heap fragmentation.
|
||||||
// to guarantee thread-safety, we fall back to malloc if the instance is
|
// thread-safe.
|
||||||
// already in use. (it's important to avoid suprises since this is such a
|
|
||||||
// low-level routine).
|
|
||||||
|
|
||||||
static WDIR global_wdir;
|
static WDIR global_wdir;
|
||||||
static uintptr_t global_wdir_is_in_use;
|
static uintptr_t global_wdir_is_in_use;
|
||||||
@ -344,26 +342,12 @@ static uintptr_t global_wdir_is_in_use;
|
|||||||
// zero-initializes the WDIR (code below relies on this)
|
// zero-initializes the WDIR (code below relies on this)
|
||||||
static inline WDIR* wdir_alloc()
|
static inline WDIR* wdir_alloc()
|
||||||
{
|
{
|
||||||
WDIR* d;
|
return (WDIR*)single_calloc(&global_wdir, &global_wdir_is_in_use, sizeof(WDIR));
|
||||||
|
|
||||||
// successfully reserved the global instance
|
|
||||||
if(CAS(&global_wdir_is_in_use, 0, 1))
|
|
||||||
{
|
|
||||||
d = &global_wdir;
|
|
||||||
memset(d, 0, sizeof(*d));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d = (WDIR*)calloc(1, sizeof(WDIR));
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wdir_free(WDIR* d)
|
static inline void wdir_free(WDIR* d)
|
||||||
{
|
{
|
||||||
if(d == &global_wdir)
|
single_free(&global_wdir, &global_wdir_is_in_use, d);
|
||||||
global_wdir_is_in_use = 0;
|
|
||||||
else
|
|
||||||
free(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user