ulibrary/source/texPalManager.c
2024-08-06 01:10:18 +01:00

283 lines
8.1 KiB
C

#include "ulib.h"
// PALETTE
//
// Les adresses (paletteID) sont à l'octet près, partant de 0 (début de la bank allouée aux TEX_PALETTE)
// On commence au début de la VRAM mappée en LCD
void *ul_texPalVramBase = (void*)VRAM_F;
// 16 ko de RAM par défaut
int ul_texPalVramSize = 16 << 10;
// Banque A seulement par défaut
UL_BANKS ul_texPalVramBanks = UL_BANK_F;
#define DEFAULT_TABLE_SIZE 128
int ulTexPalBlocksMax, ulTexPalBlocksNb;
typedef struct
{
u16 offset, size;
} UL_TEXPALBLOCK;
#define isBlockFree(i) (ulTexPalBlocks[i].size & 0x8000)
#define getBlockSize(i) (ulTexPalBlocks[i].size & 0x7fff)
#define getBlockOffset(i) (ulTexPalBlocks[i].offset)
#define setBlockFree(i, free) \
(ulTexPalBlocks[i].size = (ulTexPalBlocks[i].size & ((free) ? 0xffff : 0x7fff)) | ((free)? 0x8000 : 0))
#define setBlockSize(i, nsize) \
(ulTexPalBlocks[i].size = (ulTexPalBlocks[i].size & ~0x7fff) | (nsize))
#define setBlockOffset(i, noffset) \
(ulTexPalBlocks[i].offset = noffset)
UL_TEXPALBLOCK *ulTexPalBlocks;
void ulTexPalInit()
{
ulTexPalBlocksMax = DEFAULT_TABLE_SIZE;
ulTexPalBlocksNb = 1;
ulTexPalBlocks = (UL_TEXPALBLOCK*)calloc(1, ulTexPalBlocksMax * sizeof(UL_TEXPALBLOCK));
// Premier bloc: libre, taille totale de la VRAM, adresse 0
setBlockOffset(0, 0);
setBlockSize(0, ul_texPalVramSize >> 3);
setBlockFree(0, 1);
}
int ulTexPalAllocBlock(int blockSize, int format)
{
int i, align;
align = (format == UL_PF_PAL2) ? 8 : 16;
// La taille est toujours multiple de 8 ou 16 - arrondir au bloc supérieur
//if (initialBlockSize & (align - 1))
// initialBlockSize += align - (initialBlockSize & (align - 1));
if (blockSize & 7)
blockSize += 8;
blockSize >>= 3;
for (i=0;i<ulTexPalBlocksNb;i++)
{
if (!isBlockFree(i))
continue;
// Si le bloc n'est pas aligné, il faut un peu plus d'espace
if ((getBlockOffset(i) & 1) && align == 16)
{
// Bloc suffisant?
if (getBlockSize(i) >= blockSize + 1)
{
// Le bloc précédent sera aggrandi de façon à ce que le nouveau
// débute à la position alignée
if (i > 0)
{
setBlockSize(i - 1, getBlockSize(i - 1) + 1);
setBlockSize(i, getBlockSize(i) - 1);
setBlockOffset(i, getBlockOffset(i) + 1);
}
break;
}
}
else
{
// Ce bloc est-il suffisant?
if (getBlockSize(i) >= blockSize)
break;
}
}
// Aucun bloc libre
if (i >= ulTexPalBlocksNb)
return -1;
// Pile la mémoire qu'il faut? - supprimé pour la même raison que
// ulTexVramAllocBlock()
if (getBlockSize(i) == blockSize && i != ulTexPalBlocksNb - 1)
{
// Il n'est plus libre
setBlockFree(i, 0);
}
else
{
// On va ajouter un nouveau bloc
ulTexPalBlocksNb++;
// Plus de mémoire pour le tableau? On l'aggrandit
if (ulTexPalBlocksNb >= ulTexPalBlocksMax)
{
UL_TEXPALBLOCK *oldBlock = ulTexPalBlocks;
ulTexPalBlocksMax += DEFAULT_TABLE_SIZE;
ulTexPalBlocks = (UL_TEXPALBLOCK *)realloc(ulTexPalBlocks, ulTexPalBlocksMax);
// Vérification que la mémoire a bien pu être allouée
if (!ulTexPalBlocks)
{
ulTexPalBlocks = oldBlock;
ulTexPalBlocksMax -= DEFAULT_TABLE_SIZE;
// Pas assez de mémoire
return -1;
}
}
// Décalage pour insérer notre nouvel élément
memmove(ulTexPalBlocks + i + 1, ulTexPalBlocks + i,
sizeof(UL_TEXPALBLOCK) * (ulTexPalBlocksNb - i - 1));
// Remplissons notre nouveau bloc
setBlockSize(i, blockSize);
// Il a l'adresse du bloc qui était là avant
setBlockOffset(i, getBlockOffset(i + 1));
// Il n'est pas libre
setBlockFree(i, 0);
// Pour le prochain, sa taille diminue
setBlockSize(i + 1, getBlockSize(i + 1) - blockSize);
// ATTENTION: calcul d'offset
setBlockOffset(i + 1, getBlockOffset(i + 1) + blockSize);
}
// Note: il faut traduire l'offset en vraie adresse
return getBlockOffset(i);
}
// Note: il faut traduire une vraie adresse en offset
int ulTexPalFreeBlock(int blockOffset)
{
int i, j, updateNeeded;
for (i = 0; i < ulTexPalBlocksNb; i++)
{
if (getBlockOffset(i) == blockOffset)
break;
}
// Impossible de trouver le bloc
if (i >= ulTexPalBlocksNb)
return 0;
// Le bloc est maintenant libre ^^
setBlockFree(i, 1);
// Bon maintenant reste à "assembler" les blocs libres adjacents
do
{
updateNeeded = 0;
for (j = 0; j < ulTexPalBlocksNb - 1; j++)
{
// Cherchons deux blocs adjacents
if ((isBlockFree(j) && isBlockFree(j + 1)) ||
(isBlockFree(j) && getBlockSize(j) == 0))
{
// Assemblons ces blocs maintenant
int newSize = getBlockSize(j) + getBlockSize(j + 1);
int newAdd = getBlockOffset(j);
memmove(ulTexPalBlocks + j, ulTexPalBlocks + j + 1,
sizeof(UL_TEXPALBLOCK) * (ulTexPalBlocksNb - j - 1));
setBlockOffset(j, newAdd);
setBlockSize(j, newSize);
// Le bloc entre deux est supprimé
ulTexPalBlocksNb--;
// ATT: On devra refaire un tour pour vérifier si de nouveaux
// blocs n'ont pas été créés
updateNeeded = 1;
}
}
} while (updateNeeded);
return 1;
}
void uluTexUnloadPal(u32 addr)
{
addr = ulTexPalAddressToOffset(addr);
ulTexPalFreeBlock(addr);
}
// Alignement supérieur (16, 32 => 32 / 64, 32 => 64)
#define alignVal(val, to) \
(((val) & ((to) - 1)) ? ((val) & ~((to) - 1)) + (to) : (val))
void ulTexLoadPal(u16* pal, u16 count, u32 addr)
{
ulChangeVramAllocation(ul_texPalVramBanks, UL_BANK_TYPE_LCD);
// Words are 32 bits => copy number of colors / 2 words
swiCopy(pal, ulGetPaletteAddress(addr) , (count >> 1) | COPY_MODE_WORD);
ulChangeVramAllocation(ul_texPalVramBanks, UL_BANK_TYPE_TEXPAL);
}
int uluTexLoadPal(u16* pal, u16 count, uint8 format)
{
// Ca c'est la taille totale de la mémoire
int memSize;
int addr;
// Détermine la taille de la palette en octets
memSize = alignVal(count << 1, 1 << 3);
// Dans les formats autres que UL_PF_PAL2, on doit aligner à 16 octets au lieu de 8
addr = (int)ulTexPalOffsetToAddress(ulTexPalAllocBlock(memSize, format));
if (addr >= 0 && pal)
{
// Every color is 2 bytes
ulTexLoadPal(pal, memSize >> 1, (u32) addr);
}
return addr;
}
// 1 on success, 0 on failure
int ulSetTexPalVramParameters(int activeBanks, void *baseAddr, int totalSize)
{
int curVramSize = ul_texPalVramSize >> 4;
int blockNum = ulTexPalBlocksNb - 1;
int sizeDiff;
// La taille est toujours multiple de 8 - arrondir au bloc supérieur
if (totalSize & 7)
totalSize += 8;
totalSize >>= 3;
// Différence de taille (négatif pour réduction, positif pour aggrandissement)
sizeDiff = totalSize - curVramSize;
// Le dernier bloc est TOUJOURS libre, même s'il reste 0 octet. Cf
// ulTexPalAllocBlock().
if (isBlockFree(blockNum) && getBlockSize(blockNum) + sizeDiff >= 0)
{
setBlockSize(blockNum, getBlockSize(blockNum) + sizeDiff);
ul_texPalVramBase = baseAddr;
ul_texPalVramSize = totalSize;
ul_texPalVramBanks = activeBanks;
ulChangeVramAllocation(ul_texPalVramBanks, UL_BANK_TYPE_TEXPAL);
}
else
{
return 0;
}
return 1;
}
int ulGetTexPalAvailMemory()
{
return getBlockSize(ulTexPalBlocksNb - 1) << 3;
}
int ulGetTexPalTotalMemory()
{
return ul_texPalVramSize;
}
int ulGetTexPalUsedMemory()
{
return ul_texPalVramSize - ulGetTexPalAvailMemory();
}