#include "egg/core/eggVideo.h" #include "rvl/OS/OSHardware.h" #include "rvl/OS/OSTime.h" #include "rvl/SC/scapi.h" namespace { const GXRenderModeObj gRMO_Pal60_640x456Prog_16x9 = { 0, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 25, // viXOrigin 12, // viYOrigin 670, // viWidth 456, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Pal60_640x456IntDf_16x9 = { 2, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 25, // viXOrigin 12, // viYOrigin 670, // viWidth 456, // viHeight 0, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {0, 0, 21, 22, 21, 0, 0} // vFilter }; const GXRenderModeObj gRMO_Pal50_640x456IntDf_16x9 = { 4, // tvInfo 640, // fbWidth 456, // efbHeight 542, // xfbHeight 27, // viXOrigin 16, // viYOrigin 666, // viWidth 542, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Ntsc_640x456Prog_16x9 = { 20, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 25, // viXOrigin 12, // viYOrigin 670, // viWidth 456, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Ntsc_640x456IntDf_16x9 = { 22, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 25, // viXOrigin 12, // viYOrigin 670, // viWidth 456, // viHeight 0, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {0, 0, 21, 22, 21, 0, 0} // vFilter }; const GXRenderModeObj gRMO_Pal60_640x456Prog_4x3 = { 0, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 17, // viXOrigin 12, // viYOrigin 686, // viWidth 456, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Pal60_640x456IntDf_4x3 = { 2, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 17, // viXOrigin 12, // viYOrigin 686, // viWidth 456, // viHeight 0, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {0, 0, 21, 22, 21, 0, 0} // vFilter }; const GXRenderModeObj gRMO_Pal50_640x456IntDf_4x3 = { 4, // tvInfo 640, // fbWidth 456, // efbHeight 542, // xfbHeight 19, // viXOrigin 16, // viYOrigin 682, // viWidth 542, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Ntsc_640x456Prog_4x3 = { 20, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 17, // viXOrigin 12, // viYOrigin 686, // viWidth 456, // viHeight 1, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {7, 7, 12, 12, 12, 7, 7} // vFilter }; const GXRenderModeObj gRMO_Ntsc_640x456IntDf_4x3 = { 22, // tvInfo 640, // fbWidth 456, // efbHeight 456, // xfbHeight 17, // viXOrigin 12, // viYOrigin 686, // viWidth 456, // viHeight 0, // xfbMode 0, // field_rendering 0, // aa { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, }, // sample_pattern {0, 0, 21, 22, 21, 0, 0} // vFilter }; const EGG::Video::RenderModeObjSet gStandardRenderModeObjSet = { {&gRMO_Pal60_640x456Prog_16x9, &gRMO_Pal60_640x456IntDf_16x9, &gRMO_Pal50_640x456IntDf_16x9, &gRMO_Ntsc_640x456Prog_16x9, &gRMO_Ntsc_640x456IntDf_16x9, &gRMO_Pal60_640x456Prog_4x3, &gRMO_Pal60_640x456IntDf_4x3, &gRMO_Pal50_640x456IntDf_4x3, &gRMO_Ntsc_640x456Prog_4x3, &gRMO_Ntsc_640x456IntDf_4x3} }; } // namespace namespace EGG { void Video::initialize(GXRenderModeObj *obj, const RenderModeObjSet *set) { VIInit(); configure(obj, set); } GXRenderModeObj *Video::configure(GXRenderModeObj *obj, const RenderModeObjSet *set) { GXRenderModeObj *oldMode = pRenderMode; if (set == nullptr) { set = &gStandardRenderModeObjSet; } if (obj == nullptr) { // Cast away constness. In an incredibly cursed way, adding proper // const correctness to this class changes regalloc obj = (GXRenderModeObj *)getStandardRenderModeObj(set); } if (pRenderMode != obj) { pRenderMode = obj; VISetBlack(true); VIConfigure(obj); VIFlush(); mConfiguredTime = OSGetTick(); mFlag.setBit(0); u16 efbWidth = obj->fbWidth; u16 efbHeight = obj->efbHeight; f32 factor = GXGetYScaleFactor(efbHeight, obj->xfbHeight); u16 lines = GXGetNumXfbLines(efbHeight, factor); GXSetDispCopySrc(0, 0, efbWidth, efbHeight); GXSetDispCopyDst(efbWidth, lines); GXSetDispCopyYScale(factor); VIWaitForRetrace(); VIWaitForRetrace(); } return oldMode; } // Random function that pretends to do an int to float // cast here, for float ordering issues f32 itof(u32 n) { return n; } // TODO VITvFormat u32 Video::getTickPerVRetrace(u32 tvFormat) { f32 val = tvFormat - 1 <= VI_TV_FMT_PAL ? 50.0f : 59.94f; return (u32)((OS_BUS_CLOCK_SPEED >> 2) / val); } u32 Video::getTickPerVRetrace() { return getTickPerVRetrace(VIGetTvFormat()); } const GXRenderModeObj *Video::getStandardRenderModeObj(const RenderModeObjSet *set) { bool pmode = SCGetProgressiveMode() == 1; bool rbg60mode = SCGetEuRgb60Mode() == 1; bool aspect = SCGetAspectRatio() == 0; bool dtvstatus = VIGetDTVStatus() == 1; u32 tvFormat = VIGetTvFormat(); bool isNtscLike; switch (tvFormat) { case VI_TV_FMT_NTSC: isNtscLike = true; break; case VI_TV_FMT_PAL: case VI_TV_FMT_EURGB60: isNtscLike = false; break; default: isNtscLike = true; } if (dtvstatus && pmode) { if (isNtscLike) { if (aspect) { return set->table[1]; } else { return set->table[6]; } } else if (aspect) { return set->table[4]; } else { return set->table[9]; } } else if (isNtscLike) { if (aspect) { return set->table[0]; } else { return set->table[5]; } } else if (rbg60mode) { if (aspect) { return set->table[3]; } else { return set->table[8]; } } else if (aspect) { return set->table[2]; } return set->table[7]; } } // namespace EGG