mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-30 23:44:28 -04:00
9649319ec4
* Reorganize files into libs/{dolphin,JSystem,PowerPC_EABI_Support,revolution,TRK_MINNOW_DOLPHIN}
* Update configure.py and project.py for new libs structure
* Refactor `#include <dolphin/x.h>` -> `<x.h>`
* Remove `__REVOLUTION_SDK__` forwards from dolphin
* Fix dolphin/ references in revolution
* Wrap `#include <dolphin.h>` in `!__REVOLUTION_SDK__`
* Always build TRK against dolphin headers
* Resolve revolution SDK header resolution issues
1316 lines
42 KiB
C
1316 lines
42 KiB
C
#include <revolution/gx.h>
|
|
#include <revolution/os.h>
|
|
#include <cstring>
|
|
|
|
#include "__gx.h"
|
|
|
|
// GXTexObj internal data
|
|
typedef struct __GXTexObjInt_struct {
|
|
u32 mode0;
|
|
u32 mode1;
|
|
u32 image0;
|
|
u32 image3;
|
|
void* userData;
|
|
GXTexFmt fmt;
|
|
u32 tlutName;
|
|
u16 loadCnt;
|
|
u8 loadFmt;
|
|
u8 flags;
|
|
} __GXTexObjInt;
|
|
|
|
// GXTexRegion internal data
|
|
typedef struct __GXTexRegionInt_struct {
|
|
u32 image1;
|
|
u32 image2;
|
|
u16 sizeEven;
|
|
u16 sizeOdd;
|
|
u8 is32bMipmap;
|
|
u8 isCached;
|
|
} __GXTexRegionInt;
|
|
|
|
// GXTlutObj internal data
|
|
typedef struct __GXTlutObjInt_struct {
|
|
u32 tlut;
|
|
u32 loadTlut0;
|
|
u16 numEntries;
|
|
} __GXTlutObjInt;
|
|
|
|
// GXTlutRegion internal data
|
|
typedef struct __GXTlutRegionInt_struct {
|
|
u32 loadTlut1;
|
|
__GXTlutObjInt tlutObj;
|
|
} __GXTlutRegionInt;
|
|
|
|
u8 GXTexMode0Ids[8] = { 0x80, 0x81, 0x82, 0x83, 0xA0, 0xA1, 0xA2, 0xA3 };
|
|
u8 GXTexMode1Ids[8] = { 0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7 };
|
|
u8 GXTexImage0Ids[8] = { 0x88, 0x89, 0x8A, 0x8B, 0xA8, 0xA9, 0xAA, 0xAB };
|
|
u8 GXTexImage1Ids[8] = { 0x8C, 0x8D, 0x8E, 0x8F, 0xAC, 0xAD, 0xAE, 0xAF };
|
|
u8 GXTexImage2Ids[8] = { 0x90, 0x91, 0x92, 0x93, 0xB0, 0xB1, 0xB2, 0xB3 };
|
|
u8 GXTexImage3Ids[8] = { 0x94, 0x95, 0x96, 0x97, 0xB4, 0xB5, 0xB6, 0xB7 };
|
|
u8 GXTexTlutIds[8] = { 0x98, 0x99, 0x9A, 0x9B, 0xB8, 0xB9, 0xBA, 0xBB };
|
|
static u8 GX2HWFiltConv[6] = { 0x00, 0x04, 0x01, 0x05, 0x02, 0x06 };
|
|
static u8 HW2GXFiltConv[8] = { 0x00, 0x02, 0x04, 0x00, 0x01, 0x03, 0x05, 0x00 };
|
|
|
|
static void __GXGetTexTileShift(GXTexFmt fmt, u32* rowTileS, u32* colTileS) {
|
|
switch (fmt) {
|
|
case GX_TF_I4:
|
|
case 0x8:
|
|
case GX_TF_CMPR:
|
|
case GX_CTF_R4:
|
|
case GX_CTF_Z4:
|
|
*rowTileS = 3;
|
|
*colTileS = 3;
|
|
break;
|
|
case GX_TF_I8:
|
|
case GX_TF_IA4:
|
|
case 0x9:
|
|
case GX_TF_Z8:
|
|
case GX_CTF_RA4:
|
|
case GX_TF_A8:
|
|
case GX_CTF_R8:
|
|
case GX_CTF_G8:
|
|
case GX_CTF_B8:
|
|
case GX_CTF_Z8M:
|
|
case GX_CTF_Z8L:
|
|
*rowTileS = 3;
|
|
*colTileS = 2;
|
|
break;
|
|
case GX_TF_IA8:
|
|
case GX_TF_RGB565:
|
|
case GX_TF_RGB5A3:
|
|
case GX_TF_RGBA8:
|
|
case 0xA:
|
|
case GX_TF_Z16:
|
|
case GX_TF_Z24X8:
|
|
case GX_CTF_RA8:
|
|
case GX_CTF_RG8:
|
|
case GX_CTF_GB8:
|
|
case GX_CTF_Z16L:
|
|
*rowTileS = 2;
|
|
*colTileS = 2;
|
|
break;
|
|
default:
|
|
*rowTileS = *colTileS = 0;
|
|
ASSERTMSGLINEV(447, 0, "%s: invalid texture format", "GX");
|
|
break;
|
|
}
|
|
}
|
|
|
|
u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod) {
|
|
u32 tileShiftX;
|
|
u32 tileShiftY;
|
|
u32 tileBytes;
|
|
u32 bufferSize;
|
|
u32 nx;
|
|
u32 ny;
|
|
u32 level;
|
|
|
|
ASSERTMSGLINEV(463, width <= 1024, "%s: width too large", "GXGetTexBufferSize");
|
|
ASSERTMSGLINEV(464, height <= 1024, "%s: height too large", "GXGetTexBufferSize");
|
|
|
|
__GXGetTexTileShift(format, &tileShiftX, &tileShiftY);
|
|
if (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) {
|
|
tileBytes = 64;
|
|
} else {
|
|
tileBytes = 32;
|
|
}
|
|
|
|
if (mipmap == GX_TRUE) {
|
|
nx = 1 << (31 - __cntlzw(width));
|
|
ASSERTMSGLINEV(482, width == nx, "%s: width must be a power of 2", "GXGetTexBufferSize");
|
|
ny = 1 << (31 - __cntlzw(height));
|
|
ASSERTMSGLINEV(485, height == ny, "%s: height must be a power of 2", "GXGetTexBufferSize");
|
|
|
|
bufferSize = 0;
|
|
for (level = 0; level < max_lod; level++) {
|
|
nx = (width + (1 << tileShiftX) - 1) >> tileShiftX;
|
|
ny = (height + (1 << tileShiftY) - 1) >> tileShiftY;
|
|
bufferSize += tileBytes * (nx * ny);
|
|
if (width == 1 && height == 1) {
|
|
break;
|
|
}
|
|
width = (width > 1) ? width >> 1 : 1;
|
|
height = (height > 1) ? height >> 1 : 1;
|
|
}
|
|
} else {
|
|
nx = (width + (1 << tileShiftX) - 1) >> tileShiftX;
|
|
ny = (height + (1 << tileShiftY) - 1) >> tileShiftY;
|
|
bufferSize = nx * ny * tileBytes;
|
|
}
|
|
|
|
return bufferSize;
|
|
}
|
|
|
|
void __GetImageTileCount(GXTexFmt fmt, u16 wd, u16 ht, u32* rowTiles, u32* colTiles, u32* cmpTiles) {
|
|
u32 texRowShift;
|
|
u32 texColShift;
|
|
|
|
__GXGetTexTileShift(fmt, &texRowShift, &texColShift);
|
|
if (wd == 0) {
|
|
wd = 1;
|
|
}
|
|
if (ht == 0) {
|
|
ht = 1;
|
|
}
|
|
*rowTiles = (wd + (1 << texRowShift) - 1) >> texRowShift;
|
|
*colTiles = (ht + (1 << texColShift) - 1) >> texColShift;
|
|
*cmpTiles = (fmt == GX_TF_RGBA8 || fmt == GX_TF_Z24X8) ? 2 : 1;
|
|
}
|
|
|
|
#define SOME_SET_REG_MACRO(reg, size, shift, val) \
|
|
do { \
|
|
(reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \
|
|
} while (0);
|
|
|
|
void GXInitTexObj(GXTexObj* obj, void* image_ptr, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, GXBool mipmap) {
|
|
u32 imageBase;
|
|
u32 maxLOD;
|
|
u16 rowT;
|
|
u16 colT;
|
|
u32 rowC;
|
|
u32 colC;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(567, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(569, "GXInitTexObj");
|
|
ASSERTMSGLINEV(570, width <= 1024, "%s: width too large", "GXInitTexObj");
|
|
ASSERTMSGLINEV(571, height <= 1024, "%s: height too large", "GXInitTexObj");
|
|
ASSERTMSGLINEV(573, !(format & _GX_TF_CTF), "%s: invalid texture format", "GXInitTexObj");
|
|
|
|
#if DEBUG
|
|
if (wrap_s != GX_CLAMP || mipmap) {
|
|
u32 mask = 1 << (31 - __cntlzw(width));
|
|
ASSERTMSGLINEV(583, width == mask, "%s: width must be a power of 2", "GXInitTexObj");
|
|
}
|
|
if (wrap_t != GX_CLAMP || mipmap) {
|
|
u32 mask = 1 << (31 - __cntlzw(height));
|
|
ASSERTMSGLINEV(588, height == mask, "%s: height must be a power of 2", "GXInitTexObj");
|
|
}
|
|
#endif
|
|
|
|
memset(t, 0, 0x20);
|
|
SET_REG_FIELD(602, t->mode0, 2, 0, wrap_s);
|
|
SET_REG_FIELD(603, t->mode0, 2, 2, wrap_t);
|
|
SET_REG_FIELD(604, t->mode0, 1, 4, 1);
|
|
|
|
if (mipmap) {
|
|
u8 lmax;
|
|
t->flags |= 1;
|
|
|
|
if (format == 8 || format == 9 || format == 10) {
|
|
SOME_SET_REG_MACRO(t->mode0, 3, 5, 5);
|
|
} else {
|
|
SOME_SET_REG_MACRO(t->mode0, 3, 5, 6);
|
|
}
|
|
|
|
|
|
if (width > height) {
|
|
maxLOD = 31 - __cntlzw(width);
|
|
} else {
|
|
maxLOD = 31 - __cntlzw(height);
|
|
}
|
|
|
|
lmax = 16.0f * maxLOD;
|
|
SET_REG_FIELD(634, t->mode1, 8, 8, lmax);
|
|
} else {
|
|
SOME_SET_REG_MACRO(t->mode0, 3, 5, 4);
|
|
}
|
|
|
|
t->fmt = format;
|
|
SET_REG_FIELD(648, t->image0, 10, 0, width - 1);
|
|
SET_REG_FIELD(649, t->image0, 10, 10, height - 1);
|
|
SET_REG_FIELD(650, t->image0, 4, 20, format & 0xF);
|
|
ASSERTMSGLINEV(656, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObj", "image");
|
|
imageBase = GX_PHY_ADDR(image_ptr) >> 5;
|
|
SET_REG_FIELD(658, t->image3, 24, 0, imageBase);
|
|
|
|
switch (format & 0xF) {
|
|
case GX_TF_I4:
|
|
case 8:
|
|
t->loadFmt = 1;
|
|
rowT = 3;
|
|
colT = 3;
|
|
break;
|
|
case GX_TF_I8:
|
|
case GX_TF_IA4:
|
|
case 9:
|
|
t->loadFmt = 2;
|
|
rowT = 3;
|
|
colT = 2;
|
|
break;
|
|
case GX_TF_IA8:
|
|
case GX_TF_RGB565:
|
|
case GX_TF_RGB5A3:
|
|
case 10:
|
|
t->loadFmt = 2;
|
|
rowT = 2;
|
|
colT = 2;
|
|
break;
|
|
case GX_TF_RGBA8:
|
|
t->loadFmt = 3;
|
|
rowT = 2;
|
|
colT = 2;
|
|
break;
|
|
case GX_TF_CMPR:
|
|
t->loadFmt = 0;
|
|
rowT = 3;
|
|
colT = 3;
|
|
break;
|
|
default:
|
|
ASSERTMSGLINEV(701, 0, "%s: invalid texture format", "GXPreLoadEntireTexture");
|
|
t->loadFmt = 2;
|
|
rowT = 2;
|
|
colT = 2;
|
|
break;
|
|
}
|
|
|
|
rowC = (width + (1 << rowT) - 1) >> rowT;
|
|
colC = (height + (1 << colT) - 1) >> colT;
|
|
t->loadCnt = (rowC * colC) & 0x7FFF;
|
|
t->flags |= 2;
|
|
}
|
|
|
|
void GXInitTexObjCI(GXTexObj* obj, void* image_ptr, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, GXBool mipmap, u32 tlut_name) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(739, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(741, "GXInitTexObjCI");
|
|
GXInitTexObj(obj, image_ptr, width, height, format, wrap_s, wrap_t, mipmap);
|
|
t->flags &= 0xFFFFFFFD;
|
|
t->tlutName = tlut_name;
|
|
}
|
|
|
|
void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt, f32 min_lod, f32 max_lod, f32 lod_bias, u8 bias_clamp, u8 do_edge_lod, GXAnisotropy max_aniso) {
|
|
u8 lbias;
|
|
u8 lmin;
|
|
u8 lmax;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(778, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(780, "GXInitTexObjLOD");
|
|
|
|
if (lod_bias < -4.0f) {
|
|
lod_bias = -4.0f;
|
|
} else if (lod_bias >= 4.0f) {
|
|
lod_bias = 3.99f;
|
|
}
|
|
|
|
lbias = (u8)(32.0f * lod_bias) & 0xFF;
|
|
SET_REG_FIELD(790, t->mode0, 8, 9, lbias);
|
|
ASSERTMSG1LINE(793, (u32)mag_filt <= 1, "%s: invalid mag_filt value", "GXInitTexObjLOD");
|
|
SET_REG_FIELD(794, t->mode0, 1, 4, (mag_filt == GX_LINEAR) ? 1 : 0);
|
|
ASSERTMSG1LINE(797, (u32)min_filt <= 5, "%s: invalid min_filt value", "GXInitTexObjLOD");
|
|
SET_REG_FIELD(798, t->mode0, 3, 5, GX2HWFiltConv[min_filt]);
|
|
SET_REG_FIELD(800, t->mode0, 1, 8, do_edge_lod ? 0 : 1);
|
|
SET_REG_FIELD(801, t->mode0, 1, 17, 0);
|
|
SET_REG_FIELD(801, t->mode0, 1, 18, 0);
|
|
SET_REG_FIELD(803, t->mode0, 2, 19, max_aniso);
|
|
SET_REG_FIELD(804, t->mode0, 1, 21, bias_clamp);
|
|
|
|
if (min_lod < 0.0f) {
|
|
min_lod = 0.0f;
|
|
} else if (min_lod > 10.0f) {
|
|
min_lod = 10.0f;
|
|
}
|
|
lmin = 16.0f * min_lod;
|
|
if (max_lod < 0.0f) {
|
|
max_lod = 0.0f;
|
|
} else if (max_lod > 10.0f) {
|
|
max_lod = 10.0f;
|
|
}
|
|
lmax = 16.0f * max_lod;
|
|
SET_REG_FIELD(818, t->mode1, 8, 0, lmin);
|
|
SET_REG_FIELD(819, t->mode1, 8, 8, lmax);
|
|
}
|
|
|
|
void GXInitTexObjData(GXTexObj* obj, void* image_ptr) {
|
|
u32 imageBase;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(835, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(837, "GXInitTexObjData");
|
|
ASSERTMSGLINEV(840, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObjData", "image");
|
|
imageBase = ((u32)image_ptr >> 5) & 0x01FFFFFF;
|
|
SET_REG_FIELD(843, t->image3, 21, 0, imageBase);
|
|
}
|
|
|
|
void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode sm, GXTexWrapMode tm) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(860, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(862, "GXInitTexObjWrapMode");
|
|
SET_REG_FIELD(864, t->mode0, 2, 0, sm);
|
|
SET_REG_FIELD(865, t->mode0, 2, 2, tm);
|
|
}
|
|
|
|
void GXInitTexObjTlut(GXTexObj* obj, u32 tlut_name) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(881, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(883, "GXInitTexObjTlut");
|
|
t->tlutName = tlut_name;
|
|
}
|
|
|
|
void GXInitTexObjFilter(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(902, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(904, "GXInitTexObjFilter");
|
|
|
|
ASSERTMSG1LINE(907, (u32)mag_filt <= 1, "%s: invalid mag_filt value", "GXInitTexObjFilter");
|
|
SET_REG_FIELD(908, t->mode0, 1, 4, mag_filt == 1 ? 1 : 0);
|
|
|
|
ASSERTMSG1LINE(911, (u32)min_filt <= 5, "%s: invalid min_filt value", "GXInitTexObjFilter");
|
|
SET_REG_FIELD(912, t->mode0, 3, 5, GX2HWFiltConv[min_filt]);
|
|
}
|
|
|
|
void GXInitTexObjMaxLOD(GXTexObj* obj, f32 max_lod) {
|
|
u8 lmax;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(930, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(932, "GXInitTexObjMaxLOD");
|
|
|
|
if (max_lod < 0.0f) {
|
|
max_lod = 0.0f;
|
|
} else if (max_lod > 10.0f) {
|
|
max_lod = 10.0f;
|
|
}
|
|
lmax = 16.0f * max_lod;
|
|
SET_REG_FIELD(938, t->mode1, 8, 8, lmax);
|
|
}
|
|
|
|
void GXInitTexObjMinLOD(GXTexObj* obj, f32 min_lod) {
|
|
u8 lmin;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(956, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(958, "GXInitTexObjMinLOD");
|
|
|
|
if (min_lod < 0.0f) {
|
|
min_lod = 0.0f;
|
|
} else if (min_lod > 10.0f) {
|
|
min_lod = 10.0f;
|
|
}
|
|
lmin = 16.0f * min_lod;
|
|
SET_REG_FIELD(964, t->mode1, 8, 0, lmin);
|
|
}
|
|
|
|
void GXInitTexObjLODBias(GXTexObj* obj, f32 lod_bias) {
|
|
u8 lbias;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(982, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(984, "GXInitTexObjLODBias");
|
|
|
|
if (lod_bias < -4.0f) {
|
|
lod_bias = -4.0f;
|
|
} else if (lod_bias >= 4.0f) {
|
|
lod_bias = 3.99f;
|
|
}
|
|
lbias = 32.0f * lod_bias;
|
|
SET_REG_FIELD(991, t->mode0, 8, 9, lbias);
|
|
}
|
|
|
|
void GXInitTexObjBiasClamp(GXTexObj* obj, u8 bias_clamp) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(1007, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(1009, "GXInitTexObjBiasClamp");
|
|
|
|
SET_REG_FIELD(1011, t->mode0, 1, 21, bias_clamp);
|
|
}
|
|
|
|
void GXInitTexObjEdgeLOD(GXTexObj* obj, u8 do_edge_lod) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(1027, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(1029, "GXInitTexObjEdgeLOD");
|
|
|
|
SET_REG_FIELD(1031, t->mode0, 1, 8, do_edge_lod ? 0 : 1);
|
|
}
|
|
|
|
void GXInitTexObjMaxAniso(GXTexObj* obj, GXAnisotropy max_aniso) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(1047, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(1049, "GXInitTexObjMaxAniso");
|
|
|
|
SET_REG_FIELD(1051, t->mode0, 2, 19, max_aniso);
|
|
}
|
|
|
|
void GXInitTexObjUserData(GXTexObj* obj, void* user_data) {
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
|
|
ASSERTMSGLINE(1068, obj, "Texture Object Pointer is null");
|
|
CHECK_GXBEGIN(1069, "GXInitTexObjUserData");
|
|
t->userData = user_data;
|
|
}
|
|
|
|
void* GXGetTexObjUserData(const GXTexObj* obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)obj;
|
|
|
|
ASSERTMSGLINE(1075, obj, "Texture Object Pointer is null");
|
|
return t->userData;
|
|
}
|
|
|
|
void GXGetTexObjAll(const GXTexObj* obj, void** image_ptr, u16* width, u16* height, GXTexFmt* format, GXTexWrapMode* wrap_s, GXTexWrapMode* wrap_t, u8* mipmap) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)obj;
|
|
|
|
ASSERTMSGLINE(1095, obj, "Texture Object Pointer is null");
|
|
*image_ptr = (void *)(GET_REG_FIELD(t->image3, 21, 0) << 5);
|
|
*width = (u32)GET_REG_FIELD(t->image0, 10, 0) + 1;
|
|
*height = (u32)GET_REG_FIELD(t->image0, 10, 10) + 1;
|
|
*format = t->fmt;
|
|
*wrap_s = GET_REG_FIELD(t->mode0, 2, 0);
|
|
*wrap_t = GET_REG_FIELD(t->mode0, 2, 2);
|
|
*mipmap = (t->flags & 1) == 1;
|
|
}
|
|
|
|
void* GXGetTexObjData(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1108, to, "Texture Object Pointer is null");
|
|
return (void*)(GET_REG_FIELD(t->image3, 21, 0) << 5);
|
|
}
|
|
|
|
u16 GXGetTexObjWidth(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1116, to, "Texture Object Pointer is null");
|
|
return (u32)GET_REG_FIELD(t->image0, 10, 0) + 1;
|
|
}
|
|
|
|
u16 GXGetTexObjHeight(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1122, to, "Texture Object Pointer is null");
|
|
return (u32)GET_REG_FIELD(t->image0, 10, 10) + 1;
|
|
}
|
|
|
|
GXTexFmt GXGetTexObjFmt(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1128, to, "Texture Object Pointer is null");
|
|
return t->fmt;
|
|
}
|
|
|
|
GXTexWrapMode GXGetTexObjWrapS(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1134, to, "Texture Object Pointer is null");
|
|
return GET_REG_FIELD(t->mode0, 2, 0);
|
|
}
|
|
|
|
GXTexWrapMode GXGetTexObjWrapT(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1140, to, "Texture Object Pointer is null");
|
|
return GET_REG_FIELD(t->mode0, 2, 2);
|
|
}
|
|
|
|
GXBool GXGetTexObjMipMap(const GXTexObj* to) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)to;
|
|
|
|
ASSERTMSGLINE(1146, to, "Texture Object Pointer is null");
|
|
return (t->flags & 1) == 1;
|
|
}
|
|
|
|
void GXGetTexObjLODAll(const GXTexObj* tex_obj, GXTexFilter* min_filt, GXTexFilter* mag_filt, f32* min_lod, f32* max_lod, f32* lod_bias, u8* bias_clamp, u8* do_edge_lod, GXAnisotropy* max_aniso) {
|
|
s16 tmp;
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1166, tex_obj, "Texture Object Pointer is null");
|
|
*min_filt = HW2GXFiltConv[GET_REG_FIELD(t->mode0, 3, 5)];
|
|
*mag_filt = GET_REG_FIELD(t->mode0, 1, 4);
|
|
*min_lod = (u8)t->mode1 / 16.0f;
|
|
*max_lod = (u32)GET_REG_FIELD(t->mode1, 8, 8) / 16.0f;
|
|
tmp = (s32)GET_REG_FIELD(t->mode0, 8, 9);
|
|
*lod_bias = (s8)tmp / 32.0f;
|
|
*bias_clamp = (u32)GET_REG_FIELD(t->mode0, 1, 21);
|
|
*do_edge_lod = !GET_REG_FIELD(t->mode0, 1, 8);
|
|
*max_aniso = GET_REG_FIELD(t->mode0, 2, 19);
|
|
}
|
|
|
|
GXTexFilter GXGetTexObjMinFilt(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1182, tex_obj, "Texture Object Pointer is null");
|
|
return HW2GXFiltConv[GET_REG_FIELD(t->mode0, 3, 5)];
|
|
}
|
|
|
|
GXTexFilter GXGetTexObjMagFilt(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1189, tex_obj, "Texture Object Pointer is null");
|
|
return GET_REG_FIELD(t->mode0, 1, 4);
|
|
}
|
|
|
|
f32 GXGetTexObjMinLOD(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1195, tex_obj, "Texture Object Pointer is null");
|
|
return (u32)GET_REG_FIELD(t->mode1, 8, 0) / 16.0f;
|
|
}
|
|
|
|
f32 GXGetTexObjMaxLOD(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1201, tex_obj, "Texture Object Pointer is null");
|
|
return (u32)GET_REG_FIELD(t->mode1, 8, 8) / 16.0f;
|
|
}
|
|
|
|
f32 GXGetTexObjLODBias(const GXTexObj* tex_obj) {
|
|
s16 tmp;
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1208, tex_obj, "Texture Object Pointer is null");
|
|
tmp = (s32)GET_REG_FIELD(t->mode0, 8, 9);
|
|
return (s8)tmp / 32.0f;
|
|
}
|
|
|
|
GXBool GXGetTexObjBiasClamp(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1215, tex_obj, "Texture Object Pointer is null");
|
|
return (u32)GET_REG_FIELD(t->mode0, 1, 21);
|
|
}
|
|
|
|
GXBool GXGetTexObjEdgeLOD(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1221, tex_obj, "Texture Object Pointer is null");
|
|
return !GET_REG_FIELD(t->mode0, 1, 8);
|
|
}
|
|
|
|
GXAnisotropy GXGetTexObjMaxAniso(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1227, tex_obj, "Texture Object Pointer is null");
|
|
return GET_REG_FIELD(t->mode0, 2, 19);
|
|
}
|
|
|
|
u32 GXGetTexObjTlut(const GXTexObj* tex_obj) {
|
|
const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj;
|
|
|
|
ASSERTMSGLINE(1235, tex_obj, "Texture Object Pointer is null");
|
|
return t->tlutName;
|
|
}
|
|
|
|
void GXLoadTexObjPreLoaded(GXTexObj* obj, GXTexRegion* region, GXTexMapID id) {
|
|
__GXTlutRegionInt* tlr;
|
|
u32 m0;
|
|
u32 m1;
|
|
u32 img0;
|
|
u32 img1;
|
|
u32 img2;
|
|
u32 img3;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)obj;
|
|
__GXTexRegionInt* r = (__GXTexRegionInt *)region;
|
|
|
|
ASSERTMSGLINE(1259, obj, "Texture Object Pointer is null");
|
|
ASSERTMSGLINE(1259, region, "TexRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1261, "GXLoadTexObjPreLoaded");
|
|
ASSERTMSGLINEV(1262, id < GX_MAX_TEXMAP, "%s: invalid texture map ID", "GXLoadTexObj");
|
|
|
|
m0 = t->mode0;
|
|
m1 = t->mode1;
|
|
img0 = t->image0;
|
|
img1 = r->image1;
|
|
img2 = r->image2;
|
|
img3 = t->image3;
|
|
|
|
SET_REG_FIELD(1273, t->mode0, 8, 24, GXTexMode0Ids[id]);
|
|
SET_REG_FIELD(1274, t->mode1, 8, 24, GXTexMode1Ids[id]);
|
|
SET_REG_FIELD(1275, t->image0, 8, 24, GXTexImage0Ids[id]);
|
|
SET_REG_FIELD(1276, r->image1, 8, 24, GXTexImage1Ids[id]);
|
|
SET_REG_FIELD(1277, r->image2, 8, 24, GXTexImage2Ids[id]);
|
|
SET_REG_FIELD(1278, t->image3, 8, 24, GXTexImage3Ids[id]);
|
|
|
|
GX_WRITE_RAS_REG(t->mode0);
|
|
GX_WRITE_RAS_REG(t->mode1);
|
|
GX_WRITE_RAS_REG(t->image0);
|
|
GX_WRITE_RAS_REG(r->image1);
|
|
GX_WRITE_RAS_REG(r->image2);
|
|
GX_WRITE_RAS_REG(t->image3);
|
|
|
|
if (!(t->flags & 2)) {
|
|
ASSERTMSGLINEV(1289, __GXData->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj/PreLoaded");
|
|
tlr = (__GXTlutRegionInt*)__GXData->tlutRegionCallback(t->tlutName);
|
|
ASSERTMSGLINEV(1291, tlr, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTexObj/PreLoaded");
|
|
|
|
SET_REG_FIELD(1293, tlr->tlutObj.tlut, 8, 24, GXTexTlutIds[id]);
|
|
GX_WRITE_RAS_REG(tlr->tlutObj.tlut);
|
|
}
|
|
|
|
__GXData->tImage0[id] = t->image0;
|
|
__GXData->tMode0[id] = t->mode0;
|
|
__GXData->dirtyState |= 1;
|
|
__GXData->bpSentNot = 0;
|
|
}
|
|
|
|
void GXLoadTexObj(GXTexObj* obj, GXTexMapID id) {
|
|
GXTexRegion* r;
|
|
|
|
CHECK_GXBEGIN(1320, "GXLoadTexObj");
|
|
ASSERTMSGLINEV(1321, id < 8, "%s: invalid texture map ID", "GXLoadTexObj");
|
|
ASSERTMSGLINEV(1326, __GXData->texRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj");
|
|
r = __GXData->texRegionCallback(obj, id);
|
|
ASSERTMSGLINEV(1328, r, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTexObj");
|
|
GXLoadTexObjPreLoaded(obj, r, id);
|
|
}
|
|
|
|
void GXInitTlutObj(GXTlutObj* tlut_obj, void* lut, GXTlutFmt fmt, u16 n_entries) {
|
|
__GXTlutObjInt* t = (__GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1352, tlut_obj, "TLut Object Pointer is null");
|
|
CHECK_GXBEGIN(1353, "GXInitTlutObj");
|
|
ASSERTMSGLINEV(1356, n_entries <= 0x4000, "%s: number of entries exceeds maximum", "GXInitTlutObj");
|
|
ASSERTMSGLINEV(1358, ((u32)lut & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTlutObj", "Tlut");
|
|
t->tlut = 0;
|
|
SET_REG_FIELD(1361, t->tlut, 2, 10, fmt);
|
|
SET_REG_FIELD(1362, t->loadTlut0, 24, 0, GX_PHY_ADDR(lut) >> 5);
|
|
SET_REG_FIELD(1363, t->loadTlut0, 8, 24, 0x64);
|
|
t->numEntries = n_entries;
|
|
}
|
|
|
|
void GXGetTlutObjAll(const GXTlutObj* tlut_obj, void **data, GXTlutFmt* format, u16* numEntries) {
|
|
const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1382, tlut_obj, "TLut Object Pointer is null");
|
|
*data = (void *)(GET_REG_FIELD(t->loadTlut0, 21, 0) << 5);
|
|
*format = GET_REG_FIELD(t->tlut, 2, 10);
|
|
*numEntries = t->numEntries;
|
|
}
|
|
|
|
void* GXGetTlutObjData(const GXTlutObj* tlut_obj) {
|
|
const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1391, tlut_obj, "TLut Object Pointer is null");
|
|
return (void *)(GET_REG_FIELD(t->loadTlut0, 21, 0) << 5);
|
|
}
|
|
|
|
GXTlutFmt GXGetTlutObjFmt(const GXTlutObj* tlut_obj) {
|
|
const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1398, tlut_obj, "TLut Object Pointer is null");
|
|
return GET_REG_FIELD(t->tlut, 2, 10);
|
|
}
|
|
|
|
u16 GXGetTlutObjNumEntries(const GXTlutObj* tlut_obj) {
|
|
const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1405, tlut_obj, "TLut Object Pointer is null");
|
|
return t->numEntries;
|
|
}
|
|
|
|
void GXLoadTlut(GXTlutObj* tlut_obj, u32 tlut_name) {
|
|
__GXTlutRegionInt* r;
|
|
u32 tlut_offset;
|
|
__GXTlutObjInt* t = (__GXTlutObjInt *)tlut_obj;
|
|
|
|
ASSERTMSGLINE(1434, tlut_obj, "TLut Object Pointer is null");
|
|
CHECK_GXBEGIN(1436, "GXLoadTlut");
|
|
ASSERTMSGLINEV(1437, __GXData->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTlut");
|
|
r = (__GXTlutRegionInt *)__GXData->tlutRegionCallback(tlut_name);
|
|
ASSERTMSGLINEV(1439, r, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTlut");
|
|
|
|
__GXFlushTextureState();
|
|
GX_WRITE_RAS_REG(t->loadTlut0);
|
|
GX_WRITE_RAS_REG(r->loadTlut1);
|
|
__GXFlushTextureState();
|
|
tlut_offset = r->loadTlut1 & 0x3FF;
|
|
SET_REG_FIELD(1455, t->tlut, 10, 0, tlut_offset);
|
|
r->tlutObj = *t;
|
|
}
|
|
|
|
void GXInitTexCacheRegion(GXTexRegion* region, u8 is_32b_mipmap, u32 tmem_even, GXTexCacheSize size_even, u32 tmem_odd, GXTexCacheSize size_odd) {
|
|
u32 WidthExp2;
|
|
__GXTexRegionInt* t = (__GXTexRegionInt*)region;
|
|
|
|
ASSERTMSGLINE(1486, region, "TexRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1488, "GXInitTexCacheRegion");
|
|
ASSERTMSGLINEV(1490, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexCacheRegion", "tmem even");
|
|
ASSERTMSGLINEV(1492, (tmem_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexCacheRegion", "tmem odd");
|
|
|
|
switch (size_even) {
|
|
case GX_TEXCACHE_32K:
|
|
WidthExp2 = 3;
|
|
break;
|
|
case GX_TEXCACHE_128K:
|
|
WidthExp2 = 4;
|
|
break;
|
|
case GX_TEXCACHE_512K:
|
|
WidthExp2 = 5;
|
|
break;
|
|
default:
|
|
ASSERTMSGLINEV(1500, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem even");
|
|
break;
|
|
}
|
|
|
|
t->image1 = 0;
|
|
SET_REG_FIELD(1505, t->image1, 15, 0, tmem_even >> 5);
|
|
SET_REG_FIELD(1506, t->image1, 3, 15, WidthExp2);
|
|
SET_REG_FIELD(1507, t->image1, 3, 18, WidthExp2);
|
|
SET_REG_FIELD(1508, t->image1, 1, 21, 0);
|
|
|
|
switch (size_odd) {
|
|
case GX_TEXCACHE_32K:
|
|
WidthExp2 = 3;
|
|
break;
|
|
case GX_TEXCACHE_128K:
|
|
WidthExp2 = 4;
|
|
break;
|
|
case GX_TEXCACHE_512K:
|
|
WidthExp2 = 5;
|
|
break;
|
|
case GX_TEXCACHE_NONE:
|
|
WidthExp2 = 0;
|
|
break;
|
|
default:
|
|
ASSERTMSGLINEV(1516, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem odd");
|
|
break;
|
|
}
|
|
|
|
t->image2 = 0;
|
|
SET_REG_FIELD(1521, t->image2, 15, 0, tmem_odd >> 5);
|
|
SET_REG_FIELD(1522, t->image2, 3, 15, WidthExp2);
|
|
SET_REG_FIELD(1523, t->image2, 3, 18, WidthExp2);
|
|
t->is32bMipmap = (u8)is_32b_mipmap;
|
|
t->isCached = 1;
|
|
}
|
|
|
|
void GXInitTexPreLoadRegion(GXTexRegion* region, u32 tmem_even, u32 size_even, u32 tmem_odd, u32 size_odd) {
|
|
__GXTexRegionInt* t = (__GXTexRegionInt *)region;
|
|
|
|
ASSERTMSGLINE(1550, region, "TexRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1552, "GXInitTexPreLoadRegion");
|
|
ASSERTMSGLINEV(1554, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem even");
|
|
ASSERTMSGLINEV(1556, (tmem_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem odd");
|
|
ASSERTMSGLINEV(1558, (size_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size even");
|
|
ASSERTMSGLINEV(1560, (size_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size odd");
|
|
|
|
t->image1 = 0;
|
|
SET_REG_FIELD(1564, t->image1, 15, 0, tmem_even >> 5);
|
|
SET_REG_FIELD(1565, t->image1, 3, 15, 0);
|
|
SET_REG_FIELD(1566, t->image1, 3, 18, 0);
|
|
SET_REG_FIELD(1567, t->image1, 1, 21, 1);
|
|
|
|
t->image2 = 0;
|
|
SET_REG_FIELD(1570, t->image2, 15, 0, tmem_odd >> 5);
|
|
SET_REG_FIELD(1571, t->image2, 3, 15, 0);
|
|
SET_REG_FIELD(1572, t->image2, 3, 18, 0);
|
|
t->is32bMipmap = 0;
|
|
t->isCached = 0;
|
|
t->sizeEven = (u16)(size_even >> 5);
|
|
t->sizeOdd = (u16)(size_odd >> 5);
|
|
}
|
|
|
|
void GXGetTexRegionAll(const GXTexRegion* region, u8* is_cached, u8* is_32b_mipmap, u32* tmem_even, u32* size_even, u32* tmem_odd, u32* size_odd) {
|
|
const __GXTexRegionInt* t = (const __GXTexRegionInt *)region;
|
|
|
|
ASSERTMSGLINE(1601, region, "TexRegion Object Pointer is null");
|
|
*tmem_even = GET_REG_FIELD(t->image1, 15, 0) << 5;
|
|
*tmem_odd = GET_REG_FIELD(t->image2, 15, 0) << 5;
|
|
if (t->isCached) {
|
|
switch (GET_REG_FIELD(t->image1, 3, 15)) {
|
|
case 3:
|
|
*size_even = 0x8000;
|
|
break;
|
|
case 4:
|
|
*size_even = 0x20000;
|
|
break;
|
|
case 5:
|
|
*size_even = 0x80000;
|
|
break;
|
|
default:
|
|
*size_even = 0;
|
|
break;
|
|
}
|
|
|
|
switch (GET_REG_FIELD(t->image2, 3, 15)) {
|
|
case 3:
|
|
*size_odd = 0x8000;
|
|
break;
|
|
case 4:
|
|
*size_odd = 0x20000;
|
|
break;
|
|
case 5:
|
|
*size_odd = 0x80000;
|
|
break;
|
|
default:
|
|
*size_odd = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
*size_even = t->sizeEven << 5;
|
|
*size_odd = t->sizeOdd << 5;
|
|
}
|
|
|
|
*is_32b_mipmap = t->is32bMipmap;
|
|
*is_cached = t->isCached;
|
|
}
|
|
|
|
void GXInitTlutRegion(GXTlutRegion* region, u32 tmem_addr, GXTlutSize tlut_size) {
|
|
__GXTlutRegionInt* t = (__GXTlutRegionInt *)region;
|
|
|
|
ASSERTMSGLINE(1654, region, "TLutRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1656, "GXInitTlutRegion");
|
|
ASSERTMSGLINEV(1657, (tmem_addr & 0x1FF) == 0, "%s: tmem pointer is not aligned to 512B", "GXInitTlutRegion");
|
|
ASSERTMSGLINEV(1658, tlut_size <= 0x400, "%s: tlut size exceeds 16K", "GXInitTlutRegion");
|
|
t->loadTlut1 = 0;
|
|
tmem_addr -= 0x80000;
|
|
SET_REG_FIELD(1662, t->loadTlut1, 10, 0, tmem_addr >> 9);
|
|
SET_REG_FIELD(1663, t->loadTlut1, 11, 10, tlut_size);
|
|
SET_REG_FIELD(1664, t->loadTlut1, 8, 24, 0x65);
|
|
}
|
|
|
|
void GXGetTlutRegionAll(const GXTlutRegion* region, u32* tmem_addr, GXTlutSize* tlut_size) {
|
|
const __GXTlutRegionInt* t = (const __GXTlutRegionInt *)region;
|
|
|
|
ASSERTMSGLINE(1682, region, "TLutRegion Object Pointer is null");
|
|
*tmem_addr = (GET_REG_FIELD(t->loadTlut1, 10, 0) << 9) + 0x80000;
|
|
*tlut_size = GET_REG_FIELD(t->loadTlut1, 11, 10);
|
|
}
|
|
|
|
void GXInvalidateTexRegion(GXTexRegion* region) {
|
|
s32 wle;
|
|
s32 hle;
|
|
s32 wlo;
|
|
s32 hlo;
|
|
s32 count;
|
|
u32 reg0;
|
|
u32 reg1;
|
|
__GXTexRegionInt* r = (__GXTexRegionInt*)region;
|
|
|
|
ASSERTMSGLINE(1705, region, "TexRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1707, "GXInvalidateTexRegion");
|
|
|
|
wle = GET_REG_FIELD(r->image1, 3, 15) - 1;
|
|
hle = GET_REG_FIELD(r->image1, 3, 18) - 1;
|
|
wlo = GET_REG_FIELD(r->image2, 3, 15) - 1;
|
|
hlo = GET_REG_FIELD(r->image2, 3, 18) - 1;
|
|
if (wle < 0) {
|
|
wle = 0;
|
|
}
|
|
if (hle < 0) {
|
|
hle = 0;
|
|
}
|
|
if (wlo < 0) {
|
|
wlo = 0;
|
|
}
|
|
if (hlo < 0) {
|
|
hlo = 0;
|
|
}
|
|
count = wle + hle;
|
|
if (r->is32bMipmap) {
|
|
count = wlo + hlo - 2 + count;
|
|
}
|
|
|
|
reg0 = 0;
|
|
SET_REG_FIELD(1724, reg0, 9, 0, GET_REG_FIELD(r->image1, 9, 6));
|
|
SET_REG_FIELD(1725, reg0, 4, 9, count);
|
|
SET_REG_FIELD(1724, reg0, 8, 24, 0x66);
|
|
|
|
if (wlo != 0) {
|
|
count = wlo + hlo;
|
|
if (r->is32bMipmap) {
|
|
count = wle + hle - 2 + count;
|
|
}
|
|
reg1 = 0;
|
|
SET_REG_FIELD(1736, reg1, 9, 0, GET_REG_FIELD(r->image2, 9, 6));
|
|
SET_REG_FIELD(1737, reg1, 4, 9, count);
|
|
SET_REG_FIELD(1738, reg1, 8, 24, 0x66);
|
|
}
|
|
|
|
__GXFlushTextureState();
|
|
GX_WRITE_RAS_REG(reg0);
|
|
if (wlo != 0) {
|
|
GX_WRITE_RAS_REG(reg1);
|
|
}
|
|
__GXFlushTextureState();
|
|
|
|
reg0; reg1; r; // needed to match
|
|
}
|
|
|
|
void GXInvalidateTexAll(void) {
|
|
u32 reg0;
|
|
u32 reg1;
|
|
|
|
CHECK_GXBEGIN(1757, "GXInvalidateTexAll");
|
|
reg0 = 0x66001000;
|
|
reg1 = 0x66001100;
|
|
__GXFlushTextureState();
|
|
GX_WRITE_RAS_REG(reg0);
|
|
GX_WRITE_RAS_REG(reg1);
|
|
__GXFlushTextureState();
|
|
}
|
|
|
|
GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback f) {
|
|
GXTexRegionCallback oldcb = __GXData->texRegionCallback;
|
|
|
|
__GXData->texRegionCallback = f;
|
|
return oldcb;
|
|
}
|
|
|
|
GXTlutRegionCallback GXSetTlutRegionCallback(GXTlutRegionCallback f) {
|
|
GXTlutRegionCallback oldcb = __GXData->tlutRegionCallback;
|
|
|
|
__GXData->tlutRegionCallback = f;
|
|
return oldcb;
|
|
}
|
|
|
|
void GXPreLoadEntireTexture(GXTexObj* tex_obj, GXTexRegion* region) {
|
|
GXBool isMipMap;
|
|
GXBool is32bit;
|
|
u32 wd;
|
|
u32 ht;
|
|
u32 maxLevelIndex;
|
|
u32 loadImage0;
|
|
u32 loadImage1;
|
|
u32 loadImage2;
|
|
u32 loadImage3;
|
|
u32 base;
|
|
u32 tmem1;
|
|
u32 tmem2;
|
|
u32 tmemAR;
|
|
u32 tmemGB;
|
|
u32 nTiles;
|
|
#if DEBUG
|
|
u32 totalOdd;
|
|
u32 totalEven;
|
|
u32 count;
|
|
#endif
|
|
u32 rowTiles;
|
|
u32 colTiles;
|
|
u32 cmpTiles;
|
|
u32 i;
|
|
__GXTexObjInt* t = (__GXTexObjInt*)tex_obj;
|
|
__GXTexRegionInt* r = (__GXTexRegionInt*)region;
|
|
|
|
ASSERTMSGLINE(1820, tex_obj, "Texture Object Pointer is null");
|
|
ASSERTMSGLINE(1820, region, "TexRegion Object Pointer is null");
|
|
CHECK_GXBEGIN(1822, "GXPreLoadEntireTexture");
|
|
isMipMap = (t->flags & 1) == 1;
|
|
is32bit = GET_REG_FIELD(t->image0, 4, 20) == 6;
|
|
|
|
loadImage0 = 0;
|
|
SET_REG_FIELD(0, loadImage0, 8, 24, 0x60);
|
|
base = t->image3 & 0x1FFFFF;
|
|
SET_REG_FIELD(1831, loadImage0, 21, 0, base);
|
|
|
|
loadImage1 = 0;
|
|
SET_REG_FIELD(0, loadImage1, 8, 24, 0x61);
|
|
tmem1 = r->image1 & 0x7FFF;
|
|
SET_REG_FIELD(1837, loadImage1, 15, 0, tmem1);
|
|
|
|
loadImage2 = 0;
|
|
SET_REG_FIELD(0, loadImage2, 8, 24, 0x62);
|
|
tmem2 = r->image2 & 0x7FFF;
|
|
SET_REG_FIELD(1843, loadImage2, 15, 0, tmem2);
|
|
|
|
loadImage3 = 0;
|
|
SET_REG_FIELD(0, loadImage3, 8, 24, 0x63);
|
|
SET_REG_FIELD(1848, loadImage3, 15, 0, t->loadCnt);
|
|
SET_REG_FIELD(1849, loadImage3, 2, 15, t->loadFmt);
|
|
maxLevelIndex = 0;
|
|
nTiles = t->loadCnt;
|
|
|
|
if (isMipMap) {
|
|
wd = GET_REG_FIELD(t->image0, 10, 0) + 1;
|
|
ht = GET_REG_FIELD(t->image0, 10, 10) + 1;
|
|
if (wd > ht) {
|
|
maxLevelIndex = (u16)(31 - __cntlzw(wd));
|
|
} else {
|
|
maxLevelIndex = (u16)(31 - __cntlzw(ht));
|
|
}
|
|
|
|
#if DEBUG
|
|
count = nTiles;
|
|
totalOdd = totalEven = 0;
|
|
|
|
for (i = 0; i < maxLevelIndex; i++) {
|
|
if (i & 1) {
|
|
if (count == 0) {
|
|
count = 1;
|
|
}
|
|
totalOdd += count;
|
|
} else {
|
|
if (count == 0) {
|
|
count = 1;
|
|
}
|
|
totalEven += count;
|
|
}
|
|
__GetImageTileCount(t->fmt, wd >> (i + 1), ht >> (i + 1), &rowTiles, &colTiles, &cmpTiles);
|
|
count = rowTiles * colTiles;
|
|
}
|
|
#endif
|
|
} else {
|
|
#if DEBUG
|
|
totalEven = (nTiles == 0) ? 1 : nTiles;
|
|
totalOdd = totalEven;
|
|
#endif
|
|
}
|
|
|
|
#if DEBUG
|
|
if (is32bit) {
|
|
totalOdd = isMipMap ? totalOdd : 0;
|
|
totalEven = totalEven + totalOdd;
|
|
ASSERTMSGLINE(1890, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size");
|
|
ASSERTMSGLINE(1891, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size");
|
|
} else if (isMipMap != 0) {
|
|
if (r->sizeEven > r->sizeOdd) {
|
|
ASSERTMSGLINE(1896, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size");
|
|
ASSERTMSGLINE(1897, totalOdd <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size");
|
|
} else {
|
|
ASSERTMSGLINE(1900, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size");
|
|
ASSERTMSGLINE(1901, totalOdd <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size");
|
|
}
|
|
} else if (r->sizeEven > r->sizeOdd) {
|
|
ASSERTMSGLINE(1906, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size");
|
|
} else {
|
|
ASSERTMSGLINE(1908, totalOdd <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size");
|
|
}
|
|
#endif
|
|
|
|
__GXFlushTextureState();
|
|
GX_WRITE_RAS_REG(loadImage0);
|
|
GX_WRITE_RAS_REG(loadImage1);
|
|
GX_WRITE_RAS_REG(loadImage2);
|
|
GX_WRITE_RAS_REG(loadImage3);
|
|
|
|
if (maxLevelIndex != 0) {
|
|
tmemAR = tmem1;
|
|
tmemGB = tmem2;
|
|
for (i = 0; i < maxLevelIndex; i++) {
|
|
if (is32bit) {
|
|
base += nTiles * 2;
|
|
tmemAR += nTiles;
|
|
tmemGB += nTiles;
|
|
} else {
|
|
base += nTiles;
|
|
if (i & 1) {
|
|
tmemGB += nTiles;
|
|
} else {
|
|
tmemAR += nTiles;
|
|
}
|
|
}
|
|
tmem1 = (i & 1) ? tmemAR : tmemGB;
|
|
tmem2 = (i & 1) ? tmemGB : tmemAR;
|
|
__GetImageTileCount(t->fmt, (u16) (wd >> (i + 1)), (u16) (ht >> (i + 1)), &rowTiles, &colTiles, &cmpTiles);
|
|
nTiles = rowTiles * colTiles;
|
|
SET_REG_FIELD(1957, loadImage0, 21, 0, base);
|
|
SET_REG_FIELD(1958, loadImage1, 15, 0, tmem1);
|
|
SET_REG_FIELD(1959, loadImage2, 15, 0, tmem2);
|
|
SET_REG_FIELD(1960, loadImage3, 15, 0, nTiles);
|
|
GX_WRITE_RAS_REG(loadImage0);
|
|
GX_WRITE_RAS_REG(loadImage1);
|
|
GX_WRITE_RAS_REG(loadImage2);
|
|
GX_WRITE_RAS_REG(loadImage3);
|
|
}
|
|
}
|
|
__GXFlushTextureState();
|
|
|
|
// needed to match debug
|
|
maxLevelIndex; maxLevelIndex; base; base; base; tmem1; tmem1; tmem2; tmem2;
|
|
}
|
|
|
|
void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 ss, u16 ts) {
|
|
CHECK_GXBEGIN(1991, "GXSetTexCoordScaleManually");
|
|
ASSERTMSGLINEV(1993, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordScaleManually");
|
|
__GXData->tcsManEnab = (__GXData->tcsManEnab & ~(1 << coord)) | (enable << coord);
|
|
|
|
if (enable) {
|
|
SET_REG_FIELD(1999, __GXData->suTs0[coord], 16, 0, (u16)(ss - 1));
|
|
SET_REG_FIELD(2000, __GXData->suTs1[coord], 16, 0, (u16)(ts - 1));
|
|
GX_WRITE_RAS_REG(__GXData->suTs0[coord]);
|
|
GX_WRITE_RAS_REG(__GXData->suTs1[coord]);
|
|
__GXData->bpSentNot = 0;
|
|
}
|
|
}
|
|
|
|
void GXSetTexCoordCylWrap(GXTexCoordID coord, u8 s_enable, u8 t_enable) {
|
|
CHECK_GXBEGIN(2023, "GXSetTexCoordCylWrap");
|
|
ASSERTMSGLINEV(2025, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordCylWrap");
|
|
SET_REG_FIELD(2027, __GXData->suTs0[coord], 1, 17, s_enable);
|
|
SET_REG_FIELD(2028, __GXData->suTs1[coord], 1, 17, t_enable);
|
|
|
|
if (__GXData->tcsManEnab & (1 << coord)) {
|
|
GX_WRITE_RAS_REG(__GXData->suTs0[coord]);
|
|
GX_WRITE_RAS_REG(__GXData->suTs1[coord]);
|
|
__GXData->bpSentNot = 0;
|
|
}
|
|
}
|
|
|
|
void GXSetTexCoordBias(GXTexCoordID coord, u8 s_enable, u8 t_enable) {
|
|
CHECK_GXBEGIN(2054, "GXSetTexCoordBias");
|
|
ASSERTMSGLINEV(2056, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordBias");
|
|
SET_REG_FIELD(2058, __GXData->suTs0[coord], 1, 16, s_enable);
|
|
SET_REG_FIELD(2059, __GXData->suTs1[coord], 1, 16, t_enable);
|
|
|
|
if (__GXData->tcsManEnab & (1 << coord)) {
|
|
GX_WRITE_RAS_REG(__GXData->suTs0[coord]);
|
|
GX_WRITE_RAS_REG(__GXData->suTs1[coord]);
|
|
__GXData->bpSentNot = 0;
|
|
}
|
|
}
|
|
|
|
static void __SetSURegs(u32 tmap, u32 tcoord) {
|
|
u32 w;
|
|
u32 h;
|
|
u8 s_bias;
|
|
u8 t_bias;
|
|
|
|
w = GET_REG_FIELD(__GXData->tImage0[tmap], 10, 0);
|
|
h = GET_REG_FIELD(__GXData->tImage0[tmap], 10, 10);
|
|
SET_REG_FIELD(2091, __GXData->suTs0[tcoord], 16, 0, w);
|
|
SET_REG_FIELD(2092, __GXData->suTs1[tcoord], 16, 0, h);
|
|
s_bias = GET_REG_FIELD(__GXData->tMode0[tmap], 2, 0) == 1;
|
|
t_bias = GET_REG_FIELD(__GXData->tMode0[tmap], 2, 2) == 1;
|
|
SET_REG_FIELD(2098, __GXData->suTs0[tcoord], 1, 16, s_bias);
|
|
SET_REG_FIELD(2099, __GXData->suTs1[tcoord], 1, 16, t_bias);
|
|
GX_WRITE_RAS_REG(__GXData->suTs0[tcoord]);
|
|
GX_WRITE_RAS_REG(__GXData->suTs1[tcoord]);
|
|
__GXData->bpSentNot = 0;
|
|
}
|
|
|
|
void __GXSetSUTexRegs(void) {
|
|
u32 nStages;
|
|
u32 nIndStages;
|
|
u32 i;
|
|
u32 map;
|
|
u32 tmap;
|
|
u32 coord;
|
|
u32* ptref;
|
|
|
|
if (__GXData->tcsManEnab != 0xFF) {
|
|
nStages = GET_REG_FIELD(__GXData->genMode, 4, 10) + 1;
|
|
nIndStages = GET_REG_FIELD(__GXData->genMode, 3, 16);
|
|
for (i = 0; i < nIndStages; i++) {
|
|
switch (i) {
|
|
case 0:
|
|
tmap = GET_REG_FIELD(__GXData->iref, 3, 0);
|
|
coord = GET_REG_FIELD(__GXData->iref, 3, 3);
|
|
break;
|
|
case 1:
|
|
tmap = GET_REG_FIELD(__GXData->iref, 3, 6);
|
|
coord = GET_REG_FIELD(__GXData->iref, 3, 9);
|
|
break;
|
|
case 2:
|
|
tmap = GET_REG_FIELD(__GXData->iref, 3, 12);
|
|
coord = GET_REG_FIELD(__GXData->iref, 3, 15);
|
|
break;
|
|
case 3:
|
|
tmap = GET_REG_FIELD(__GXData->iref, 3, 18);
|
|
coord = GET_REG_FIELD(__GXData->iref, 3, 21);
|
|
break;
|
|
}
|
|
if (!(__GXData->tcsManEnab & (1 << coord))) {
|
|
__SetSURegs(tmap, coord);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nStages; i++) {
|
|
ptref = &__GXData->tref[i / 2];
|
|
map = __GXData->texmapId[i];
|
|
tmap = map & 0xFFFFFEFF;
|
|
if (i & 1) {
|
|
coord = GET_REG_FIELD(*ptref, 3, 15);
|
|
} else {
|
|
coord = GET_REG_FIELD(*ptref, 3, 3);
|
|
}
|
|
if ((tmap != 0xFF) && !(__GXData->tcsManEnab & (1 << coord)) && (__GXData->tevTcEnab & (1 << i))) {
|
|
__SetSURegs(tmap, coord);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void __GXGetSUTexSize(GXTexCoordID coord, u16* width, u16* height) {
|
|
*width = (u16)__GXData->suTs0[coord] + 1;
|
|
*height = (u16)__GXData->suTs1[coord] + 1;
|
|
}
|
|
|
|
void __GXSetTmemConfig(u32 config) {
|
|
switch (config) {
|
|
case 2:
|
|
GX_WRITE_RAS_REG(0x8c0d8000);
|
|
GX_WRITE_RAS_REG(0x900dc000);
|
|
|
|
GX_WRITE_RAS_REG(0x8d0d8800);
|
|
GX_WRITE_RAS_REG(0x910dc800);
|
|
|
|
GX_WRITE_RAS_REG(0x8e0d9000);
|
|
GX_WRITE_RAS_REG(0x920dd000);
|
|
|
|
GX_WRITE_RAS_REG(0x8f0d9800);
|
|
GX_WRITE_RAS_REG(0x930dd800);
|
|
|
|
GX_WRITE_RAS_REG(0xac0da000);
|
|
GX_WRITE_RAS_REG(0xb00dc400);
|
|
|
|
GX_WRITE_RAS_REG(0xad0da800);
|
|
GX_WRITE_RAS_REG(0xb10dcc00);
|
|
|
|
GX_WRITE_RAS_REG(0xae0db000);
|
|
GX_WRITE_RAS_REG(0xb20dd400);
|
|
|
|
GX_WRITE_RAS_REG(0xaf0db800);
|
|
GX_WRITE_RAS_REG(0xb30ddc00);
|
|
break;
|
|
case 1:
|
|
GX_WRITE_RAS_REG(0x8c0d8000);
|
|
GX_WRITE_RAS_REG(0x900dc000);
|
|
|
|
GX_WRITE_RAS_REG(0x8d0d8800);
|
|
GX_WRITE_RAS_REG(0x910dc800);
|
|
|
|
GX_WRITE_RAS_REG(0x8e0d9000);
|
|
GX_WRITE_RAS_REG(0x920dd000);
|
|
|
|
GX_WRITE_RAS_REG(0x8f0d9800);
|
|
GX_WRITE_RAS_REG(0x930dd800);
|
|
|
|
GX_WRITE_RAS_REG(0xac0da000);
|
|
GX_WRITE_RAS_REG(0xb00de000);
|
|
|
|
GX_WRITE_RAS_REG(0xad0da800);
|
|
GX_WRITE_RAS_REG(0xb10de800);
|
|
|
|
GX_WRITE_RAS_REG(0xae0db000);
|
|
GX_WRITE_RAS_REG(0xb20df000);
|
|
|
|
GX_WRITE_RAS_REG(0xaf0db800);
|
|
GX_WRITE_RAS_REG(0xb30df800);
|
|
|
|
break;
|
|
case 0:
|
|
default:
|
|
GX_WRITE_RAS_REG(0x8c0d8000);
|
|
GX_WRITE_RAS_REG(0x900dc000);
|
|
|
|
GX_WRITE_RAS_REG(0x8d0d8400);
|
|
GX_WRITE_RAS_REG(0x910dc400);
|
|
|
|
GX_WRITE_RAS_REG(0x8e0d8800);
|
|
GX_WRITE_RAS_REG(0x920dc800);
|
|
|
|
GX_WRITE_RAS_REG(0x8f0d8c00);
|
|
GX_WRITE_RAS_REG(0x930dcc00);
|
|
|
|
GX_WRITE_RAS_REG(0xac0d9000);
|
|
GX_WRITE_RAS_REG(0xb00dd000);
|
|
|
|
GX_WRITE_RAS_REG(0xad0d9400);
|
|
GX_WRITE_RAS_REG(0xb10dd400);
|
|
|
|
GX_WRITE_RAS_REG(0xae0d9800);
|
|
GX_WRITE_RAS_REG(0xb20dd800);
|
|
|
|
GX_WRITE_RAS_REG(0xaf0d9c00);
|
|
GX_WRITE_RAS_REG(0xb30ddc00);
|
|
|
|
break;
|
|
}
|
|
}
|