#include "gx.hpp" #include "../gfx/texture.hpp" #include static absl::flat_hash_map g_resolvedTexMap; void GXInitTexObj(GXTexObj* obj_, const void* data, u16 width, u16 height, u32 format, GXTexWrapMode wrapS, GXTexWrapMode wrapT, GXBool mipmap) { memset(obj_, 0, sizeof(GXTexObj)); auto* obj = reinterpret_cast(obj_); obj->data = data; obj->width = width; obj->height = height; obj->fmt = format; obj->wrapS = wrapS; obj->wrapT = wrapT; obj->hasMips = mipmap; // TODO default values? obj->minFilter = GX_LINEAR; obj->magFilter = GX_LINEAR; obj->minLod = 0.f; obj->maxLod = 0.f; obj->lodBias = 0.f; obj->biasClamp = false; obj->doEdgeLod = false; obj->maxAniso = GX_ANISO_4; obj->tlut = GX_TLUT0; if (g_resolvedTexMap.contains(data)) { obj->dataInvalidated = false; // TODO hack } else { obj->dataInvalidated = true; } } void GXInitTexObjCI(GXTexObj* obj_, const void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS, GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) { memset(obj_, 0, sizeof(GXTexObj)); auto* obj = reinterpret_cast(obj_); obj->data = data; obj->width = width; obj->height = height; obj->fmt = static_cast(format); obj->wrapS = wrapS; obj->wrapT = wrapT; obj->hasMips = mipmap; obj->tlut = static_cast(tlut); // TODO default values? obj->minFilter = GX_LINEAR; obj->magFilter = GX_LINEAR; obj->minLod = 0.f; obj->maxLod = 0.f; obj->lodBias = 0.f; obj->biasClamp = false; obj->doEdgeLod = false; obj->maxAniso = GX_ANISO_4; obj->dataInvalidated = true; } void GXInitTexObjLOD(GXTexObj* obj_, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias, GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) { auto* obj = reinterpret_cast(obj_); obj->minFilter = minFilt; obj->magFilter = magFilt; obj->minLod = minLod; obj->maxLod = maxLod; obj->lodBias = lodBias; obj->biasClamp = biasClamp; obj->doEdgeLod = doEdgeLod; obj->maxAniso = maxAniso; } void GXInitTexObjData(GXTexObj* obj_, const void* data) { auto* obj = reinterpret_cast(obj_); obj->data = data; obj->dataInvalidated = true; } void GXInitTexObjWrapMode(GXTexObj* obj_, GXTexWrapMode wrapS, GXTexWrapMode wrapT) { auto* obj = reinterpret_cast(obj_); obj->wrapS = wrapS; obj->wrapT = wrapT; } void GXInitTexObjTlut(GXTexObj* obj_, u32 tlut) { auto* obj = reinterpret_cast(obj_); obj->tlut = static_cast(tlut); } // TODO GXInitTexObjFilter // TODO GXInitTexObjMaxLOD // TODO GXInitTexObjMinLOD // TODO GXInitTexObjLODBias // TODO GXInitTexObjBiasClamp // TODO GXInitTexObjEdgeLOD // TODO GXInitTexObjMaxAniso // TODO GXInitTexObjUserData // TODO GXGetTexObjUserData void GXLoadTexObj(GXTexObj* obj_, GXTexMapID id) { auto* obj = reinterpret_cast(obj_); if (!obj->ref) { obj->ref = aurora::gfx::new_dynamic_texture_2d(obj->width, obj->height, u32(obj->maxLod) + 1, obj->fmt, fmt::format(FMT_STRING("GXLoadTexObj_{}"), obj->fmt).c_str()); } if (obj->dataInvalidated) { aurora::gfx::write_texture(*obj->ref, {static_cast(obj->data), UINT32_MAX /* TODO */}); obj->dataInvalidated = false; } g_gxState.textures[id] = {*obj}; g_gxState.stateDirty = true; // TODO only if changed? } u32 GXGetTexBufferSize(u16 width, u16 height, u32 fmt, GXBool mips, u8 maxLod) { s32 shiftX = 0; s32 shiftY = 0; switch (fmt) { case GX_TF_I4: case GX_TF_C4: case GX_TF_CMPR: case GX_CTF_R4: case GX_CTF_Z4: shiftX = 3; shiftY = 3; break; case GX_TF_I8: case GX_TF_IA4: case GX_TF_C8: case GX_TF_Z8: case GX_CTF_RA4: case GX_CTF_A8: case GX_CTF_R8: case GX_CTF_G8: case GX_CTF_B8: case GX_CTF_Z8M: case GX_CTF_Z8L: shiftX = 3; shiftY = 2; break; case GX_TF_IA8: case GX_TF_RGB565: case GX_TF_RGB5A3: case GX_TF_RGBA8: case GX_TF_C14X2: case GX_TF_Z16: case GX_TF_Z24X8: case GX_CTF_RA8: case GX_CTF_RG8: case GX_CTF_GB8: case GX_CTF_Z16L: shiftX = 2; shiftY = 2; break; default: break; } u32 bitSize = fmt == GX_TF_RGBA8 || fmt == GX_TF_Z24X8 ? 64 : 32; u32 bufLen = 0; if (mips) { while (maxLod != 0) { const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); bufLen += bitSize * tileX * tileY; if (width == 1 && height == 1) { return bufLen; } width = (width < 2) ? 1 : width / 2; height = (height < 2) ? 1 : height / 2; --maxLod; }; } else { const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); bufLen = bitSize * tileX * tileY; } return bufLen; } void GXInitTlutObj(GXTlutObj* obj_, const void* data, GXTlutFmt format, u16 entries) { memset(obj_, 0, sizeof(GXTlutObj)); GXTexFmt texFmt; switch (format) { case GX_TL_IA8: texFmt = GX_TF_IA8; break; case GX_TL_RGB565: texFmt = GX_TF_RGB565; break; case GX_TL_RGB5A3: texFmt = GX_TF_RGB5A3; break; default: Log.report(LOG_FATAL, FMT_STRING("invalid tlut format {}"), format); unreachable(); } auto* obj = reinterpret_cast(obj_); obj->ref = aurora::gfx::new_static_texture_2d( entries, 1, 1, texFmt, aurora::ArrayRef{static_cast(data), static_cast(entries) * 2}, "GXInitTlutObj"); } void GXLoadTlut(const GXTlutObj* obj_, GXTlut idx) { g_gxState.tluts[idx] = *reinterpret_cast(obj_); // TODO stateDirty? } // TODO GXInitTexCacheRegion // TODO GXInitTexPreLoadRegion // TODO GXInitTlutRegion // TODO GXInvalidateTexRegion void GXInvalidateTexAll() { // no-op? } // TODO GXPreLoadEntireTexture // TODO GXSetTexRegionCallback // TODO GXSetTlutRegionCallback // TODO GXLoadTexObjPreLoaded // TODO GXSetTexCoordScaleManually // TODO GXSetTexCoordCylWrap // TODO GXSetTexCoordBias void GXCopyTex(void* dest, GXBool clear) { // TODO g_resolvedTexMap.emplace(dest, 0); }