2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-18 21:25:25 +00:00

Transition all Textured/ColoredQuad usages

- Upload textures using staging buffer
- Fixes SetOrtho logic
- More work on thermal visor rendering (still WIP)
- Rework Dawn backend initialization
- Support MoltenVK on Metal
- Various fixes & cleanup
This commit is contained in:
2022-05-23 20:26:35 -04:00
parent 36a7bfc464
commit f80813b9cc
65 changed files with 857 additions and 687 deletions

View File

@@ -4,6 +4,7 @@
#include "CDvdRequest.hpp"
#include "Graphics/CGraphics.hpp"
#include "Graphics/CCubeRenderer.hpp"
#include "Graphics/CGX.hpp"
#include "GameGlobalObjects.hpp"
#include <amuse/DSPCodec.hpp>
@@ -11,6 +12,110 @@
namespace metaforce {
static void MyTHPYuv2RgbTextureSetup(void* dataY, void* dataU, void* dataV, u16 width, u16 height) {
GXTexObj texV;
GXTexObj texU;
GXTexObj texY;
GXInitTexObj(&texY, dataY, width, height, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texY, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texY, GX::TEXMAP0);
GXInitTexObj(&texU, dataU, width / 2, height / 2, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texU, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texU, GX::TEXMAP1);
GXInitTexObj(&texV, dataV, width / 2, height / 2, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texV, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texV, GX::TEXMAP2);
CTexture::InvalidateTexMap(GX::TEXMAP0);
CTexture::InvalidateTexMap(GX::TEXMAP1);
CTexture::InvalidateTexMap(GX::TEXMAP2);
}
const std::array<u8, 32> InterlaceTex{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0,
};
static void MyTHPGXYuv2RgbSetup(bool interlaced2ndFrame, bool fieldFlip) {
CGX::SetZMode(true, GX::ALWAYS, false);
CGX::SetBlendMode(GX::BM_NONE, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
CGX::SetNumChans(0);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
CGX::SetTexCoordGen(GX::TEXCOORD1, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
if (!fieldFlip) {
CGX::SetNumTexGens(3);
CGX::SetTexCoordGen(GX::TEXCOORD2, GX::TG_MTX2x4, GX::TG_POS, GX::TEXMTX0, false, GX::PTIDENTITY);
aurora::Mat4x2<float> mtx;
mtx.m0.x = 0.125f;
mtx.m2.y = 0.25f;
if (interlaced2ndFrame) {
mtx.m3.y = 0.25f;
}
GXLoadTexMtxImm(&mtx, GX::TEXMTX0, GX::MTX2x4);
GXTexObj texObj;
GXInitTexObj(&texObj, InterlaceTex.data(), 8, 4, GX::TF_I8, GX_REPEAT, GX_REPEAT, false);
GXInitTexObjLOD(&texObj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
GXLoadTexObj(&texObj, GX::TEXMAP3);
CTexture::InvalidateTexMap(GX::TEXMAP3);
CGX::SetTevOrder(GX::TEVSTAGE4, GX::TEXCOORD2, GX::TEXMAP3, GX::COLOR_NULL);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE4);
CGX::SetTevColorIn(GX::TEVSTAGE4, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_CPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE4, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA);
CGX::SetAlphaCompare(GX::LESS, 128, GX::AOP_AND, GX::ALWAYS, 0);
CGX::SetNumTevStages(5);
} else {
CGX::SetNumTexGens(2);
CGX::SetNumTevStages(4);
}
constexpr std::array vtxDescList{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
CGX::SetVtxDescv(vtxDescList.data());
GXSetColorUpdate(true);
GXSetAlphaUpdate(false);
GXInvalidateTexAll();
GXSetVtxAttrFmt(GX::VTXFMT7, GX::VA_POS, GX::CLR_RGBA, GX::F32, 0);
GXSetVtxAttrFmt(GX::VTXFMT7, GX::VA_TEX0, GX::CLR_RGBA, GX::RGBX8, 0);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_C0);
CGX::SetTevColorOp(GX::TEVSTAGE0, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_A0);
CGX::SetTevAlphaOp(GX::TEVSTAGE0, GX::TEV_SUB, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0);
CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP2, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_CPREV);
CGX::SetTevColorOp(GX::TEVSTAGE1, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_2, false, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_APREV);
CGX::SetTevAlphaOp(GX::TEVSTAGE1, GX::TEV_SUB, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE1, GX::TEV_KCSEL_K1);
CGX::SetTevKAlphaSel(GX::TEVSTAGE1, GX::TEV_KASEL_K1_A);
CGX::SetTevOrder(GX::TEVSTAGE2, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE2, GX::CC_ZERO, GX::CC_TEXC, GX::CC_ONE, GX::CC_CPREV);
CGX::SetTevColorOp(GX::TEVSTAGE2, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE2, GX::CA_TEXA, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV);
CGX::SetTevAlphaOp(GX::TEVSTAGE2, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevOrder(GX::TEVSTAGE3, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE3, GX::CC_APREV, GX::CC_CPREV, GX::CC_KONST, GX::CC_ZERO);
CGX::SetTevColorOp(GX::TEVSTAGE3, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE3, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO);
CGX::SetTevAlphaOp(GX::TEVSTAGE3, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE3, GX::TEV_KCSEL_K2);
GXSetTevColorS10(GX::TEVREG0, 0xffa60000ff8e0087u);
CGX::SetTevKColor(GX::KCOLOR0, zeus::Comp32(0x0000e258));
CGX::SetTevKColor(GX::KCOLOR1, zeus::Comp32(0xb30000b6));
CGX::SetTevKColor(GX::KCOLOR2, zeus::Comp32(0xff00ff80));
}
static void MyTHPGXRestore() {
CGX::SetZMode(true, GX::ALWAYS, false);
CGX::SetBlendMode(GX::BM_NONE, GX::BL_ONE, GX::BL_ZERO, GX::LO_SET);
CGX::SetNumTexGens(1);
CGX::SetNumChans(0);
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
}
/* used in the original to look up fixed-point dividends on a
* MIDI-style volume scale (0-127) -> (n/0x8000) */
static const std::array<u16, 128> StaticVolumeLookup = {
@@ -359,29 +464,92 @@ void CMoviePlayer::Rewind() {
xe8_curSeconds = 0.f;
}
void CMoviePlayer::Draw() {
bool CMoviePlayer::DrawVideo() {
// TODO
// if (!xa0_bufferQueue.empty()) {
// return false;
// }
g_Renderer->SetDepthReadWrite(false, false);
g_Renderer->SetViewportOrtho(false, -4096.f, 4096.f);
const s32 vpHeight = CGraphics::GetViewportHeight();
const s32 vpWidth = CGraphics::GetViewportWidth();
const s32 vpTop = CGraphics::GetViewportTop();
const s32 vpLeft = CGraphics::GetViewportLeft();
const s32 vidWidth = x6c_videoInfo.width;
const s32 vidHeight = x6c_videoInfo.height;
const s32 centerX = (vidWidth - vpWidth) / 2;
const s32 centerY = (vidHeight - vpHeight) / 2;
const s32 vl = vpLeft - centerX;
const s32 vr = vpLeft + vpWidth + centerX;
const s32 vb = vpTop + vpHeight + centerY;
const s32 vt = vpTop - centerY;
aurora::Vec3<float> v1;
aurora::Vec3<float> v2;
aurora::Vec3<float> v3;
aurora::Vec3<float> v4;
v1.x = vl;
v1.y = 0.0;
v1.z = vb;
v2.x = vr;
v2.y = 0.0;
v2.z = vb;
v3.x = vl;
v3.y = 0.0;
v3.z = vt;
v4.x = vr;
v4.y = 0.0;
v4.z = vt;
DrawFrame(v1, v2, v3, v4);
return true;
}
void CMoviePlayer::DrawFrame(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3,
const zeus::CVector3f& v4) {
if (xd0_drawTexSlot == UINT32_MAX || !GetIsFullyCached()) {
return;
}
SCOPED_GRAPHICS_DEBUG_GROUP("CMoviePlayer::DrawFrame", zeus::skYellow);
/* Correct movie aspect ratio */
float hPad, vPad;
if (CGraphics::GetViewportAspect() >= 1.78f) {
hPad = 1.78f / CGraphics::GetViewportAspect();
vPad = 1.78f / 1.33f;
} else {
hPad = 1.f;
vPad = CGraphics::GetViewportAspect() / 1.33f;
}
CGraphics::SetUseVideoFilter(xf4_26_fieldFlip);
/* draw appropriate field */
CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, hPad, vPad);
/* Correct movie aspect ratio */
// float hPad, vPad;
// if (CGraphics::GetViewportAspect() >= 1.78f) {
// hPad = 1.78f / CGraphics::GetViewportAspect();
// vPad = 1.78f / 1.33f;
// } else {
// hPad = 1.f;
// vPad = CGraphics::GetViewportAspect() / 1.33f;
// }
//
// /* draw appropriate field */
// CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
// aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, hPad, vPad);
MyTHPGXYuv2RgbSetup(CGraphics::g_LastFrameUsedAbove, xf4_26_fieldFlip);
uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
uintptr_t planeSizeQuarter = planeSize / 4;
MyTHPYuv2RgbTextureSetup(m_yuvBuf.get(), m_yuvBuf.get() + planeSize, m_yuvBuf.get() + planeSize + planeSizeQuarter,
x6c_videoInfo.width, x6c_videoInfo.height);
CGX::Begin(GX::TRIANGLEFAN, GX::VTXFMT7, 4);
GXPosition3f32(v1);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(v3);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(v4);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(v2);
GXTexCoord2f32(1.f, 0.f);
CGX::End();
MyTHPGXRestore();
/* ensure second field is being displayed by VI to signal advance
* (faked in metaforce with continuous xor) */
if (!xfc_fieldIndex && CGraphics::g_LastFrameUsedAbove)
if (xfc_fieldIndex == 0 && CGraphics::g_LastFrameUsedAbove)
xf4_26_fieldFlip = true;
++xfc_fieldIndex;
@@ -487,29 +655,29 @@ void CMoviePlayer::DecodeFromRead(const void* data) {
tjDecompressToYUV(TjHandle, (u8*)inptr, frameHeader.imageSize, m_yuvBuf.get(), 0);
inptr += frameHeader.imageSize;
uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
uintptr_t planeSizeHalf = planeSize / 2;
uintptr_t planeSizeQuarter = planeSizeHalf / 2;
// uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
// uintptr_t planeSizeHalf = planeSize / 2;
// uintptr_t planeSizeQuarter = planeSizeHalf / 2;
if (m_deinterlace) {
/* Deinterlace into 2 discrete 60-fps half-res textures */
auto buffer = std::make_unique<u8[]>(planeSizeHalf);
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
x6c_videoInfo.width);
}
aurora::gfx::write_texture(*tex.Y[0], {buffer.get(), planeSizeHalf});
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
x6c_videoInfo.width);
}
aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf});
} else {
/* Direct planar load */
aurora::gfx::write_texture(*tex.Y[0], {m_yuvBuf.get(), planeSize});
}
aurora::gfx::write_texture(*tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
// if (m_deinterlace) {
// /* Deinterlace into 2 discrete 60-fps half-res textures */
// auto buffer = std::make_unique<u8[]>(planeSizeHalf);
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
// memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
// x6c_videoInfo.width);
// }
// aurora::gfx::write_texture(*tex.Y[0], {buffer.get(), planeSizeHalf});
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
// memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
// x6c_videoInfo.width);
// }
// aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf});
// } else {
// /* Direct planar load */
// aurora::gfx::write_texture(*tex.Y[0], {m_yuvBuf.get(), planeSize});
// }
// aurora::gfx::write_texture(*tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
// aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
break;
}