Add support for cube textures, see below:
- Added C3D_TexCube structure for holding pointers to all 6 faces - C3D_TexLoadImage accepts face number and mipmap level - C3D_TexGenerateMipmap accepts face number - Added functions (C3D_Tex*GetImagePtr) for accessing image data - Now using GX to copy texture data to VRAM instead of failing - Moved texunit setup code to texture.c
This commit is contained in:
parent
6ec42ae8a1
commit
15de0e300e
@ -3,12 +3,30 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* data;
|
||||
void* data[6];
|
||||
} C3D_TexCube;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
void* data;
|
||||
C3D_TexCube* cube;
|
||||
};
|
||||
|
||||
GPU_TEXCOLOR fmt : 4;
|
||||
size_t size : 28;
|
||||
|
||||
u16 width, height;
|
||||
union
|
||||
{
|
||||
u32 dim;
|
||||
struct
|
||||
{
|
||||
u16 height;
|
||||
u16 width;
|
||||
};
|
||||
};
|
||||
|
||||
u32 param;
|
||||
u32 border;
|
||||
union
|
||||
@ -33,9 +51,9 @@ typedef struct ALIGN(8)
|
||||
bool onVram : 1;
|
||||
} C3D_TexInitParams;
|
||||
|
||||
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p);
|
||||
void C3D_TexUploadLevel(C3D_Tex* tex, const void* data, int level);
|
||||
void C3D_TexGenerateMipmap(C3D_Tex* tex);
|
||||
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexCube* cube, C3D_TexInitParams p);
|
||||
void C3D_TexLoadImage(C3D_Tex* tex, const void* data, GPU_TEXFACE face, int level);
|
||||
void C3D_TexGenerateMipmap(C3D_Tex* tex, GPU_TEXFACE face);
|
||||
void C3D_TexBind(int unitId, C3D_Tex* tex);
|
||||
void C3D_TexFlush(C3D_Tex* tex);
|
||||
void C3D_TexDelete(C3D_Tex* tex);
|
||||
@ -73,32 +91,53 @@ static inline u32 C3D_TexCalcTotalSize(u32 size, int maxLevel)
|
||||
|
||||
static inline bool C3D_TexInit(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3D_TexInitWithParams(tex,
|
||||
return C3D_TexInitWithParams(tex, NULL,
|
||||
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, false });
|
||||
}
|
||||
|
||||
static inline bool C3D_TexInitMipmap(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3D_TexInitWithParams(tex,
|
||||
return C3D_TexInitWithParams(tex, NULL,
|
||||
(C3D_TexInitParams){ width, height, (u8)C3D_TexCalcMaxLevel(width, height), format, GPU_TEX_2D, false });
|
||||
}
|
||||
|
||||
static inline bool C3D_TexInitCube(C3D_Tex* tex, C3D_TexCube* cube, u16 width, u16 height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3D_TexInitWithParams(tex, cube,
|
||||
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_CUBE_MAP, false });
|
||||
}
|
||||
|
||||
static inline bool C3D_TexInitVRAM(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3D_TexInitWithParams(tex,
|
||||
return C3D_TexInitWithParams(tex, NULL,
|
||||
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, true });
|
||||
}
|
||||
|
||||
static inline void* C3D_TexGetLevel(C3D_Tex* tex, int level, u32* size)
|
||||
static inline GPU_TEXTURE_MODE_PARAM C3D_TexGetType(C3D_Tex* tex)
|
||||
{
|
||||
if (size) *size = C3D_TexCalcLevelSize(tex->size, level);
|
||||
if (!level) return tex->data;
|
||||
return (u8*)tex->data + C3D_TexCalcTotalSize(tex->size, level-1);
|
||||
return (GPU_TEXTURE_MODE_PARAM)((tex->param>>28)&0x7);
|
||||
}
|
||||
|
||||
static inline void* C3D_TexGetImagePtr(C3D_Tex* tex, void* data, int level, u32* size)
|
||||
{
|
||||
if (size) *size = level > 0 ? C3D_TexCalcLevelSize(tex->size, level) : C3D_TexCalcTotalSize(tex->size, tex->maxLevel);
|
||||
if (!level) return data;
|
||||
return (u8*)data + (level > 0 ? C3D_TexCalcTotalSize(tex->size, level-1) : 0);
|
||||
}
|
||||
|
||||
static inline void* C3D_Tex2DGetImagePtr(C3D_Tex* tex, int level, u32* size)
|
||||
{
|
||||
return C3D_TexGetImagePtr(tex, tex->data, level, size);
|
||||
}
|
||||
|
||||
static inline void* C3D_TexCubeGetImagePtr(C3D_Tex* tex, GPU_TEXFACE face, int level, u32* size)
|
||||
{
|
||||
return C3D_TexGetImagePtr(tex, tex->cube->data[face], level, size);
|
||||
}
|
||||
|
||||
static inline void C3D_TexUpload(C3D_Tex* tex, const void* data)
|
||||
{
|
||||
C3D_TexUploadLevel(tex, data, 0);
|
||||
C3D_TexLoadImage(tex, data, GPU_TEXFACE_2D, 0);
|
||||
}
|
||||
|
||||
static inline void C3D_TexSetFilter(C3D_Tex* tex, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter)
|
||||
|
@ -5,32 +5,6 @@
|
||||
|
||||
C3D_Context __C3D_Context;
|
||||
|
||||
static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex)
|
||||
{
|
||||
u32 reg[5];
|
||||
reg[0] = tex->border;
|
||||
reg[1] = (u32)tex->height | ((u32)tex->width << 16);
|
||||
reg[2] = tex->param;
|
||||
reg[3] = tex->lodParam;
|
||||
reg[4] = osConvertVirtToPhys(tex->data) >> 3;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT0_BORDER_COLOR, reg, 5);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, tex->fmt);
|
||||
break;
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT1_BORDER_COLOR, reg, 5);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, tex->fmt);
|
||||
break;
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT2_BORDER_COLOR, reg, 5);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, tex->fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static aptHookCookie hookCookie;
|
||||
|
||||
static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
|
||||
|
@ -88,6 +88,7 @@ void C3Di_UpdateContext(void);
|
||||
void C3Di_AttrInfoBind(C3D_AttrInfo* info);
|
||||
void C3Di_BufInfoBind(C3D_BufInfo* info);
|
||||
void C3Di_TexEnvBind(int id, C3D_TexEnv* env);
|
||||
void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex);
|
||||
void C3Di_EffectBind(C3D_Effect* effect);
|
||||
void C3Di_RenderBufBind(C3D_RenderBuf* rb);
|
||||
|
||||
|
133
source/texture.c
133
source/texture.c
@ -1,4 +1,5 @@
|
||||
#include "internal.h"
|
||||
#include <c3d/renderqueue.h>
|
||||
|
||||
// Return bits per pixel
|
||||
static inline size_t fmtSize(GPU_TEXCOLOR fmt)
|
||||
@ -29,28 +30,80 @@ static inline size_t fmtSize(GPU_TEXCOLOR fmt)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool typeIsCube(GPU_TEXTURE_MODE_PARAM type)
|
||||
{
|
||||
return type == GPU_TEX_CUBE_MAP || type == GPU_TEX_SHADOW_CUBE;
|
||||
}
|
||||
|
||||
static inline bool C3Di_TexIs2D(C3D_Tex* tex)
|
||||
{
|
||||
return !typeIsCube(C3D_TexGetType(tex));
|
||||
}
|
||||
|
||||
static inline bool addrIsVRAM(const void* addr)
|
||||
{
|
||||
u32 vaddr = (u32)addr;
|
||||
return vaddr >= 0x1F000000 && vaddr < 0x1F600000;
|
||||
}
|
||||
|
||||
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p)
|
||||
static inline void allocFree(void* addr)
|
||||
{
|
||||
if (addrIsVRAM(addr))
|
||||
vramFree(addr);
|
||||
else
|
||||
linearFree(addr);
|
||||
}
|
||||
|
||||
static void C3Di_TexCubeDelete(C3D_TexCube* cube)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 6; i ++)
|
||||
{
|
||||
if (cube->data[i])
|
||||
{
|
||||
allocFree(cube->data[i]);
|
||||
cube->data[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexCube* cube, C3D_TexInitParams p)
|
||||
{
|
||||
if (tex->data) return false;
|
||||
if ((p.width|p.height) & 7) return false;
|
||||
|
||||
bool isCube = typeIsCube(p.type);
|
||||
if (isCube && !cube) return false;
|
||||
|
||||
u32 size = fmtSize(p.format);
|
||||
if (!size) return false;
|
||||
size *= (u32)p.width * p.height / 8;
|
||||
u32 total_size = C3D_TexCalcLevelSize(size, p.maxLevel);
|
||||
|
||||
tex->data = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
|
||||
if (!tex->data) return false;
|
||||
if (!isCube)
|
||||
{
|
||||
tex->data = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
|
||||
if (!tex->data) return false;
|
||||
} else
|
||||
{
|
||||
memset(cube, 0, sizeof(*cube));
|
||||
int i;
|
||||
for (i = 0; i < 6; i ++)
|
||||
{
|
||||
cube->data[i] = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
|
||||
if (!cube->data[i] ||
|
||||
(i>0 && (((u32)cube->data[0] ^ (u32)cube->data[i])>>(3+22)))) // Check upper 6bits match with first face
|
||||
{
|
||||
C3Di_TexCubeDelete(cube);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
tex->cube = cube;
|
||||
}
|
||||
|
||||
tex->width = p.width;
|
||||
tex->height = p.height;
|
||||
tex->param = GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST) | GPU_TEXTURE_MODE(p.type);
|
||||
tex->param = GPU_TEXTURE_MODE(p.type);
|
||||
if (p.format == GPU_ETC1)
|
||||
tex->param |= GPU_TEXTURE_ETC1_PARAM;
|
||||
if (p.type == GPU_TEX_SHADOW_2D || p.type == GPU_TEX_SHADOW_CUBE)
|
||||
@ -64,14 +117,23 @@ bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexInitParams p)
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_TexUploadLevel(C3D_Tex* tex, const void* data, int level)
|
||||
void C3D_TexLoadImage(C3D_Tex* tex, const void* data, GPU_TEXFACE face, int level)
|
||||
{
|
||||
if (!tex->data || addrIsVRAM(tex->data))
|
||||
if (!tex->data)
|
||||
return;
|
||||
|
||||
u32 size = 0;
|
||||
void* out = C3D_TexGetLevel(tex, level, &size);
|
||||
memcpy(out, data, size);
|
||||
void* out = C3D_TexGetImagePtr(tex,
|
||||
C3Di_TexIs2D(tex) ? tex->data : tex->cube->data[face],
|
||||
level, &size);
|
||||
|
||||
if (!addrIsVRAM(out))
|
||||
memcpy(out, data, size);
|
||||
else
|
||||
{
|
||||
C3D_SafeTextureCopy((u32*)data, 0, (u32*)out, 0, size, 8);
|
||||
gspWaitForPPF();
|
||||
}
|
||||
}
|
||||
|
||||
static void C3Di_DownscaleRGBA8(u32* dst, const u32* src[4])
|
||||
@ -104,7 +166,7 @@ static void C3Di_DownscaleRGB8(u8* dst, const u8* src[4])
|
||||
}
|
||||
}
|
||||
|
||||
void C3D_TexGenerateMipmap(C3D_Tex* tex)
|
||||
void C3D_TexGenerateMipmap(C3D_Tex* tex, GPU_TEXFACE face)
|
||||
{
|
||||
int fmt = tex->fmt;
|
||||
size_t block_size = (8*8*fmtSize(fmt))/8;
|
||||
@ -115,9 +177,12 @@ void C3D_TexGenerateMipmap(C3D_Tex* tex)
|
||||
GX_TRANSFER_IN_FORMAT(tex->fmt) | GX_TRANSFER_OUT_FORMAT(tex->fmt);
|
||||
*/
|
||||
|
||||
void* src = C3Di_TexIs2D(tex) ? tex->data : tex->cube->data[face];
|
||||
if (addrIsVRAM(src))
|
||||
return; // CPU can't write to VRAM
|
||||
|
||||
int i;
|
||||
u32 level_size = tex->size;
|
||||
void* src = tex->data;
|
||||
u32 src_width = tex->width;
|
||||
u32 src_height = tex->height;
|
||||
for (i = 0; i < tex->maxLevel; i ++)
|
||||
@ -176,7 +241,7 @@ void C3D_TexBind(int unitId, C3D_Tex* tex)
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (unitId > 0 && ((tex->param>>28)&7) != GPU_TEX_2D)
|
||||
if (unitId > 0 && C3D_TexGetType(tex) != GPU_TEX_2D)
|
||||
return;
|
||||
|
||||
ctx->flags |= C3DiF_Tex(unitId);
|
||||
@ -186,17 +251,53 @@ void C3D_TexBind(int unitId, C3D_Tex* tex)
|
||||
void C3D_TexFlush(C3D_Tex* tex)
|
||||
{
|
||||
if (tex->data && !addrIsVRAM(tex->data))
|
||||
GSPGPU_FlushDataCache(tex->data, tex->size);
|
||||
GSPGPU_FlushDataCache(tex->data, C3D_TexCalcTotalSize(tex->size, tex->maxLevel));
|
||||
}
|
||||
|
||||
void C3D_TexDelete(C3D_Tex* tex)
|
||||
{
|
||||
if (!tex->data) return;
|
||||
|
||||
if (addrIsVRAM(tex->data))
|
||||
vramFree(tex->data);
|
||||
if (C3Di_TexIs2D(tex))
|
||||
allocFree(tex->data);
|
||||
else
|
||||
linearFree(tex->data);
|
||||
|
||||
C3Di_TexCubeDelete(tex->cube);
|
||||
tex->data = NULL;
|
||||
}
|
||||
|
||||
void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex)
|
||||
{
|
||||
u32 reg[10];
|
||||
u32 regcount = 5;
|
||||
reg[0] = tex->border;
|
||||
reg[1] = tex->dim;
|
||||
reg[2] = tex->param;
|
||||
reg[3] = tex->lodParam;
|
||||
if (C3Di_TexIs2D(tex))
|
||||
reg[4] = osConvertVirtToPhys(tex->data) >> 3;
|
||||
else
|
||||
{
|
||||
int i;
|
||||
C3D_TexCube* cube = tex->cube;
|
||||
regcount = 10;
|
||||
reg[4] = osConvertVirtToPhys(cube->data[0]) >> 3;
|
||||
for (i = 1; i < 6; i ++)
|
||||
reg[4+i] = (osConvertVirtToPhys(cube->data[i]) >> 3) & 0x3FFFFF;
|
||||
}
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT0_BORDER_COLOR, reg, regcount);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, tex->fmt);
|
||||
break;
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT1_BORDER_COLOR, reg, 5);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, tex->fmt);
|
||||
break;
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT2_BORDER_COLOR, reg, 5);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, tex->fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user