From 6ec42ae8a1e5a82daa098951b5ad8ccc9c506b0f Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 11 Feb 2017 18:29:41 +0100 Subject: [PATCH] Calculate total mipmap texture size with geometric series formula --- include/c3d/texture.h | 34 +++++++++++++++++++++++++++++++++- source/texture.c | 35 +++-------------------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/include/c3d/texture.h b/include/c3d/texture.h index 33200ad..d44e02b 100644 --- a/include/c3d/texture.h +++ b/include/c3d/texture.h @@ -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); diff --git a/source/texture.c b/source/texture.c index 94e5534..f6078d0 100644 --- a/source/texture.c +++ b/source/texture.c @@ -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,8 +71,7 @@ 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); + memcpy(out, data, size); } static void C3Di_DownscaleRGBA8(u32* dst, const u32* src[4])