diff options
| author | Elijah Thomas <42302100+elijah-thomas774@users.noreply.github.com> | 2024-05-02 13:26:04 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-02 13:26:04 -0400 |
| commit | 8d343e8fef3dc22ac13b183db957a473aa9d025c (patch) | |
| tree | 040acb459de75e17fd606842d147345fd1d5f33b /src/egg/core/eggAsyncDisplay.cpp | |
| parent | 79cb3484097acfad3ff02984617add9b73495c0a (diff) | |
| parent | 05259b75e348e974697cb497b5e3d8fb78e4b376 (diff) | |
Merge pull request #7 from robojumper/eggAsyncDisplay
egg/core/eggAsyncDisplay.cpp
Diffstat (limited to 'src/egg/core/eggAsyncDisplay.cpp')
| -rw-r--r-- | src/egg/core/eggAsyncDisplay.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/egg/core/eggAsyncDisplay.cpp b/src/egg/core/eggAsyncDisplay.cpp new file mode 100644 index 00000000..7a128d55 --- /dev/null +++ b/src/egg/core/eggAsyncDisplay.cpp @@ -0,0 +1,237 @@ +#include <egg/core/eggAsyncDisplay.h> +#include <egg/core/eggXfbManager.h> +#include <egg/math/eggMatrix.h> +#include <rvl/GX/GXHardware.h> +#include <rvl/GX/GXTexture.h> + +// TODO: Find the proper place for this symbol? - Ghidra has it literally unused +extern "C" static EGG::Display *spSelector; + +namespace { +static GXTexObj clear_z_tobj; +// clang-format off +u8 clear_z_TX[64] ALIGN(32) = { + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; +// clang-format on +} // namespace + +// Hacks for float ordering +static f32 one() { + return 1.0f; +} + +static f64 cast() { + return 4503599627370496.0; +} + +static f32 zero() { + return 0.0f; +} + +namespace EGG { + +AsyncDisplay::AsyncDisplay(u8 maxRetrace) : Display(maxRetrace) { + this->field_0x98 = 0; + this->field_0x9C = 1.0f; + this->field_0xA4 = 0; + this->field_0xA8 = 0; + this->field_0xAC = 0; + this->field_0xB8 = 0; + spSelector = this; + OSInitThreadQueue(&this->mThreadQueue); + OSInitMessageQueue(&this->mMesgQueue, this->mMesgBuf, 4); +} + +f32 AsyncDisplay::calcS() { + f32 tmp = this->field_0x9C + this->field_0xA0; + this->field_0x9C = tmp; + if (tmp > 1.0f) { + if (this->mScreenStateFlag.onBit(4)) { + this->field_0x9C = tmp - 1.0f; + this->mScreenStateFlag.resetBit(4); + } else { + this->field_0x9C = tmp - this->field_0xA0; + this->mScreenStateFlag.setBit(4); + } + } + return tmp; +} + +inline void AsyncDisplay::waitForMsg(bool b) { + // This is really ugly but I couldn't find a different way + // to make the compiler use the registers + XfbManager *xfb; + while (!((xfb = BaseSystem::mConfigData->getXfbMgr(), 1 < xfb->mNumXfbs - this->field_0xAC) && + (BaseSystem::mConfigData->getXfbMgr()->mToCopyXfb != nullptr || b))) { + OSReceiveMessage(&this->mMesgQueue, this->mMesgBuf, 1); + + while (OSReceiveMessage(&this->mMesgQueue, this->mMesgBuf, 0)) {} + } +} + +void AsyncDisplay::beginFrame() { + BaseSystem::mConfigData->getXfbMgr(); + GXDrawDone(); + + if (this->mFlag.onBit(1)) { + OSSleepThread(&this->mThreadQueue); + } + bool b = false; + if (BaseSystem::mConfigData->getXfbMgr()->mNumXfbs == 1) { + s32 tick = OSGetTick(); + s32 lastTick = this->mLastTick; + if (tick - lastTick > Display::sTickPeriod) { + VIWaitForRetrace(); + } + } else { + b = false; + if (this->field_0x98 == 1 && this->mScreenStateFlag.onBit(6)) { + b = true; + } + + this->waitForMsg(b); + } + + if (b) { + this->clearEFB(); + this->mScreenStateFlag.resetBit(6); + GXDrawDone(); + } else { + this->copyEFBtoXFB(); + } + + if (this->field_0x98 == 1) { + this->calcS(); + } + this->field_0xAC++; + this->mFrameCount++; + this->calcFrequency(); +} + +void AsyncDisplay::endFrame() { + if (this->mScreenStateFlag.onBit(4)) { + this->mScreenStateFlag.setBit(5); + } +} + +void AsyncDisplay::endRender() { + if (this->mScreenStateFlag.onBit(5)) { + this->mScreenStateFlag.setBit(6); + this->mScreenStateFlag.resetBit(5); + } +} + +void AsyncDisplay::preVRetrace() { + s32 tick = OSGetTick(); + this->mLastTick = tick; + if (this->field_0x98 == 0) { + u32 a8 = ++this->field_0xA8; + if (a8 - this->field_0xA4 >= this->mMaxRetraces) { + this->field_0xA4 = a8; + this->mScreenStateFlag.setBit(3); + OSSendMessage(&this->mMesgQueue, this->mMesgBuf, 0); + if (this->field_0xAC > 0) { + this->field_0xAC--; + } + } + OSWakeupThread(&this->mThreadQueue); + } + + if (this->mScreenStateFlag.onBit(3)) { + s32 count = VIGetRetraceCount(); + if (count - this->mRetraceCount >= this->mMaxRetraces) { + if (this->mScreenStateFlag.onBit(0)) { + Video *video = BaseSystem::mConfigData->getVideo(); + VISetBlack(video->mFlag.offBit(0)); + if (video->mFlag.offBit(0)) { + video->mFlag.setBit(0); + } else { + video->mFlag.resetBit(0); + } + this->mScreenStateFlag.resetBit(0); + } + XfbManager *xfb = BaseSystem::mConfigData->getXfbMgr(); + xfb->setNextFrameBuffer(); + s32 newCount = VIGetRetraceCount(); + this->mRetraceCount = newCount; + this->mScreenStateFlag.resetBit(3); + } + } +} + +void AsyncDisplay::clearEFB() { + Video *video = BaseSystem::mConfigData->getVideo(); + GXRenderModeObj const *renderMode = video->pRenderMode; + this->clearEFB(renderMode->fbWidth, renderMode->efbHeight, 0, 0, renderMode->fbWidth, renderMode->efbHeight, + this->mClearColor); +} + +u32 AsyncDisplay::getTickPerFrame() { + if (this->field_0x98 == 1) { + return Video::getTickPerVRetrace(0); + } else { + return Video::getTickPerVRetrace(); + } +} + +void AsyncDisplay::clearEFB(u16 fbWidth, u16 fbHeight, u16 x, u16 y, u16 width, u16 height, nw4r::ut::Color color) { + GXInitTexObj(&clear_z_tobj, &clear_z_TX, 4, 4, GX_TF_Z24X8, GX_REPEAT, GX_REPEAT, 0); + GXInitTexObjLOD(&clear_z_tobj, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); + Mtx44 mat; + C_MTXOrtho(mat, 0.0, fbHeight, 0.0, fbWidth, 0.0, 1.0f); + GXSetProjection(mat, GX_ORTHOGRAPHIC); + GXSetViewport(0.0, 0.0, fbWidth, fbHeight, 0.0, 1.0f); + GXSetScissor(0, 0, fbWidth, fbHeight); + Matrix34f::ident.loadPosMtx(0); + GXSetCurrentMtx(0); + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBX8, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGB565, 0); + GXSetNumChans(0); + GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetChanCtrl(GX_COLOR1A1, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetNumTexGens(1); + GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c, false, 0x7d); + GXLoadTexObj(&clear_z_tobj, GX_TEXMAP0); + GXSetNumTevStages(1); + GXSetTevColor(GX_TEVREG0, color); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_TEV_SCALE_0, 1, GX_TEVPREV); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_TEV_SCALE_0, 1, GX_TEVPREV); + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); + GXSetZTexture(2, GX_TF_Z24X8, 0); + GXSetZCompLoc(false); + GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_NOOP); + GXSetAlphaUpdate(true); + GXSetDstAlpha(true, color.a); + GXSetZMode(true, GX_ALWAYS, true); + GXSetCullMode(GX_CULL_BACK); + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + + GXPosition2u16(x, y); + GXPosition2u8(0, 0); + u16 tmp = x + width; + GXPosition2u16(tmp, y); + GXPosition2u8(1, 0); + u16 tmp2 = y + height; + GXPosition2u16(tmp, tmp2); + GXPosition2u8(1, 1); + GXPosition2u16(x, tmp2); + GXPosition2u8(0, 1); + + // GXEnd(); + + GXSetZTexture(0, GX_TF_Z24X8, 0); + GXSetZCompLoc(true); + GXSetDstAlpha(false, color.a); +} + +} // namespace EGG |
