Calculate total mipmap texture size with geometric series formula
This commit is contained in:
parent
0fd245b171
commit
6ec42ae8a1
@ -34,7 +34,6 @@ typedef struct ALIGN(8)
|
||||
} C3D_TexInitParams;
|
||||
|
||||
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p);
|
||||
void* C3D_TexGetLevel(C3D_Tex* tex, int level, u32* size);
|
||||
void C3D_TexUploadLevel(C3D_Tex* tex, const void* data, int level);
|
||||
void C3D_TexGenerateMipmap(C3D_Tex* tex);
|
||||
void C3D_TexBind(int unitId, C3D_Tex* tex);
|
||||
@ -46,6 +45,32 @@ static inline int C3D_TexCalcMaxLevel(u32 width, u32 height)
|
||||
return (31-__builtin_clz(width < height ? width : height)) - 3; // avoid sizes smaller than 8
|
||||
}
|
||||
|
||||
static inline u32 C3D_TexCalcLevelSize(u32 size, int level)
|
||||
{
|
||||
return size >> (2*level);
|
||||
}
|
||||
|
||||
static inline u32 C3D_TexCalcTotalSize(u32 size, int maxLevel)
|
||||
{
|
||||
/*
|
||||
S = s + sr + sr^2 + sr^3 + ... + sr^n
|
||||
Sr = sr + sr^2 + sr^3 + ... + sr^(n+1)
|
||||
S-Sr = s - sr^(n+1)
|
||||
S(1-r) = s(1 - r^(n+1))
|
||||
S = s (1 - r^(n+1)) / (1-r)
|
||||
|
||||
r = 1/4
|
||||
1-r = 3/4
|
||||
|
||||
S = 4s (1 - (1/4)^(n+1)) / 3
|
||||
S = 4s (1 - 1/4^(n+1)) / 3
|
||||
S = (4/3) (s - s/4^(n+1))
|
||||
S = (4/3) (s - s/(1<<(2n+2)))
|
||||
S = (4/3) (s - s>>(2n+2))
|
||||
*/
|
||||
return (size - C3D_TexCalcLevelSize(size,maxLevel+1)) * 4 / 3;
|
||||
}
|
||||
|
||||
static inline bool C3D_TexInit(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3D_TexInitWithParams(tex,
|
||||
@ -64,6 +89,13 @@ static inline bool C3D_TexInitVRAM(C3D_Tex* tex, u16 width, u16 height, GPU_TEXC
|
||||
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, true });
|
||||
}
|
||||
|
||||
static inline void* C3D_TexGetLevel(C3D_Tex* tex, int level, u32* size)
|
||||
{
|
||||
if (size) *size = C3D_TexCalcLevelSize(tex->size, level);
|
||||
if (!level) return tex->data;
|
||||
return (u8*)tex->data + C3D_TexCalcTotalSize(tex->size, level-1);
|
||||
}
|
||||
|
||||
static inline void C3D_TexUpload(C3D_Tex* tex, const void* data)
|
||||
{
|
||||
C3D_TexUploadLevel(tex, data, 0);
|
||||
|
@ -43,19 +43,9 @@ bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p)
|
||||
u32 size = fmtSize(p.format);
|
||||
if (!size) return false;
|
||||
size *= (u32)p.width * p.height / 8;
|
||||
u32 total_size = C3D_TexCalcLevelSize(size, p.maxLevel);
|
||||
|
||||
u32 alloc_size = size;
|
||||
{
|
||||
int i;
|
||||
u32 level_size = size;
|
||||
for (i = 0; i < p.maxLevel; i ++)
|
||||
{
|
||||
level_size >>= 2;
|
||||
alloc_size += level_size;
|
||||
}
|
||||
}
|
||||
|
||||
tex->data = p.onVram ? vramAlloc(alloc_size) : linearAlloc(alloc_size);
|
||||
tex->data = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
|
||||
if (!tex->data) return false;
|
||||
|
||||
tex->width = p.width;
|
||||
@ -74,24 +64,6 @@ bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p)
|
||||
return true;
|
||||
}
|
||||
|
||||
void* C3D_TexGetLevel(C3D_Tex* tex, int level, u32* size)
|
||||
{
|
||||
u8* data = (u8*)tex->data;
|
||||
u32 level_size = tex->size;
|
||||
int i;
|
||||
for (i = 0; i <= tex->maxLevel; i ++)
|
||||
{
|
||||
if (i == level)
|
||||
{
|
||||
if (size) *size = level_size;
|
||||
return data;
|
||||
}
|
||||
data += level_size;
|
||||
level_size >>= 2;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void C3D_TexUploadLevel(C3D_Tex* tex, const void* data, int level)
|
||||
{
|
||||
if (!tex->data || addrIsVRAM(tex->data))
|
||||
@ -99,7 +71,6 @@ void C3D_TexUploadLevel(C3D_Tex* tex, const void* data, int level)
|
||||
|
||||
u32 size = 0;
|
||||
void* out = C3D_TexGetLevel(tex, level, &size);
|
||||
if (out)
|
||||
memcpy(out, data, size);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user