1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-10-04 05:13:19 +00:00

Merge branch 'experimental'

This commit is contained in:
fgenesis 2013-11-05 16:51:26 +01:00
commit cccd42227f
41 changed files with 1335 additions and 1122 deletions

View file

@ -113,6 +113,13 @@ void AfterEffectManager::deleteShaders()
}
}
void AfterEffectManager::unloadShaders()
{
for(size_t i = 0; i < loadedShaders.size(); ++i)
if(loadedShaders[i])
loadedShaders[i]->unload();
}
void AfterEffectManager::clear()
{
deleteEffects();
@ -196,7 +203,7 @@ void AfterEffectManager::renderGrid()
Shader *activeShader = 0;
for (size_t i = 0; i < shaderPipeline.size(); ++i)
{
if(shaderPipeline[i])
if(shaderPipeline[i] && shaderPipeline[i]->isLoaded())
{
if(firstShader < 0)
{
@ -275,7 +282,7 @@ void AfterEffectManager::renderGrid()
for(int i = firstShader + 1; i <= lastShader; ++i)
{
activeShader = shaderPipeline[i];
if(!activeShader)
if(!(activeShader && activeShader->isLoaded()))
continue;
// Swap and exchange framebuffers. The old output buffer serves as texture input for the other one
@ -373,7 +380,7 @@ void AfterEffectManager::renderGridPoints()
void AfterEffectManager::unloadDevice()
{
backupBuffer.unloadDevice();
deleteShaders();
unloadShaders();
}
void AfterEffectManager::reloadDevice()
@ -399,7 +406,22 @@ void AfterEffectManager::reloadDevice()
else
backupBuffer.init(-1, -1, true);
loadShaders();
for (size_t i = 0; i < loadedShaders.size(); ++i)
{
if (Shader *sh = loadedShaders[i])
{
sh->reload();
if (!sh->isLoaded())
{
debugLog("AfterEffect::reloadDevice(): Failed to reload shader");
delete sh;
loadedShaders[i] = 0;
for(size_t j = 0; j < shaderPipeline.size(); ++j)
if(sh == shaderPipeline[j])
shaderPipeline[j] = 0;
}
}
}
}
void AfterEffectManager::addEffect(Effect *e)
@ -612,7 +634,7 @@ int AfterEffectManager::_insertShader(Shader *sh)
return loadedShaders.size();
}
void AfterEffectManager::unloadShader(int handle)
void AfterEffectManager::deleteShader(int handle)
{
Shader *sh = getShaderPtr(handle);
if(!sh)

View file

@ -91,6 +91,7 @@ public:
void renderGridPoints();
void loadShaders();
void unloadShaders(); // unloads shaders but keeps code and data intact, so that they can be reloaded.
void deleteShaders();
void unloadDevice();
@ -116,7 +117,7 @@ public:
Shader *getShaderPtr(int handle);
void setShaderPipelineSize(size_t size);
bool setShaderPipelinePos(int handle, size_t pos);
void unloadShader(int handle);
void deleteShader(int handle);
protected:
int _insertShader(Shader *sh);

View file

@ -12,6 +12,7 @@ public:
virtual void setText(const std::string& text) = 0;
virtual void setWidth(int width) = 0;
virtual void setFontSize(int sz) = 0;
virtual void setAlign(Align a) = 0;
};

View file

@ -63,7 +63,7 @@ public:
bool isScrollingText();
void stopScrollingText();
bool isEmpty();
void setAlign(Align align);
virtual void setAlign(Align align);
std::string getText();
int getWidthOnScreen();
void loadSpacingMap(const std::string &file);

View file

@ -32,7 +32,7 @@ public:
void setWidth(int width);
void setFontSize(int sz);
int getNumLines() { return lines.size(); }
void setAlign(Align align);
virtual void setAlign(Align align);
protected:
int fontDrawSize, textWidth;
void formatText();

View file

@ -0,0 +1,291 @@
// Public domain
// Aquaria specific...
#include "Base.h"
#include "algorithmx.h"
#include "MemoryAllocatorSmallBlock.h"
#include "bithacks.h"
#include <assert.h>
//#define DD(...) fprintf(stderr, __VA_ARGS__)
#define DD(...)
#define logdev(...)
#define logerror(...)
#ifdef NDEBUG
# define ASSERT(x)
#else
# define ASSERT(x) assert(x)
#endif
SmallBlockAllocator::SmallBlockAllocator(unsigned int blockSizeMin,
unsigned int blockSizeMax,
unsigned int blockSizeIncr /* = 8 */,
unsigned int elemsPerBlockMin /* = 64 */,
unsigned int elemsPerBlockMax /* = 2048 */)
: _blockSizeMin(blockSizeMin)
, _blockSizeMax(blockSizeMax)
, _blockSizeIncr(blockSizeIncr)
, _elemsPerBlockMin(elemsPerBlockMin)
, _elemsPerBlockMax(elemsPerBlockMax)
{
ASSERT(_blockSizeIncr % 4 == 0); // less than 4 bytes makes no sense
ASSERT(_blockSizeMin % _blockSizeIncr == 0);
ASSERT(_blockSizeMax % _blockSizeIncr == 0);
ASSERT((_blockSizeMax - _blockSizeMin) % _blockSizeIncr == 0);
unsigned int c = ((_blockSizeMax - _blockSizeMin) / _blockSizeIncr) + 1;
logdev("SBA: Using %u distinct block sizes from %u - %u bytes", c, _blockSizeMin, _blockSizeMax);
_blocks = new Block*[c]; // TODO: Do we really want to use dynamic allocation here?
memset(_blocks, 0, c * sizeof(Block*));
}
SmallBlockAllocator::~SmallBlockAllocator()
{
while(_allblocks.size())
{
Block *blk = _allblocks.back();
logerror("~SmallBlockAllocator(): Warning: Leftover block with %u/%u elements, %uB each",
blk->maxElems, blk->maxElems - blk->freeElems, blk->elemSize);
_FreeBlock(blk);
}
delete [] _blocks;
}
void *SmallBlockAllocator::Alloc(void *ptr, size_t newsize, size_t oldsize)
{
DD("SBA::Alloc() ptr = %p; newsize = %u, oldsize = %u", ptr, newsize, oldsize);
if(ptr)
{
if(!newsize)
{
_Free(ptr, oldsize);
return NULL;
}
else if(newsize == oldsize)
return ptr;
else
return _Realloc(ptr, newsize, oldsize);
}
else
{
if(newsize)
return _Alloc(newsize);
}
return NULL;
}
SmallBlockAllocator::Block *SmallBlockAllocator::_AllocBlock(unsigned int elemCount, unsigned int elemSize)
{
DD("SBA: _AllocBlock: elemCount = %u, elemSize = %u", elemCount, elemSize);
const unsigned int bitsPerInt = (sizeof(unsigned int) * 8); // 32
unsigned int bitmapInts = (elemCount + (bitsPerInt - 1)) / bitsPerInt;
void *ptr = malloc(
(sizeof(Block) - sizeof(unsigned int)) // block header without bitmap[1]
+ (bitmapInts * sizeof(unsigned int)) // actual bitmap size
+ (elemCount * elemSize) // data size
);
if(!ptr)
return NULL;
Block *blk = (Block*)ptr;
memset(&blk->bitmap[0], 0xff, bitmapInts * sizeof(unsigned int)); // all free
blk->elemSize = elemSize;
blk->maxElems = elemCount;
blk->freeElems = elemCount;
blk->bitmapInts = bitmapInts;
blk->next = NULL;
blk->prev = NULL;
// using insertion sort
std::vector<Block*>::iterator insertit = std::lower_bound(_allblocks.begin(), _allblocks.end(), blk);
_allblocks.insert(insertit, blk);
return blk;
}
void SmallBlockAllocator::_FreeBlock(Block *blk)
{
DD("SBA: _FreeBlock: elemCount = %u, elemSize = %u", blk->maxElems, blk->elemSize);
if(blk->prev)
blk->prev->next = blk->next;
else
_blocks[GetIndexForElemSize(blk->elemSize)] = blk->next;
if(blk->next)
blk->next->prev = blk->prev;
free(blk);
// keeps the vector sorted
_allblocks.erase(std::remove(_allblocks.begin(), _allblocks.end(), blk), _allblocks.end());
}
SmallBlockAllocator::Block *SmallBlockAllocator::_AppendBlock(unsigned int elemSize)
{
unsigned int idx = GetIndexForElemSize(elemSize);
Block *blk = _blocks[idx];
unsigned int elemsPerBlock = _elemsPerBlockMin;
if(blk)
{
while(blk->next)
blk = blk->next;
elemsPerBlock = blk->maxElems * 2; // new block is double the size
if(elemsPerBlock > _elemsPerBlockMax)
elemsPerBlock = _elemsPerBlockMax;
}
unsigned int blockElemSize = ((elemSize + (_blockSizeIncr - 1)) / _blockSizeIncr) * _blockSizeIncr;
ASSERT(blockElemSize >= elemSize);
Block *newblk = _AllocBlock(elemsPerBlock, blockElemSize);
if(!newblk)
return NULL;
if(blk)
{
blk->next = newblk; // append to list
newblk->prev = blk;
}
else
_blocks[idx] = newblk; // list head
return newblk;
}
SmallBlockAllocator::Block *SmallBlockAllocator::_GetFreeBlock(unsigned int elemSize)
{
unsigned int idx = GetIndexForElemSize(elemSize);
Block *blk = _blocks[idx];
while(blk && !blk->freeElems)
blk = blk->next;
return blk;
}
void *SmallBlockAllocator::Block::allocElem()
{
ASSERT(freeElems);
unsigned int i = 0;
for( ; !bitmap[i]; ++i) // as soon as one isn't all zero, there's a free slot
ASSERT(i < bitmapInts);
ASSERT(i < bitmapInts);
int freeidx = bithacks::ctz(bitmap[i]);
ASSERT(bitmap[i] & (1 << freeidx)); // make sure this is '1' (= free)
bitmap[i] &= ~(1 << freeidx); // put '0' where '1' was (-> mark as non-free)
--freeElems;
const unsigned int offs = (i * sizeof(unsigned int) * 8 * elemSize); // skip forward i bitmaps (32 elems each)
unsigned char *ret = getPtr() + offs + (elemSize * freeidx);
ASSERT(contains(ret));
return ret;
}
bool SmallBlockAllocator::Block::contains(unsigned char *ptr) const
{
const unsigned char *pp = getPtr();
if(ptr < pp)
return false; // pointer is out of range (1)
if(ptr >= pp + (maxElems * elemSize))
return false; // pointer is out of range (2)
return true;
}
void SmallBlockAllocator::Block::freeElem(unsigned char *ptr)
{
ASSERT(contains(ptr));
ASSERT(freeElems < maxElems); // make sure the block is not all free
const ptrdiff_t p = ptr - getPtr();
ASSERT((p % elemSize) == 0); // make sure alignment is right
const unsigned int idx = p / elemSize;
const unsigned int bitsPerInt = sizeof(unsigned int) * 8; // 32
const unsigned int bitmapIdx = idx / bitsPerInt;
const unsigned int bitIdx = idx % bitsPerInt;
ASSERT(bitmapIdx < bitmapInts);
ASSERT(!(bitmap[bitmapIdx] & (1 << bitIdx))); // make sure this is '0' (= used)
bitmap[bitmapIdx] |= (1 << bitIdx); // put '1' where '0' was (-> mark as free)
++freeElems;
#ifdef _DEBUG
memset(ptr, 0xfa, elemSize);
#endif
}
void *SmallBlockAllocator::_FallbackAlloc(unsigned int size)
{
return malloc(size);
}
void SmallBlockAllocator::_FallbackFree(void *ptr)
{
free(ptr);
}
void *SmallBlockAllocator::_Alloc(unsigned int size)
{
if(size > _blockSizeMax)
return _FallbackAlloc(size);
Block *blk = _GetFreeBlock(size);
ASSERT(!blk || blk->freeElems);
if(!blk)
{
blk = _AppendBlock(size);
if(!blk)
return _FallbackAlloc(size);
}
return blk->allocElem();
}
bool SmallBlockAllocator::Block_ptr_cmp(const Block *blk, const void *ptr)
{
return blk->getEndPtr() < ((unsigned char*)ptr);
}
SmallBlockAllocator::Block *SmallBlockAllocator::_FindBlockContainingPtr(void *ptr)
{
// MSVC's std::lower_bound uses iterator debug checks in debug mode,
// which breaks Block_ptr_cmp() because the left and right types are different.
std::vector<Block*>::iterator it = stdx_fg::lower_bound(_allblocks.begin(), _allblocks.end(), ptr, Block_ptr_cmp);
return (it != _allblocks.end() && (*it)->contains((unsigned char*)ptr)) ? *it : NULL;
}
void SmallBlockAllocator::_Free(void *ptr, unsigned int size)
{
if(size <= _blockSizeMax)
{
Block *blk = _FindBlockContainingPtr(ptr);
if(blk)
{
ASSERT(blk->elemSize >= size); // ptr might be from a larger block in case _Realloc() failed to shrink
blk->freeElem((unsigned char*)ptr);
if(blk->freeElems == blk->maxElems)
_FreeBlock(blk); // remove if completely unused
return;
}
}
_FallbackFree(ptr);
}
void *SmallBlockAllocator::_Realloc(void *ptr, unsigned int newsize, unsigned int oldsize)
{
void *newptr = _Alloc(newsize);
// If the new allocation failed, just re-use the old pointer if it was a shrink request
// This also satisfies Lua, which assumes that realloc() shrink requests cannot fail
if(!newptr)
return newsize <= oldsize ? ptr : NULL;
memcpy(newptr, ptr, std::min(oldsize, newsize));
_Free(ptr, oldsize);
return newptr;
}

View file

@ -0,0 +1,100 @@
#ifndef MEMORY_ALLOCATOR_SMALL_BLOCK_H
#define MEMORY_ALLOCATOR_SMALL_BLOCK_H
/* Optimized memory allocator for small & frequent (de-)allocations.
* Low memory overhead. Used for Lua.
* Inspired by http://dns.achurch.org/cgi-bin/hg/aquaria-psp/file/tip/PSP/src/lalloc.c
*/
// Originally made for LV3proj_ng (https://github.com/fgenesis/lv3proj_ng)
// Hacked in shape for use in Aquaria
// Public domain
#include <vector>
class SmallBlockAllocator
{
public:
SmallBlockAllocator(unsigned int blockSizeMin, unsigned int blockSizeMax, unsigned int blockSizeIncr = 8,
unsigned int elemsPerBlockMin = 64, unsigned int elemsPerBlockMax = 2048);
~SmallBlockAllocator();
void *Alloc(void *ptr, size_t newsize, size_t oldsize);
private:
void *_Alloc(unsigned int size);
void *_Realloc(void *ptr, unsigned int newsize, unsigned int oldsize);
void _Free(void* ptr, unsigned int size);
void *_FallbackAlloc(unsigned int size);
void _FallbackFree(void *ptr);
struct Block
{
// block header start
Block *next;
Block *prev;
unsigned short maxElems;
unsigned short freeElems;
unsigned short elemSize;
unsigned short bitmapInts;
// block header end
unsigned int bitmap[1]; // variable sized
// actual storage memory starts after bitmap[bitmapInts]
inline unsigned char *getPtr()
{
return (unsigned char*)&bitmap[bitmapInts];
}
inline const unsigned char *getPtr() const
{
return (unsigned char*)&bitmap[bitmapInts];
}
inline unsigned char *getEndPtr()
{
return getPtr() + (maxElems * elemSize);
}
inline const unsigned char *getEndPtr() const
{
return getPtr() + (maxElems * elemSize);
}
void *allocElem();
void freeElem(unsigned char *ptr);
bool contains(unsigned char *ptr) const;
};
Block *_AllocBlock(unsigned int elemCount, unsigned int elemSize);
void _FreeBlock(Block *blk);
Block *_AppendBlock(unsigned int elemSize);
Block *_GetFreeBlock(unsigned int elemSize); // NULL if none free
Block *_FindBlockContainingPtr(void *ptr);
inline unsigned int GetIndexForElemSize(unsigned int elemSize)
{
//ASSERT(elemSize);
//ASSERT(elemSize <= _blockSizeMax);
return ((elemSize + (_blockSizeIncr - 1)) / _blockSizeIncr) - 1;
}
static bool Block_ptr_cmp(const Block *blk, const void *ptr);
Block **_blocks;
std::vector<Block*> _allblocks; // always sorted by pointer address
unsigned int _blockSizeMin;
unsigned int _blockSizeMax;
unsigned int _blockSizeIncr;
unsigned int _elemsPerBlockMin;
unsigned int _elemsPerBlockMax;
};
#endif

View file

@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
ParticleEffect::ParticleEffect() : RenderObject()
{
addType(SCO_PARTICLE_EFFECT);
running = false;
waitForParticles = true;
effectLife = -1;

View file

@ -39,6 +39,7 @@ static const char *scriptObjTypeNames[] =
/* (1 <<11) */ "Text",
/* (1 <<12) */ "PauseQuad",
/* (1 <<13) */ "Shader",
/* (1 <<14) */ "ParticleEffect",
NULL
};

View file

@ -41,6 +41,7 @@ enum ScriptObjectType
SCO_TEXT = 0x0800,
SCO_PAUSEQUAD = 0x1000,
SCO_SHADER = 0x2000,
SCO_PARTICLE_EFFECT = 0x4000,
SCO_FORCE_32BIT = 0xFFFFFFFF
};

View file

@ -164,7 +164,10 @@ bool Shader::isLoaded() const
void Shader::reload()
{
load(vertFile, fragFile);
if (vertFile.size() || fragFile.size())
load(vertFile, fragFile);
else
loadSrc(vertSrc.c_str(), fragSrc.c_str());
}
void Shader::bind()
@ -321,6 +324,9 @@ void Shader::loadSrc(const char *vertCode, const char *fragCode)
return;
}
vertSrc = vertCode ? vertCode : "";
fragSrc = fragCode ? fragCode : "";
_queryUniforms();
#endif
@ -328,15 +334,6 @@ void Shader::loadSrc(const char *vertCode, const char *fragCode)
void Shader::_setUniform(Uniform *u)
{
/*if(u->location == -1)
{
u->location = glGetUniformLocationARB(g_programObj, u->name);
if(u->location == -1)
{
u->dirty = false;
return;
}
}*/
switch(u->type)
{
case GL_FLOAT: glUniform1fvARB(u->location, 1, u->data.f); break;
@ -381,9 +378,13 @@ void Shader::_queryUniforms()
glGetObjectParameterivARB(g_programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB , &numUniforms);
if (numUniforms <= 0)
{
uniforms.clear();
return;
}
uniforms.reserve(numUniforms);
size_t total = 0;
for (unsigned int i = 0; i < numUniforms; ++i)
{
@ -396,15 +397,27 @@ void Shader::_queryUniforms()
u.location = glGetUniformLocationARB(g_programObj, u.name);
if(u.location == -1)
continue;
u.dirty = false;
u.type = type;
memset(&u.data, 0, sizeof(u.data));
uniforms.push_back(u);
bool add = total >= uniforms.size();
if(add || type != u.type) // keep data intact on reload
memset(&u.data, 0, sizeof(u.data));
u.dirty = true;
u.type = type;
if(add)
uniforms.push_back(u);
else
uniforms[total] = u;
++total;
}
uniforms.resize(total);
// sort to be able to do binary search later
std::sort(uniforms.begin(), uniforms.end());
uniformsDirty = true;
}
int Shader::_getUniformIndex(const char *name)

View file

@ -44,6 +44,7 @@ public:
protected:
std::string vertFile, fragFile;
std::string vertSrc, fragSrc;
#ifdef BBGE_BUILD_OPENGL
GLuint g_programObj;
int numUniforms;
@ -72,7 +73,7 @@ private:
float f[4];
};
} data;
char name[32];
char name[64];
bool operator< (const Uniform&) const;
};

View file

@ -251,6 +251,7 @@ public:
void selectNextBone();
bool isLoaded();
int getNumAnimLayers() const { return animLayers.size(); }
AnimationLayer* getAnimationLayer(int l);
int getBoneIdx(Bone *b);

84
BBGE/bithacks.h Normal file
View file

@ -0,0 +1,84 @@
#ifndef BITHACKS_H
#define BITHACKS_H
#ifdef _MSC_VER
# include <intrin.h>
#endif
namespace bithacks {
typedef unsigned int uint32;
typedef int int32;
// floor to next power of 2
inline uint32 flp2(uint32 x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >> 1);
}
// ceil to next power of 2
inline uint32 clp2(uint32 x)
{
--x;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x + 1;
}
inline uint32 popcnt(uint32 x)
{
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
x += (x >> 8);
x += (x >> 16);
return x & 0x0000003f;
}
inline uint32 ctz(uint32 x)
{
#ifdef __GNUC__
return __builtin_ctz(x);
#elif defined(_MSC_VER) && defined(_M_IX86)
unsigned long r = 0;
_BitScanForward(&r, x);
return r;
#else
return popcnt((x & -x) - 1);
#endif
}
inline unsigned int clz(uint32 x)
{
#ifdef __GNUC__
return __builtin_clz(x);
#elif defined(_MSC_VER) && defined(_M_IX86)
unsigned long r = 0;
_BitScanReverse(&r, x);
return r;
#else
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return 32 - popcnt(x);
#endif
}
}; // end namespace bithacks
#endif