diff options
Diffstat (limited to 'backends/ps2')
-rw-r--r-- | backends/ps2/DmaPipe.cpp | 2 | ||||
-rw-r--r-- | backends/ps2/Gs2dScreen.cpp | 285 | ||||
-rw-r--r-- | backends/ps2/Gs2dScreen.h | 25 | ||||
-rw-r--r-- | backends/ps2/READ_PS2.TXT | 68 | ||||
-rw-r--r-- | backends/ps2/asyncfio.cpp | 6 | ||||
-rw-r--r-- | backends/ps2/fileio.cpp | 72 | ||||
-rw-r--r-- | backends/ps2/ps2input.cpp | 77 | ||||
-rw-r--r-- | backends/ps2/ps2input.h | 3 | ||||
-rw-r--r-- | backends/ps2/ps2pad.cpp | 3 | ||||
-rw-r--r-- | backends/ps2/savefile.cpp | 487 | ||||
-rw-r--r-- | backends/ps2/savefile.h | 24 | ||||
-rw-r--r-- | backends/ps2/smushio.cpp | 376 | ||||
-rw-r--r-- | backends/ps2/systemps2.cpp | 332 | ||||
-rw-r--r-- | backends/ps2/systemps2.h | 51 |
14 files changed, 1040 insertions, 771 deletions
diff --git a/backends/ps2/DmaPipe.cpp b/backends/ps2/DmaPipe.cpp index d04190c9f7..bdfa9a5f16 100644 --- a/backends/ps2/DmaPipe.cpp +++ b/backends/ps2/DmaPipe.cpp @@ -169,7 +169,7 @@ void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, uint32 rgba) { checkSpace(3); _pipes[_curPipe]->setGifRegListTag( 4, 0xffffffffffff5510); - _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0), + _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 0, 0, 1, 0, 0, 0, 0), GS_SET_COLQ(rgba)); _pipes[_curPipe]->setListReg( GS_SET_XYZ(p1->x, p1->y, p1->z), GS_SET_XYZ(p2->x, p2->y, p2->z)); diff --git a/backends/ps2/Gs2dScreen.cpp b/backends/ps2/Gs2dScreen.cpp index ee33ca6b77..fbb9d690f5 100644 --- a/backends/ps2/Gs2dScreen.cpp +++ b/backends/ps2/Gs2dScreen.cpp @@ -28,13 +28,17 @@ #include <math.h> #include "DmaPipe.h" #include "GsDefs.h" +#include "graphics/surface.h" enum Buffers { SCREEN = 0, MOUSE, - TEXT + TEXT, + PRINTF }; +#define ANIM_STACK_SIZE (1024 * 32) + #define DEFAULT_PAL_X 175 #define DEFAULT_PAL_Y 60 #define DEFAULT_NTSC_X 165 @@ -50,8 +54,6 @@ enum Buffers { #define M_SIZE 128 #define M_POW 7 -#define PI 3.1415926535897932384626433832795 - static volatile uint32 g_VblankCmd = 0, g_DmacCmd = 0; static int g_VblankSema, g_DmacSema, g_AnimSema; static bool g_RunAnim = false; @@ -60,8 +62,13 @@ static TexVertex kMouseTex[2] = { { SCALE(1), SCALE(1) }, { SCALE(M_SIZE), SCALE(M_SIZE) } }; +static TexVertex kPrintTex[2] = { + { SCALE(1), SCALE(1) }, + { SCALE(320), SCALE(200) } +}; void sioprintf(const char *zFormat, ...); +void runAnimThread(Gs2dScreen *param); int vblankStartHandler(int cause) { // start of VBlank period @@ -92,6 +99,7 @@ void createAnimThread(Gs2dScreen *screen); Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { + _systemQuit = false; ee_sema_t newSema; newSema.init_count = 1; newSema.max_count = 1; @@ -103,9 +111,9 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { g_AnimSema = CreateSema(&newSema); assert((g_VblankSema >= 0) && (g_DmacSema >= 0) && (_screenSema >= 0) && (g_AnimSema >= 0)); - AddIntcHandler(INT_VBLANK_START, vblankStartHandler, 0); - AddIntcHandler(INT_VBLANK_END, vblankEndHandler, 0); - AddDmacHandler(2, dmacHandler, 0); + _vblankStartId = AddIntcHandler(INT_VBLANK_START, vblankStartHandler, 0); + _vblankEndId = AddIntcHandler(INT_VBLANK_END, vblankEndHandler, 0); + _dmacId = AddDmacHandler(2, dmacHandler, 0); _dmaPipe = new DmaPipe(0x2000); @@ -123,6 +131,7 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { memset(_screenBuf, 0, _width * _height); memset(_clut, 0, 256 * sizeof(uint32)); + _clut[1] = GS_RGBA(0xC0, 0xC0, 0xC0, 0); clearOverlay(); if (tvMode == TV_DONT_CARE) { @@ -159,10 +168,11 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { _clutPtrs[MOUSE] = _clutPtrs[SCREEN] + 0x1000; // the cluts in PSMCT32 take up half a memory page each _clutPtrs[TEXT] = _clutPtrs[SCREEN] + 0x2000; _texPtrs[SCREEN] = _clutPtrs[SCREEN] + 0x3000; - _texPtrs[TEXT] = 0; - _texPtrs[MOUSE] = 128 * 128 * 4; // mouse cursor is loaded into the gaps of the frame buffer + _texPtrs[TEXT] = 0; // these buffers are stored in the alpha gaps of the frame buffers + _texPtrs[MOUSE] = 128 * 256 * 4; + _texPtrs[PRINTF] = _texPtrs[MOUSE] + M_SIZE * M_SIZE * 4; - _showOverlay = true; + _showOverlay = false; _showMouse = false; _mouseScaleX = (_tvWidth << 8) / _width; _mouseScaleY = (_tvHeight << 8) / _height; @@ -173,7 +183,6 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { // setup hardware now. GS_CSR = CSR_RESET; // Reset GS asm ("sync.p"); - GS_CSR = 0; GsPutIMR(0x7F00); @@ -205,14 +214,55 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { _clutChanged = _screenChanged = _overlayChanged = true; + clearPrintfOverlay(); updateScreen(); createAnimTextures(); - createAnimThread(this); + + // create anim thread + ee_thread_t animThread, thisThread; + ReferThreadStatus(GetThreadId(), &thisThread); + + _animStack = malloc(ANIM_STACK_SIZE); + animThread.initial_priority = thisThread.current_priority - 3; + animThread.stack = _animStack; + animThread.stack_size = ANIM_STACK_SIZE; + animThread.func = (void *)runAnimThread; + asm("move %0, $gp\n": "=r"(animThread.gp_reg)); + + _animTid = CreateThread(&animThread); + assert(_animTid >= 0); + StartThread(_animTid, this); +} + +void Gs2dScreen::quit(void) { + _systemQuit = true; + ee_thread_t statAnim; + do { // wait until thread called ExitThread() + SignalSema(g_AnimSema); + ReferThreadStatus(_animTid, &statAnim); + } while (statAnim.status != 0x10); + DeleteThread(_animTid); + free(_animStack); + _dmaPipe->waitForDma(); // wait for dmac and vblank for the last time + while (g_DmacCmd || g_VblankCmd); + + sioprintf("kill handlers"); + DisableIntc(INT_VBLANK_START); + DisableIntc(INT_VBLANK_END); + DisableDmac(2); + RemoveIntcHandler(INT_VBLANK_START, _vblankStartId); + RemoveIntcHandler(INT_VBLANK_END, _vblankEndId); + RemoveDmacHandler(2, _dmacId); + + DeleteSema(g_VblankSema); + DeleteSema(g_DmacSema); + DeleteSema(g_AnimSema); } void Gs2dScreen::createAnimTextures(void) { - uint8 *buf = (uint8*)memalign(64, 14 * 64); + uint8 *buf = (uint8*)memalign(64, 16 * 64); + memset(buf, 0, 16 * 64); uint32 vramDest = _texPtrs[TEXT]; for (int i = 0; i < 16; i++) { uint32 *destPos = (uint32*)buf; @@ -223,9 +273,9 @@ void Gs2dScreen::createAnimTextures(void) { destPos++; } if (!(i & 1)) - _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HH, buf, 128, 14); + _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HH, buf, 128, 16); else { - _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HL, buf, 128, 14); + _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HL, buf, 128, 16); vramDest += 128 * 16 * 4; } _dmaPipe->flush(); @@ -244,7 +294,6 @@ void Gs2dScreen::newScreenSize(uint16 width, uint16 height) { WaitSema(g_VblankSema); _dmaPipe->flush(); - _screenChanged = _overlayChanged = false; _width = width; _height = height; _pitch = (width + 127) & ~127; @@ -277,16 +326,41 @@ void Gs2dScreen::newScreenSize(uint16 width, uint16 height) { SignalSema(g_DmacSema); } -void Gs2dScreen::copyScreenRect(const uint8 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) { - assert((x + w <= _width) && (y + h <= _height)); +void Gs2dScreen::copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w, int h) { + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + if (y < 0) { + h += y; + buf -= y * pitch; + y = 0; + } + if (x + w > _width) + w = (int)_width - x; + if (y + h > _height) + h = (int)_height - y; + + if ((w > 0) && (h > 0)) { + WaitSema(g_DmacSema); + uint8 *dest = _screenBuf + y * _width + x; + if ((w == pitch) && (pitch == _width)) + memcpy(dest, buf, w * h); + else + for (int cnt = 0; cnt < h; cnt++) { + memcpy(dest, buf, w); + buf += pitch; + dest += _width; + } + _screenChanged = true; + SignalSema(g_DmacSema); + } +} +void Gs2dScreen::clearScreen(void) { WaitSema(g_DmacSema); - uint8 *dest = _screenBuf + y * _width + x; - for (uint16 cnt = 0; cnt < h; cnt++) { - memcpy(dest, buf, w); - buf += pitch; - dest += _width; - } + memset(_screenBuf, 0, _width * _height); _screenChanged = true; SignalSema(g_DmacSema); } @@ -313,9 +387,15 @@ void Gs2dScreen::grabPalette(uint32 *pal, uint8 start, uint16 num) { } } -void Gs2dScreen::updateScreen(void) { - WaitSema(_screenSema); +void Gs2dScreen::grabScreen(Graphics::Surface *surf) { + assert(surf); + WaitSema(g_DmacSema); + surf->create(_width, _height, 1); + memcpy(surf->pixels, _screenBuf, _width * _height); + SignalSema(g_DmacSema); +} +void Gs2dScreen::uploadToVram(void) { if (_clutChanged) { _clutChanged = false; uint32 tmp = _clut[_mTraCol]; @@ -328,43 +408,73 @@ void Gs2dScreen::updateScreen(void) { _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); } - _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen - if (_showOverlay) { if (_overlayChanged) { _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height); _overlayChanged = false; } - _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); - _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); } else { if (_screenChanged) { _dmaPipe->uploadTex(_texPtrs[SCREEN], _pitch, 0, 0, GS_PSMT8, _screenBuf, _width, _height); _screenChanged = false; } - _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); - _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); } +} - if (_showMouse) { - GsVertex mouseCoords[2]; - mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; - mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; - mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); - mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); - mouseCoords[0].z = mouseCoords[1].z = 0; +extern "C" void _ps2sdk_alloc_lock(void); +extern "C" void _ps2sdk_alloc_unlock(void); - _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); - _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); - } +void Gs2dScreen::updateScreen(void) { + WaitSema(_screenSema); + uploadToVram(); + if (!g_RunAnim) { + _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen + + if (_showOverlay) { + _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); + } else { + _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); + } - WaitSema(g_DmacSema); // wait for dma transfer, if there's one running - WaitSema(g_VblankSema); // wait if there's already an image waiting for vblank + if (_showMouse) { + GsVertex mouseCoords[2]; + mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; + mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; + mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); + mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); + mouseCoords[0].z = mouseCoords[1].z = 0; - g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler - _dmaPipe->flush(); - _curDrawBuf ^= 1; - _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); + } + + _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1); + +#if 0 + _ps2sdk_alloc_lock(); + uint32 heapTop = (uint32)ps2_sbrk(0); + _ps2sdk_alloc_unlock(); + if (heapTop != (uint32)-1) { + float yPos = (((float)heapTop) / (32 * 1024 * 1024)) * _tvHeight; + GsVertex bottom = { SCALE(_tvWidth - 40) + ORIGIN_X, SCALE(_tvHeight) + ORIGIN_Y, 0 }; + GsVertex top = { SCALE(_tvWidth) + ORIGIN_X, 0, 0 }; + top.y = SCALE((uint16)(_tvHeight - yPos)) + ORIGIN_Y; + _dmaPipe->flatRect(&bottom, &top, GS_RGBA(0x80, 0, 0, 0x40)); + } +#endif + + WaitSema(g_DmacSema); // wait for dma transfer, if there's one running + WaitSema(g_VblankSema); // wait if there's already an image waiting for vblank + + g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler + _dmaPipe->flush(); + _curDrawBuf ^= 1; + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + } else + _dmaPipe->flush(); SignalSema(_screenSema); } @@ -384,6 +494,22 @@ void Gs2dScreen::setShakePos(int shake) { _blitCoords[1].y = SCALE(_tvHeight + _shakePos) + ORIGIN_Y; } +void Gs2dScreen::copyPrintfOverlay(const uint8 *buf) { + assert(!((uint32)buf & 63)); + _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, buf, 320, 200); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); +} + +void Gs2dScreen::clearPrintfOverlay(void) { + uint8 *tmpBuf = (uint8*)memalign(64, 320 * 200); + memset(tmpBuf, 4, 320 * 200); + _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, tmpBuf, 320, 200); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + free(tmpBuf); +} + void Gs2dScreen::copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) { WaitSema(g_DmacSema); _overlayChanged = true; @@ -406,7 +532,7 @@ void Gs2dScreen::clearOverlay(void) { palette[cnt] = ((rgba >> 3) & 0x1F) | (((rgba >> 11) & 0x1F) << 5) | (((rgba >> 19) & 0x1F) << 10); } // now copy the current screen over - for (uint32 cnt = 0; cnt < _width * _height; cnt++) + for (int cnt = 0; cnt < _width * _height; cnt++) _overlayBuf[cnt] = palette[_screenBuf[cnt]]; SignalSema(g_DmacSema); } @@ -453,6 +579,14 @@ uint8 Gs2dScreen::tvMode(void) { return _videoMode; } +uint16 Gs2dScreen::getWidth(void) { + return _width; +} + +uint16 Gs2dScreen::getHeight(void) { + return _height; +} + void Gs2dScreen::wantAnim(bool runIt) { g_RunAnim = runIt; } @@ -475,10 +609,13 @@ void Gs2dScreen::animThread(void) { }; float angleStep = ((2 * PI) / _tvHeight); - while (1) { + while (!_systemQuit) { do { WaitSema(g_AnimSema); - } while (!g_RunAnim); + } while ((!_systemQuit) && (!g_RunAnim)); + + if (_systemQuit) + break; if (PollSema(_screenSema) > 0) { // make sure no thread is currently drawing WaitSema(g_DmacSema); // dma transfers have to be finished @@ -495,6 +632,21 @@ void Gs2dScreen::animThread(void) { _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); } + _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1); + + if (_showMouse) { + GsVertex mouseCoords[2]; + mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; + mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; + mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); + mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); + mouseCoords[0].z = mouseCoords[1].z = 0; + + _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); + } + _dmaPipe->setAlphaBlend(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0); yPos -= scrlSpeed; if (yPos <= -LINE_SPACE) { @@ -530,9 +682,9 @@ void Gs2dScreen::animThread(void) { uint32 texPtr = _texPtrs[TEXT] + 128 * 16 * 4 * (texIdx >> 1); if (texIdx & 1) - _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); else - _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); _dmaPipe->textureRect(nodes + 0, nodes + 1, nodes + 2, nodes + 3, texNodes + 0, texNodes + 1, texNodes + 2, texNodes + 3, GS_RGBA(0x80, 0x80, 0x80, 0x80)); @@ -548,31 +700,13 @@ void Gs2dScreen::animThread(void) { SignalSema(_screenSema); } } + ExitThread(); } void runAnimThread(Gs2dScreen *param) { param->animThread(); } -#define ANIM_STACK_SIZE (1024 * 32) - -void createAnimThread(Gs2dScreen *screen) { - ee_thread_t animThread, thisThread; - ReferThreadStatus(GetThreadId(), &thisThread); - - animThread.initial_priority = thisThread.current_priority - 3; - animThread.stack = malloc(ANIM_STACK_SIZE); - animThread.stack_size = ANIM_STACK_SIZE; - animThread.func = (void *)runAnimThread; - asm("move %0, $gp\n": "=r"(animThread.gp_reg)); - - int tid = CreateThread(&animThread); - if (tid >= 0) { - StartThread(tid, screen); - } else - free(animThread.stack); -} - // data for the animated zeros and ones... const uint8 Gs2dScreen::_binaryData[4 * 14 * 2] = { // figure zero @@ -600,9 +734,12 @@ const uint32 Gs2dScreen::_binaryClut[16] __attribute__((aligned(64))) = { GS_RGBA( 204, 204, 0xFF, 0x40), GS_RGBA( 140, 140, 0xFF, 0x40), - GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), - GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), - GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), + GS_RGBA( 0, 0, 0, 0x80), // scrPrintf: transparent + GS_RGBA( 0, 0, 0, 0x20), // scrPrintf: semitransparent + GS_RGBA(0xC0, 0xC0, 0xC0, 0), // scrPrintf: red + GS_RGBA(0x16, 0x16, 0xF0, 0), // scrPrintf: blue + + GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), // unused GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80) diff --git a/backends/ps2/Gs2dScreen.h b/backends/ps2/Gs2dScreen.h index 944cdec314..23969ec1df 100644 --- a/backends/ps2/Gs2dScreen.h +++ b/backends/ps2/Gs2dScreen.h @@ -36,17 +36,29 @@ enum GsInterlace { GS_INTERLACED }; + +namespace Graphics { + struct Surface; +} + class Gs2dScreen { public: Gs2dScreen(uint16 width, uint16 height, TVMode tvMode); ~Gs2dScreen(void); void newScreenSize(uint16 width, uint16 height); uint8 tvMode(void); + uint16 getWidth(void); + uint16 getHeight(void); - void copyScreenRect(const uint8 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h); + void copyPrintfOverlay(const uint8* buf); + void clearPrintfOverlay(void); + void clearScreen(void); + + void copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w, int h); void setPalette(const uint32 *pal, uint8 start, uint16 num); - void grabPalette(uint32 *pal, uint8 start, uint16 num); void updateScreen(void); + void grabPalette(uint32 *pal, uint8 start, uint16 num); + void grabScreen(Graphics::Surface *surf); //- overlay routines void copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h); void grabOverlay(uint16 *buf, uint16 pitch); @@ -61,7 +73,10 @@ public: void animThread(void); void wantAnim(bool runIt); + + void quit(void); private: + void uploadToVram(void); void createAnimTextures(void); DmaPipe *_dmaPipe; @@ -73,7 +88,7 @@ private: uint8 _curDrawBuf; uint32 _frameBufPtr[2]; // uint32 _clutPtrs[3]; // vram pointers - uint32 _texPtrs[3]; // + uint32 _texPtrs[4]; // uint16 _width, _height, _pitch; int16 _mouseX, _mouseY, _hotSpotX, _hotSpotY; @@ -88,6 +103,10 @@ private: uint32 *_clut; int _screenSema; + int _vblankStartId, _vblankEndId, _dmacId, _animTid; + void *_animStack; + volatile bool _systemQuit; + static const uint32 _binaryClut[16]; static const uint8 _binaryData[4 * 14 * 2]; static const uint16 _binaryPattern[16]; diff --git a/backends/ps2/READ_PS2.TXT b/backends/ps2/READ_PS2.TXT new file mode 100644 index 0000000000..29a53e5ba9 --- /dev/null +++ b/backends/ps2/READ_PS2.TXT @@ -0,0 +1,68 @@ +ScummVM-PS2 Readme +================== + +You need a Playstation2 with a modchip of your choice in order to run ScummVM. + +ScummVM expects the game data on the CD-R, other devices like USB sticks + and HDD are currently unsupported. + +In order to use a USB Mouse and USB Keyboard, you need Sony's USB driver, + the USBD.IRX. Copy it from a PS2 game that supports USB devices, like + Eye Toy or Singstar. +The demo disc that came with my PS2 also had it. + Put it into the directory in which you extracted the .zip file. +You can also use ScummVM without the USB driver but you can only use the + Gamepad in that case. + + +Creating a CD-R using CD-Tool +============================= +Copy any games you want on the CD over into the directory where you extracted + the ZIP file. Don't copy any files directly into the directory of the + ScummVM.ELF, those files are ignored. Instead, have each game in its own + directory. +File- and directorynames should be DOS 8+3, if they aren't, they'll get + renamed. + +If you run windows, just double click the make_iso.bat. +Wait while it creates the ISO image and burn it with Nero +or any other CD writing software. + +For Linux or Mac OS X binaries check http://www.nobis-crew.org/cd-tool/ + +Unfortunately, writing DVD images with cd-tool is currently broken and will + crash when it reaches the 2GB limit. This problem will probably be fixed in + the nearer future. + + +Notes +===== +- CD swapping doesn't work, unfortunately. So you should have all games + on the CD you booted from. +- Curse of Monkey Island is unsupported. iMuse digital crashes often, + especially during Sea battles. +- Zlib is unsupported, so compressed SAN files won't work. +- The cd/dvd drive is a bottleneck, that's why you should compress the games + with MP3 or Ogg/Vorbis using compress_scumm_sou / compress_scumm_bun / + compress_sword1 / compress_sword2 etc, but *not* compress_san as it + requires zlib. Besides, uncompressed SAN files play fine. +- I haven't had time to implement a virtual keyboard. If you don't have a USB + keyboard, you can only enter '1's using the Select button. +- When you see '1's and '0's flying across your screen, it means ScummVM is + accessing the Memory Card. Don't switch off or reset the console in that + case, and don't remove the Memory Card either :P + + +GamePad +======= +Start Button - F5 +Select Button - Figure 1 +L1 - 'n' +R1 - 'y' +L2 - Numpad 0 +Triangle - Escape +Square - Enter +Cross - Left mouse button +Circle - Right mouse button +Left analog stick - Mouse. Disabled when USB mouse is detected. + diff --git a/backends/ps2/asyncfio.cpp b/backends/ps2/asyncfio.cpp index b621db8657..724cb052ef 100644 --- a/backends/ps2/asyncfio.cpp +++ b/backends/ps2/asyncfio.cpp @@ -51,6 +51,8 @@ int AsyncFio::open(const char *name, int ioMode) { fileXioOpen(name, ioMode, DEFAULT_MODE); fileXioWaitAsync(FXIO_WAIT, &res); SignalSema(_ioSema); + if (res < -2) + printf("File %s error: %d (mode %d)\n", name, res, ioMode); return res; } @@ -60,10 +62,8 @@ void AsyncFio::close(int handle) { fileXioClose(handle); int res; fileXioWaitAsync(FXIO_WAIT, &res); - if (res != 0) { + if (res != 0) sioprintf("ERROR: fileXioClose failed, EC %d", res); - SleepThread(); - } _ioSlots[handle] = 0; SignalSema(_ioSema); } diff --git a/backends/ps2/fileio.cpp b/backends/ps2/fileio.cpp index d92989614b..f9443d6153 100644 --- a/backends/ps2/fileio.cpp +++ b/backends/ps2/fileio.cpp @@ -36,6 +36,8 @@ #define MAX_CACHED_FILES 6 #define CACHE_READ_THRESHOLD (16 * 2048) #define CACHE_FILL_MIN (2048 * 24) +#define READ_ALIGN 64 // align all reads to the size of an EE cache line +#define READ_ALIGN_MASK (READ_ALIGN - 1) extern void sioprintf(const char *zFormat, ...); @@ -50,7 +52,7 @@ Ps2File::~Ps2File(void) { class Ps2ReadFile : public Ps2File { public: - Ps2ReadFile(int64 cacheId); + Ps2ReadFile(int64 cacheId, bool stream); virtual ~Ps2ReadFile(void); virtual bool open(const char *name); virtual uint32 read(void *dest, uint32 len); @@ -69,9 +71,10 @@ private: uint32 _fileSize, _bytesInCache, _cacheOfs; uint32 _readBytesBlock; + bool _stream; }; -Ps2ReadFile::Ps2ReadFile(int64 cacheId) : Ps2File(cacheId) { +Ps2ReadFile::Ps2ReadFile(int64 cacheId, bool stream) : Ps2File(cacheId) { _fd = -1; _cacheBuf = (uint8*)memalign(64, CACHE_SIZE); @@ -80,6 +83,7 @@ Ps2ReadFile::Ps2ReadFile(int64 cacheId) : Ps2File(cacheId) { _fileSize = _bytesInCache = _cacheOfs = 0; _cacheOpRunning = false; _readBytesBlock = 0; + _stream = stream; ee_sema_t newSema; newSema.init_count = 1; @@ -147,7 +151,7 @@ int Ps2ReadFile::seek(int32 offset, int origin) { seekDest = -1; break; } - if ((seekDest >= 0) && (seekDest <= _fileSize)) { + if ((seekDest >= 0) && (seekDest <= (int)_fileSize)) { _filePos = seekDest; res = 0; } @@ -161,7 +165,7 @@ void Ps2ReadFile::cacheReadAhead(void) { if (fio.poll(_fd)) // did it finish? cacheReadSync(); // yes. } - if ((!_cacheOpRunning) && (_readBytesBlock >= CACHE_READ_THRESHOLD) && fio.fioAvail()) { + if ((!_cacheOpRunning) && ((_readBytesBlock >= CACHE_READ_THRESHOLD) || _stream) && fio.fioAvail()) { // the engine seems to do sequential reads and there are no other I/Os going on. read ahead. uint32 cachePosEnd = _cachePos + _bytesInCache; @@ -176,11 +180,12 @@ void Ps2ReadFile::cacheReadAhead(void) { if (_cachePos + _bytesInCache <= _filePos) { _cacheOfs = _bytesInCache = 0; - _cachePos = cachePosEnd = _filePos; + _cachePos = cachePosEnd = _filePos & ~READ_ALIGN_MASK; assert(_filePos == _physFilePos); } else { uint32 cacheDiff = _filePos - _cachePos; assert(_bytesInCache >= cacheDiff); + cacheDiff &= ~READ_ALIGN_MASK; _bytesInCache -= cacheDiff; _cachePos += cacheDiff; _cacheOfs = (_cacheOfs + cacheDiff) % CACHE_SIZE; @@ -188,6 +193,7 @@ void Ps2ReadFile::cacheReadAhead(void) { if (_physFilePos != cachePosEnd) { sioprintf("unexpected _physFilePos %d cache %d %d", _physFilePos, _cacheOfs, _bytesInCache); + assert(!(cachePosEnd & READ_ALIGN_MASK)); _physFilePos = fio.seek(_fd, cachePosEnd, SEEK_SET); if (_physFilePos != cachePosEnd) { sioprintf("cache seek error: seek to %d instead of %d, fs = %d", _physFilePos, cachePosEnd, _fileSize); @@ -202,7 +208,7 @@ void Ps2ReadFile::cacheReadAhead(void) { if (cacheRead > MAX_READ_STEP) cacheRead = MAX_READ_STEP; - assert(cacheRead); + assert((!(cacheRead & READ_ALIGN_MASK)) && cacheRead); _cacheOpRunning = true; fio.read(_fd, _cacheBuf + cacheDest, cacheRead); @@ -225,7 +231,7 @@ uint32 Ps2ReadFile::read(void *dest, uint32 len) { if ((_filePos < _cachePos) || (_filePos + len > _cachePos + _bytesInCache)) cacheReadSync(); // we have to read from CD, sync cache. - while (len) { + while (len && (_filePos != _fileSize)) { if ((_filePos >= _cachePos) && (_filePos < _cachePos + _bytesInCache)) { // read from cache uint32 staPos = (_cacheOfs + (_filePos - _cachePos)) % CACHE_SIZE; uint32 cpyLen = _bytesInCache - (_filePos - _cachePos); @@ -246,21 +252,24 @@ uint32 Ps2ReadFile::read(void *dest, uint32 len) { if ((_filePos < _physFilePos) || (_filePos > _physFilePos + (CACHE_SIZE / 2))) _readBytesBlock = 0; // reset cache hit count - if (fio.seek(_fd, _filePos, SEEK_SET) == _filePos) - _physFilePos = _filePos; - else + _physFilePos = _filePos & ~READ_ALIGN_MASK; + if (fio.seek(_fd, _physFilePos, SEEK_SET) != (int)_physFilePos) break; // read beyond EOF } - assert(_physFilePos == _filePos); - int doRead = (len > MAX_READ_STEP) ? MAX_READ_STEP : len; + + int doRead = len + (_filePos - _physFilePos); + doRead = (doRead + READ_ALIGN_MASK) & ~READ_ALIGN_MASK; + + if (doRead > MAX_READ_STEP) + doRead = MAX_READ_STEP; if (doRead < 2048) doRead = 2048; fio.read(_fd, _cacheBuf, doRead); - _cachePos = _filePos; + _cachePos = _physFilePos; _cacheOfs = 0; _bytesInCache = fio.sync(_fd); - _physFilePos = _filePos + _bytesInCache; + _physFilePos += _bytesInCache; if (!_bytesInCache) break; // EOF } @@ -303,7 +312,7 @@ Ps2WriteFile::~Ps2WriteFile(void) { if ((_fd >= 0) && (_bytesInCache)) { fio.write(_fd, _cacheBuf, _bytesInCache); int wrRes = fio.sync(_fd); - if (wrRes != _bytesInCache) // too late to return an error + if (wrRes != (int)_bytesInCache) // too late to return an error printf("Cache flush on fclose(): Unable to write %d cached bytes to mc, only %d bytes written\n", _bytesInCache, wrRes); } if (_fd >= 0) @@ -336,8 +345,7 @@ uint32 Ps2WriteFile::write(const void *src, uint32 len) { if (_bytesInCache == CACHE_SIZE) { fio.write(_fd, _cacheBuf, _bytesInCache); - int wrRes = fio.sync(_fd); - if (wrRes != _bytesInCache) { + if (fio.sync(_fd) != (int)_bytesInCache) { printf("Unable to flush %d cached bytes to memory card!\n", _bytesInCache); return 0; } @@ -426,17 +434,12 @@ FILE *ps2_fopen(const char *fname, const char *mode) { if (cacheId != 0) { Ps2File *file = findInCache(cacheId); - if (file) { - //sioprintf("open from cache: %s (%d) [%d]\n", fname, cacheId, file->_handle->_handle); + if (file) return (FILE*)file; - } if (rdOnly) { - // smush files need a quite different caching behaviour than normal data files - if (strstr(fname, ".san") || strstr(fname, ".SAN") || strstr(fname, ".San")) - file = new Ps2SmushFile(cacheId); - else - file = new Ps2ReadFile(cacheId); + bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun"); + file = new Ps2ReadFile(cacheId, isAudioFile); } else file = new Ps2WriteFile(cacheId); @@ -453,10 +456,17 @@ void checkCacheListLen(void) { while ((cacheListLen > MAX_CACHED_FILES) || ((openFileCount > 13) && cacheListLen)) { assert(cacheListEnd && cacheListStart); delete cacheListEnd->file; - cacheListEnd->prev->next = NULL; - FioHandleCache *temp = cacheListEnd; - cacheListEnd = cacheListEnd->prev; - delete temp; + if (cacheListEnd->prev) { + cacheListEnd->prev->next = NULL; + FioHandleCache *temp = cacheListEnd; + cacheListEnd = cacheListEnd->prev; + delete temp; + } else { + assert(cacheListEnd == cacheListStart); + assert(cacheListLen == 1); + delete cacheListEnd; + cacheListEnd = cacheListStart = NULL; + } cacheListLen--; openFileCount--; } @@ -595,7 +605,7 @@ int ps2_fputc(int c, FILE *stream) { int ps2_fputs(const char *s, FILE *stream) { int len = strlen(s); - if (ps2_fwrite(s, 1, len, stream) == len) + if (ps2_fwrite(s, 1, len, stream) == (size_t)len) return len; else return EOF; @@ -657,8 +667,6 @@ void TocManager::readDir(const char *path, TocNode **node, int level) { } int64 TocManager::fileExists(const char *name) { - const char *tmpName = name; - if (((name[_rootLen] != '/') && (name[_rootLen] != '\0')) || (strnicmp(name, _root, _rootLen) != 0)) { for (int i = 0; i < 8; i++) if (name[i] == ':') // we don't know the content of other drives, diff --git a/backends/ps2/ps2input.cpp b/backends/ps2/ps2input.cpp index 4189ac9035..ce050f2506 100644 --- a/backends/ps2/ps2input.cpp +++ b/backends/ps2/ps2input.cpp @@ -235,11 +235,11 @@ bool Ps2Input::getKeyEvent(OSystem::Event *event, uint16 buttonCode, bool down) entry++; buttonCode >>= 1; } - if (_asciiCodes[entry] || _keyCodes[entry]) { + if (_padCodes[entry]) { event->type = (down) ? OSystem::EVENT_KEYDOWN : OSystem::EVENT_KEYUP; - event->kbd.ascii = _asciiCodes[entry]; - event->kbd.keycode = _keyCodes[entry]; - event->kbd.flags = 0; + event->kbd.keycode = _padCodes[entry]; + event->kbd.flags = _padFlags[entry]; + event->kbd.ascii = mapKey(_padCodes[entry], _padFlags[entry]); return true; } } @@ -505,41 +505,42 @@ const int Ps2Input::_usbToSdlk[0x100] = { /* FF */ 0 }; -const int Ps2Input::_keyCodes[16] = { - 49, // '1' - Select - 0, // - L3 - 0, // - R3 - 286, // F5 - Start - 0, // - Up - 0, // - Right - 0, // - Down - 0, // - Left - 0, // - L2 - 0, // - R2 - 0, // - L1 - 0, // - R1 - 27, // Esc - Triangle - 0, // - Circle - 0, // - Cross - 0, // - Square +const int Ps2Input::_padCodes[16] = { + SDLK_1, // Select + 0, // L3 + 0, // R3 + SDLK_F5, // Start + 0, // Up + 0, // Right + 0, // Down + 0, // Left + SDLK_KP0, // L2 + 0, // R2 + SDLK_n, // L1 + SDLK_y, // R1 + SDLK_ESCAPE, // Triangle + 0, // Circle => Right mouse button + 0, // Cross => Left mouse button + SDLK_RETURN // Square }; -const uint16 Ps2Input::_asciiCodes[16] = { - 49, // '1' - Select - 0, // - L3 - 0, // - R3 - 319, // F5 - Start - 0, // - Up - 0, // - Right - 0, // - Down - 0, // - Left - 0, // - L2 - 0, // - R2 - 0, // - L1 - 0, // - R1 - 27, // Esc - Triangle - 0, // - Circle - 0, // - Cross - 0, // - Square +const int Ps2Input::_padFlags[16] = { + 0, // Select + 0, // L3 + 0, // R3 + 0, // Start + 0, // Up + 0, // Right + 0, // Down + 0, // Left + 0, // L2 + 0, // R2 + 0, // L1 + 0, // R1 + 0, // Triangle + 0, // Circle + 0, // Cross + 0 // Square }; + diff --git a/backends/ps2/ps2input.h b/backends/ps2/ps2input.h index 6f166d14eb..3735889d98 100644 --- a/backends/ps2/ps2input.h +++ b/backends/ps2/ps2input.h @@ -50,8 +50,7 @@ private: bool _mouseLoaded, _kbdLoaded; int _keyFlags; - static const int _keyCodes[16]; - static const uint16 _asciiCodes[16]; + static const int _padCodes[16], _padFlags[16]; static const int _usbToSdlk[0x100]; }; diff --git a/backends/ps2/ps2pad.cpp b/backends/ps2/ps2pad.cpp index 8dd18c7db5..ef5bb60603 100644 --- a/backends/ps2/ps2pad.cpp +++ b/backends/ps2/ps2pad.cpp @@ -97,6 +97,9 @@ void Ps2Pad::initPad(void) { case STAT_WAIT_READY: _padStatus = STAT_OKAY; break; + case STAT_OKAY: + // pad is already initialized + break; } } else { // check for timeout... diff --git a/backends/ps2/savefile.cpp b/backends/ps2/savefile.cpp index a7b3e25f33..d970832cc3 100644 --- a/backends/ps2/savefile.cpp +++ b/backends/ps2/savefile.cpp @@ -26,33 +26,148 @@ #include <fileio.h> #include <malloc.h> #include <ucl/ucl.h> +#include <libmc.h> #include "backends/ps2/savefile.h" #include "backends/ps2/Gs2dScreen.h" -#include "backends/ps2/asyncfio.h" #include "backends/ps2/systemps2.h" #include "common/scummsys.h" -extern AsyncFio fio; +#define UCL_MAGIC 0x314C4355 + +#define PORT 0 +#define SLOT 0 +// port 0, slot 0: memory card in first slot. + +void sioprintf(const char *zFormat, ...); + +class McAccess { +public: + McAccess(int port, int slot); + ~McAccess(void); + int open(const char *name, int mode); + int close(int fd); + int size(int fd); + int read(int fd, void *buf, int size); + int write(int fd, const void *buf, int size); + int mkDir(const char *name); + int getDir(const char *name, unsigned int mode, int max, void *dest); + int getInfo(int *type, int *free, int *format); +private: + int _sema; + int _port, _slot; +}; + +McAccess::McAccess(int port, int slot) { + _port = port; + _slot = slot; + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _sema = CreateSema(&newSema); + + assert(mcInit(MC_TYPE_MC) >= 0); +} + +McAccess::~McAccess(void) { + DeleteSema(_sema); +} + +int McAccess::open(const char *name, int mode) { + int res; + WaitSema(_sema); + mcOpen(_port, _slot, name, mode); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::close(int fd) { + int res; + WaitSema(_sema); + mcClose(fd); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::size(int fd) { + int res, size; + WaitSema(_sema); + mcSeek(fd, 0, SEEK_END); + mcSync(0, NULL, &size); + mcSeek(fd, 0, SEEK_SET); + mcSync(0, NULL, &res); + SignalSema(_sema); + assert(res == 0); + return size; +} + +int McAccess::read(int fd, void *buf, int size) { + int res; + WaitSema(_sema); + mcRead(fd, buf, size); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::write(int fd, const void *buf, int size) { + int res; + WaitSema(_sema); + mcWrite(fd, buf, size); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::mkDir(const char *name) { + int res; + WaitSema(_sema); + mcMkDir(_port, _slot, name); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::getDir(const char *name, unsigned int mode, int max, void *dest) { + int res; + WaitSema(_sema); + mcGetDir(_port, _slot, name, mode, max, (mcTable*)dest); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::getInfo(int *type, int *free, int *format) { + int res; + WaitSema(_sema); + mcGetInfo(_port, _slot, type, free, format); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} class UclOutSaveFile : public Common::OutSaveFile { public: - UclOutSaveFile(const char *filename, Gs2dScreen *screen); + UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc); virtual ~UclOutSaveFile(void); virtual uint32 write(const void *ptr, uint32 size); - virtual int flush(void); + virtual void flush(void); virtual bool ioFailed(void); virtual void clearIOFailed(void); private: + OSystem_PS2 *_system; Gs2dScreen *_screen; + McAccess *_mc; int _fd; uint8 *_buf; uint32 _bufSize, _bufPos; - bool _ioFailed; + bool _ioFailed, _wasFlushed; }; class UclInSaveFile : public Common::InSaveFile { public: - UclInSaveFile(const char *filename, Gs2dScreen *screen); + UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mc); virtual ~UclInSaveFile(void); virtual bool eos(void) const; virtual uint32 read(void *ptr, uint32 size); @@ -61,32 +176,74 @@ public: virtual void skip(uint32 offset); private: Gs2dScreen *_screen; + McAccess *_mc; uint8 *_buf; uint32 _bufSize, _bufPos; bool _ioFailed; }; +class AutoSaveFile : public Common::OutSaveFile { +public: + AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename); + ~AutoSaveFile(void); + virtual uint32 write(const void *ptr, uint32 size); + virtual void flush(void) { }; + virtual bool ioFailed(void) { return false; }; + virtual void clearIOFailed(void) {}; +private: + Ps2SaveFileManager *_saveMan; + char _fileName[256]; + uint8 *_buf; + uint32 _bufSize, _bufPos; +}; + +AutoSaveFile::AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename) { + strcpy(_fileName, filename); + _saveMan = saveMan; + _bufSize = 65536; + _buf = (uint8*)memalign(64, _bufSize); + _bufPos = 0; +} + +AutoSaveFile::~AutoSaveFile(void) { + _saveMan->writeSaveNonblocking(_fileName, _buf, _bufPos); + free(_buf); +} + +uint32 AutoSaveFile::write(const void *ptr, uint32 size) { + uint32 bytesFree = _bufSize - _bufPos; + if (bytesFree < size) { + uint32 allocBytes = (size > 32 * 1024) ? size : 32 * 1024; + _bufSize += allocBytes; + _buf = (uint8*)realloc(_buf, _bufSize); + bytesFree = _bufSize - _bufPos; + } + memcpy(_buf + _bufPos, ptr, size); + _bufPos += size; + return size; +} + #define MAX_MC_ENTRIES 16 +void runSaveThread(Ps2SaveFileManager *param); + Ps2SaveFileManager::Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen) { _system = system; _screen = screen; - assert(mcInit(MC_TYPE_MC) >= 0); + _mc = new McAccess(0, 0); _mcDirList = (mcTable*)memalign(64, MAX_MC_ENTRIES * sizeof(mcTable)); _mcDirName[0] = '\0'; _mcCheckTime = 0; _mcNeedsUpdate = true; - int mcCheckCount; - int res = -10; for (int mcCheckCount = 0; mcCheckCount < 3; mcCheckCount++) { /* retry mcGetInfo 3 times. It slows down startup without mc considerably, but cheap 3rd party memory cards apparently fail to get detected once in a while */ - int mcType, mcFree, mcFormat, res; - mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); - mcSync(0, NULL, &res); + int mcType, mcFree, mcFormat; + int res = _mc->getInfo(&mcType, &mcFree, &mcFormat); + if ((res == 0) || (res == -1)) { // mc okay _mcPresent = true; printf("MC okay, result = %d. Type %d, Free %d, Format %d\n", res, mcType, mcFree, mcFormat); @@ -97,6 +254,29 @@ Ps2SaveFileManager::Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen) printf("MC failed, not present or not formatted, code %d\n", res); } } + + // create save thread + ee_sema_t newSema; + newSema.init_count = 0; + newSema.max_count = 1; + _autoSaveSignal = CreateSema(&newSema); + _autoSaveBuf = NULL; + _autoSaveSize = 0; + _systemQuit = false; + + ee_thread_t saveThread, thisThread; + ReferThreadStatus(GetThreadId(), &thisThread); + + saveThread.initial_priority = thisThread.current_priority + 1; + saveThread.stack_size = 8 * 1024; + _autoSaveStack = malloc(saveThread.stack_size); + saveThread.stack = _autoSaveStack; + saveThread.func = (void *)runSaveThread; + asm("move %0, $gp\n": "=r"(saveThread.gp_reg)); + + _autoSaveTid = CreateThread(&saveThread); + assert(_autoSaveTid >= 0); + StartThread(_autoSaveTid, this); } Ps2SaveFileManager::~Ps2SaveFileManager(void) { @@ -104,25 +284,28 @@ Ps2SaveFileManager::~Ps2SaveFileManager(void) { void Ps2SaveFileManager::checkMainDirectory(void) { // verify that the main directory (scummvm config + icon) exists - int ret; - mcGetDir(0, 0, "/ScummVM/*", 0, MAX_MC_ENTRIES, _mcDirList); - mcSync(0, NULL, &ret); + int ret, fd; + _mcNeedsUpdate = true; + ret = _mc->getDir("/ScummVM/*", 0, MAX_MC_ENTRIES, _mcDirList); printf("/ScummVM/* res = %d\n", ret); if (ret <= 0) { // assume directory doesn't exist printf("Dir doesn't exist\n"); - fio.mkdir("mc0:ScummVM"); - int fd = fio.open("mc0:ScummVM/scummvm.icn", O_WRONLY | O_CREAT | O_TRUNC); - if (fd >= 0) { - uint16 icoSize; - uint16 *icoBuf = decompressIconData(&icoSize); - fio.write(fd, icoBuf, icoSize * 2); - fio.sync(fd); - free(icoBuf); - fio.close(fd); - printf(".icn written\n"); - setupIcon("mc0:ScummVM/icon.sys", "scummvm.icn", "ScummVM", "Configuration"); + ret = _mc->mkDir("/ScummVM"); + if (ret >= 0) { + fd = _mc->open("/ScummVM/scummvm.icn", O_WRONLY | O_CREAT); + if (fd >= 0) { + uint16 icoSize; + uint16 *icoBuf = decompressIconData(&icoSize); + ret = _mc->write(fd, icoBuf, icoSize * 2); + _mc->close(fd); + free(icoBuf); + + printf(".icn written\n"); + setupIcon("/ScummVM/icon.sys", "scummvm.icn", "ScummVM", "Configuration"); + } else + printf("Can't create icon file: %d\n", fd); } else - printf("unable to write icon data\n"); + printf("can't create scummvm directory: %d\n", ret); } } @@ -140,30 +323,31 @@ void Ps2SaveFileManager::splitPath(const char *fileName, char *dir, char *name) } bool Ps2SaveFileManager::mcReadyForDir(const char *dir) { - if (_mcNeedsUpdate || ((_system->getMillis() - _mcCheckTime) > 1000) || !_mcPresent) { + if (_mcNeedsUpdate || ((_system->getMillis() - _mcCheckTime) > 2000) || !_mcPresent) { // check if memory card was exchanged/removed in the meantime int mcType, mcFree, mcFormat, mcResult; - mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); - mcSync(0, NULL, &mcResult); + mcResult = _mc->getInfo(&mcType, &mcFree, &mcFormat); if (mcResult != 0) { // memory card was exchanged _mcNeedsUpdate = true; - if (mcResult != -1) { + if (mcResult == -1) { // yes, it was exchanged + checkMainDirectory(); // make sure ScummVM dir and icon are there + } else { // no memorycard in slot or not formatted or something like that _mcPresent = false; printf("MC not found, error code %d\n", mcResult); return false; } } _mcPresent = true; + _mcCheckTime = _system->getMillis(); } if (_mcNeedsUpdate || strcmp(_mcDirName, dir)) { strcpy(_mcDirName, dir); char dirStr[256]; sprintf(dirStr, "/ScummVM-%s/*", dir); - mcGetDir(0, 0, dirStr, 0, MAX_MC_ENTRIES, _mcDirList); - mcSync(0, NULL, &_mcEntries); - return (_mcEntries >= 0); - } else - return true; + _mcEntries = _mc->getDir(dirStr, 0, MAX_MC_ENTRIES, _mcDirList); + _mcNeedsUpdate = false; + } + return (_mcEntries >= 0); } Common::InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { @@ -178,12 +362,12 @@ Common::InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { fileExists = true; if (fileExists) { char fullName[256]; - sprintf(fullName, "mc0:ScummVM-%s/%s", dir, name); - UclInSaveFile *file = new UclInSaveFile(fullName, _screen); + sprintf(fullName, "/ScummVM-%s/%s", dir, name); + UclInSaveFile *file = new UclInSaveFile(fullName, _screen, _mc); if (file) { - if (!file->ioFailed()) { + if (!file->ioFailed()) return file; - } else + else delete file; } } else @@ -194,15 +378,17 @@ Common::InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { } Common::OutSaveFile *Ps2SaveFileManager::openForSaving(const char *filename) { - _screen->wantAnim(true); + int res; char dir[256], name[256]; + + _screen->wantAnim(true); splitPath(filename, dir, name); if (!mcReadyForDir(dir)) { if (_mcPresent) { // directory doesn't seem to exist yet char fullPath[256]; - sprintf(fullPath, "mc0:ScummVM-%s", dir); - fio.mkdir(fullPath); + sprintf(fullPath, "/ScummVM-%s", dir); + res = _mc->mkDir(fullPath); char icoSysDest[256], saveDesc[256]; sprintf(icoSysDest, "%s/icon.sys", fullPath); @@ -215,14 +401,20 @@ Common::OutSaveFile *Ps2SaveFileManager::openForSaving(const char *filename) { if (_mcPresent) { char fullPath[256]; - sprintf(fullPath, "mc0:ScummVM-%s/%s", dir, name); - UclOutSaveFile *file = new UclOutSaveFile(fullPath, _screen); - if (!file->ioFailed()) { - // we're creating a file, mc will have to be updated next time - _mcNeedsUpdate = true; + sprintf(fullPath, "/ScummVM-%s/%s", dir, name); + if (strstr(filename, ".s00") || strstr(filename, ".ASD") || strstr(filename, ".asd")) { + // this is an autosave + AutoSaveFile *file = new AutoSaveFile(this, fullPath); return file; - } else - delete file; + } else { + UclOutSaveFile *file = new UclOutSaveFile(fullPath, _system, _screen, _mc); + if (!file->ioFailed()) { + // we're creating a file, mc will have to be updated next time + _mcNeedsUpdate = true; + return file; + } else + delete file; + } } _screen->wantAnim(false); @@ -233,8 +425,7 @@ void Ps2SaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) _screen->wantAnim(true); int mcType, mcFree, mcFormat, mcResult; - mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); - mcSync(0, NULL, &mcResult); + mcResult = _mc->getInfo(&mcType, &mcFree, &mcFormat); memset(marks, false, num * sizeof(bool)); @@ -255,9 +446,7 @@ void Ps2SaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) ext[0] = '\0'; sprintf(mcSearchStr, "/ScummVM-%s/%s*", dirStr, ext); - int numEntries; - mcGetDir(0, 0, mcSearchStr, 0, MAX_MC_ENTRIES, mcEntries); - mcSync(0, NULL, &numEntries); + int numEntries = _mc->getDir(mcSearchStr, 0, MAX_MC_ENTRIES, mcEntries); int searchLen = strlen(ext); for (int i = 0; i < numEntries; i++) @@ -300,12 +489,12 @@ bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char strcpy((char*)icon_sys.copy, ico); strcpy((char*)icon_sys.del, ico); - int fd = fio.open(dest, O_WRONLY | O_CREAT | O_TRUNC); + int fd, res; + fd = _mc->open(dest, O_WRONLY | O_CREAT); if (fd >= 0) { - fio.write(fd, &icon_sys, sizeof(icon_sys)); - int res = fio.sync(fd); - fio.close(fd); - return (res == sizeof(icon_sys)); + res = _mc->write(fd, &icon_sys, sizeof(icon_sys)); + _mc->close(fd); + return (res == sizeof(icon_sys)); } else return false; } @@ -329,25 +518,77 @@ uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { return resData; } -UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen) { +void runSaveThread(Ps2SaveFileManager *param) { + param->saveThread(); +} + +void Ps2SaveFileManager::writeSaveNonblocking(char *name, void *buf, uint32 size) { + if (buf && size && !_systemQuit) { + strcpy(_autoSaveName, name); + assert(!_autoSaveBuf); + _autoSaveBuf = (uint8*)malloc(size); + memcpy(_autoSaveBuf, buf, size); + _autoSaveSize = size; + SignalSema(_autoSaveSignal); + } +} + +void Ps2SaveFileManager::saveThread(void) { + while (!_systemQuit) { + WaitSema(_autoSaveSignal); + if (_autoSaveBuf && _autoSaveSize) { + UclOutSaveFile *outSave = new UclOutSaveFile(_autoSaveName, _system, _screen, _mc); + if (!outSave->ioFailed()) { + outSave->write(_autoSaveBuf, _autoSaveSize); + outSave->flush(); + } + if (outSave->ioFailed()) + _system->msgPrintf(5000, "Writing autosave to %s failed", _autoSaveName); + delete outSave; + free(_autoSaveBuf); + _autoSaveBuf = NULL; + _autoSaveSize = 0; + _mcNeedsUpdate = true; // we've created a file, mc will have to be updated + _screen->wantAnim(false); + } + } + ExitThread(); +} + +void Ps2SaveFileManager::quit(void) { + _systemQuit = true; + ee_thread_t statSave, statThis; + ReferThreadStatus(GetThreadId(), &statThis); + int res = ChangeThreadPriority(_autoSaveTid, statThis.current_priority - 1); + sioprintf("SaveThread prio res: %d", res); + + do { // wait until thread called ExitThread() + SignalSema(_autoSaveSignal); + ReferThreadStatus(_autoSaveTid, &statSave); + } while (statSave.status != 0x10); + sioprintf("wait done"); + DeleteThread(_autoSaveTid); + free(_autoSaveStack); +} + +UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mc) { _screen = screen; - int fd = fio.open(filename, O_RDONLY); + _mc = mc; + int fd = _mc->open(filename, O_RDONLY); _buf = NULL; _bufSize = _bufPos = 0; _ioFailed = false; if (fd >= 0) { - int srcSize = fio.seek(fd, 0, SEEK_END); - fio.seek(fd, 0, SEEK_SET); - if (srcSize > 4) { + int srcSize = _mc->size(fd); + if (srcSize > 8) { int res; - uint8 *tmpBuf = (uint8*)malloc(srcSize); - fio.read(fd, tmpBuf, srcSize); - res = fio.sync(fd); - if (res == srcSize) { - uint32 resLen = _bufSize = *(uint32*)tmpBuf; + uint8 *tmpBuf = (uint8*)memalign(64, srcSize); + res = _mc->read(fd, tmpBuf, srcSize); + if ((res == srcSize) && (*(uint32*)tmpBuf == UCL_MAGIC)) { + uint32 resLen = _bufSize = *(uint32*)(tmpBuf + 4); _buf = (uint8*)malloc(_bufSize + 2048); - res = ucl_nrv2e_decompress_8(tmpBuf + 4, srcSize - 4, _buf, &resLen, NULL); + res = ucl_nrv2e_decompress_8(tmpBuf + 8, srcSize - 8, _buf, &resLen, NULL); if ((res < 0) || (resLen != _bufSize)) { printf("Unable to decompress file %s (%d -> %d) error code %d\n", filename, srcSize, _bufSize, res); free(_buf); @@ -357,11 +598,11 @@ UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen) { } free(tmpBuf); } - if (!_buf) { - printf("Invalid savegame %s\n", filename); - _ioFailed = true; - } - fio.close(fd); + _mc->close(fd); + } + if (!_buf) { + printf("Invalid savegame %s\n", filename); + _ioFailed = true; } } @@ -384,27 +625,36 @@ bool UclInSaveFile::eos(void) const { } uint32 UclInSaveFile::read(void *ptr, uint32 size) { - uint32 bytesRemain = _bufSize - _bufPos; - if (size > bytesRemain) { - size = bytesRemain; + if (_buf) { + uint32 bytesRemain = _bufSize - _bufPos; + if (size > bytesRemain) { + size = bytesRemain; + _ioFailed = true; + } + memcpy(ptr, _buf + _bufPos, size); + _bufPos += size; + return size; + } else { _ioFailed = true; + return 0; } - memcpy(ptr, _buf + _bufPos, size); - _bufPos += size; - return size; } void UclInSaveFile::skip(uint32 offset) { - if (_bufPos + offset <= _bufSize) - _bufPos += offset; - else - _bufPos = _bufSize; + if (_buf) { + if (_bufPos + offset <= _bufSize) + _bufPos += offset; + else + _bufPos = _bufSize; + } } -UclOutSaveFile::UclOutSaveFile(const char *filename, Gs2dScreen *screen) { +UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc) { _screen = screen; + _system = system; + _mc = mc; _bufPos = 0; - _fd = fio.open(filename, O_WRONLY | O_CREAT | O_TRUNC); + _fd = _mc->open(filename, O_WRONLY | O_CREAT); if (_fd >= 0) { _bufSize = 65536; _buf = (uint8*)malloc(_bufSize); @@ -414,16 +664,24 @@ UclOutSaveFile::UclOutSaveFile(const char *filename, Gs2dScreen *screen) { _bufSize = 0; _buf = NULL; } + _wasFlushed = false; } UclOutSaveFile::~UclOutSaveFile(void) { if (_buf) { - if (flush() < 0) - printf("~UclOutSaveFile: Flush failed!\n"); + if (_bufPos) { + printf("Engine didn't call SaveFile::flush()\n"); + flush(); + if (ioFailed()) { + // unable to save to memory card and it's too late to return an error code to the engine + _system->msgPrintf(5000, "!WARNING!\nCan't write to memory card.\nGame was NOT saved."); + printf("~UclOutSaveFile: Flush failed!\n"); + } + } free(_buf); } if (_fd >= 0) - fio.close(_fd); + _mc->close(_fd); _screen->wantAnim(false); } @@ -435,33 +693,36 @@ void UclOutSaveFile::clearIOFailed(void) { _ioFailed = false; } -int UclOutSaveFile::flush(void) { - if (_bufPos == 0) - return 0; // no data to flush - if (_buf) { - uint8 *compBuf = (uint8*)malloc(_bufPos * 2); - uint32 compSize = _bufPos * 2; - int res = ucl_nrv2e_99_compress(_buf, _bufPos, compBuf, &compSize, NULL, 10, NULL, NULL); - if (res >= 0) { - fio.write(_fd, &_bufPos, 4); - if (fio.sync(_fd) == 4) { - fio.write(_fd, compBuf, compSize); - if (fio.sync(_fd) != compSize) +void UclOutSaveFile::flush(void) { + int res = 0; + + if (_bufPos) { + if (_wasFlushed) { + // the engine flushed this file and afterwards wrote more data. + // this is unsupported because it results in savefiles that consist + // of two or more compressed segments. + printf("Error: 2nd call to UclOutSaveFile::flush!\n"); + res = -1; + } else { + uint32 compSize = _bufPos * 2; + uint8 *compBuf = (uint8*)memalign(64, compSize + 8); + *(uint32*)(compBuf + 0) = UCL_MAGIC; + *(uint32*)(compBuf + 4) = _bufPos; // uncompressed size + res = ucl_nrv2e_99_compress(_buf, _bufPos, compBuf + 8, &compSize, NULL, 10, NULL, NULL); + if (res >= 0) { + res = _mc->write(_fd, compBuf, compSize + 8); + if (res != (int)compSize + 8) res = -1; } else - res = -1; - } else - printf("Unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); - free(compBuf); - - if (res >= 0) { + printf("Unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + free(compBuf); _bufPos = 0; - return 0; } } - _ioFailed = true; - printf("UclOutSaveFile::flush failed!\n"); - return -1; + if (res < 0) { + _ioFailed = true; + printf("UclOutSaveFile::flush failed!\n"); + } } uint32 UclOutSaveFile::write(const void *ptr, uint32 size) { diff --git a/backends/ps2/savefile.h b/backends/ps2/savefile.h index 66c5357fe2..a95223b926 100644 --- a/backends/ps2/savefile.h +++ b/backends/ps2/savefile.h @@ -22,17 +22,12 @@ #ifndef __PS2_SAVEFILE__ #define __PS2_SAVEFILE__ -#include "common/savefile.h" #include <libmc.h> - -enum SaveMode { - TO_HOST = 0, - TO_MC, - TO_HDD -}; +#include "common/savefile.h" class Gs2dScreen; class OSystem_PS2; +class McAccess; class Ps2SaveFileManager : public Common::SaveFileManager { public: @@ -45,8 +40,12 @@ public: /** Get the path to the save game directory. */ virtual const char *getSavePath() const; + + void writeSaveNonblocking(char *name, void *buf, uint32 size); + void saveThread(void); + void quit(void); private: - static bool setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2); + bool setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2); bool mcReadyForDir(const char *dir); @@ -56,6 +55,15 @@ private: Gs2dScreen *_screen; OSystem_PS2 *_system; + McAccess *_mc; + + int _autoSaveTid; + int _autoSaveSignal; + void *_autoSaveStack; + volatile bool _systemQuit; + uint8 *_autoSaveBuf; + uint32 _autoSaveSize; + char _autoSaveName[256]; mcTable *_mcDirList; int _mcEntries; diff --git a/backends/ps2/smushio.cpp b/backends/ps2/smushio.cpp deleted file mode 100644 index 84efcbbcd1..0000000000 --- a/backends/ps2/smushio.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2005 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $Header$ - * - */ - -/* - The Smush player uses at least two handles for accessing the same SMUSH file, - to avoid threading issues. One handle for video, one for audio apparently. - Each of the handles always skips the data that the other one read before - (or will read later). - - This behaviour makes it difficult to do read ahead caching without reading - any given file twice, so this class tries to "reunite" the read accesses and - do the necessary caching. -*/ - -#include "backends/ps2/fileio.h" -#include "backends/ps2/asyncfio.h" -#include <kernel.h> -#include <assert.h> -#include <string.h> -#include <sio.h> - -extern AsyncFio fio; -extern void sioprintf(const char *zFormat, ...); - -#define SMUSH_CACHE_SIZE (5 * 1024 * 1024) -#define READ_STEP (32 * 1024) -#define SMUSH_IN_USE -2 - -class SmushReader { -public: - SmushReader(void); - ~SmushReader(void); - int open(const char *name); - void close(void); - uint32 read(void *dest, uint32 from, uint32 len); - void virtSeek(uint32 from, uint32 to); - uint32 size(void); - bool keepOpened(void); -private: - void processCache(bool sync); - char _fname[256]; - int _sema, _fd, _refCount; - uint8 *_cacheBuf; - volatile uint32 _cacheFilePos, _bytesInCache, _fileSize, _cacheBufOfs; - volatile uint32 _lastRead[2]; - volatile bool _cacheOp; -}; - -SmushReader::SmushReader(void) { - _cacheBuf = NULL; - _fd = -1; - _refCount = 0; - - ee_sema_t newSema; - newSema.init_count = 1; - newSema.max_count = 1; - _sema = CreateSema(&newSema); - assert(_sema >= 0); -} - -SmushReader::~SmushReader(void) { - DeleteSema(_sema); -} - -int SmushReader::open(const char *name) { - WaitSema(_sema); - if (_refCount) { - if (stricmp(_fname, name)) { - sioprintf("SmushReader is already open to file\n%s\nGot open request for %s", _fname, name); - SignalSema(_sema); - return SMUSH_IN_USE; - } - } else { - assert(_fd < 0); - _fd = fio.open(name, O_RDONLY); - if (_fd < 0) { - SignalSema(_sema); - return -1; - } - _fileSize = fio.seek(_fd, 0, SEEK_END); - fio.seek(_fd, 0, SEEK_SET); - - _cacheBuf = (uint8*)malloc(SMUSH_CACHE_SIZE); - if (!_cacheBuf) { - sioprintf("Smush Reader ran out of memory"); - fio.close(_fd); - _fd = -1; - SignalSema(_sema); - return -1; - } - _lastRead[0] = _lastRead[1] = 0; - _cacheBufOfs = _bytesInCache = _cacheFilePos = 0; - fio.read(_fd, _cacheBuf, READ_STEP); - _cacheOp = true; - strcpy(_fname, name); - } - _refCount++; - sioprintf("SmushReader %s ref count %d", _fname, _refCount); - SignalSema(_sema); - return 0; -} - -void SmushReader::close(void) { - WaitSema(_sema); - sioprintf("Closing Ref to %s", _fname); - assert(_refCount > 0); - _refCount--; - if (!_refCount) { - sioprintf("SmushReader: All references to %s closed", _fname); - processCache(true); - _fname[0] = '\0'; - fio.close(_fd); - _fd = -1; - free(_cacheBuf); - _cacheBuf = NULL; - } - SignalSema(_sema); -} - -#define MIN(a, b) ((a < b) ? (a) : (b)) - -void SmushReader::processCache(bool sync) { - if (_cacheOp) { - if (sync || fio.poll(_fd)) { // has the transfer finished or were we told to wait for it to finish? - int rdRes = fio.sync(_fd); - assert(rdRes >= 0); - _bytesInCache += rdRes; - _cacheOp = false; - } - } else if (!sync) { - if (_cacheFilePos + _bytesInCache == _fileSize) - return; - - uint32 rdPos = MIN(_lastRead[0], _lastRead[1]); - - int cacheOfs = (rdPos - _cacheFilePos) & ~0xF; // we'd like to keep the buffer aligned to 16 bytes - if (cacheOfs < 0) { - sioprintf("ERROR: smush cache too far ahead!"); - return; - } - - if (_bytesInCache - cacheOfs < SMUSH_CACHE_SIZE - READ_STEP) { - // we want to do some more reading - if (_bytesInCache > cacheOfs) { - _bytesInCache -= cacheOfs; - _cacheBufOfs += cacheOfs; - _cacheFilePos += cacheOfs; - } else { - sioprintf("cache underrun!"); - _bytesInCache = 0; - _cacheBufOfs = 0; - _cacheFilePos = rdPos; - } - - uint32 bufEndPos = (_cacheBufOfs + _bytesInCache) % SMUSH_CACHE_SIZE; - uint32 readLen = SMUSH_CACHE_SIZE - bufEndPos; - if (readLen > READ_STEP) - readLen = READ_STEP; - - fio.read(_fd, _cacheBuf + bufEndPos, readLen); - _cacheOp = true; - } - } -} - -uint32 SmushReader::read(void *dest, uint32 from, uint32 len) { - uint8 *destBuf = (uint8*)dest; - WaitSema(_sema); - if ((from >= _cacheFilePos) && (from + len <= _cacheFilePos + _bytesInCache)) - processCache(false); - else { - processCache(true); // we'll have to read, sync cache before. - } - uint32 readEnds = from + len; - if (from == _lastRead[0]) - _lastRead[0] += len; - else if (from == _lastRead[1]) - _lastRead[1] += len; - else { - if ((_lastRead[0] > readEnds) && (_lastRead[1] < readEnds)) { - _lastRead[1] = readEnds; - } else if ((_lastRead[0] < readEnds) && (_lastRead[1] > readEnds)) { - _lastRead[0] = readEnds; - } else { - if ((_lastRead[0] < readEnds) && (_lastRead[1] < readEnds)) { - if (_lastRead[0] < _lastRead[1]) - _lastRead[0] = readEnds; - else - _lastRead[1] = readEnds; - } else - sioprintf("unexpected readend: %d / %d => %d", _lastRead[0], _lastRead[1], readEnds); - } - } - - while (len) { - while (len && (from >= _cacheFilePos) && (from < _cacheFilePos + _bytesInCache)) { - uint32 cpyOfs = ((from - _cacheFilePos) + _cacheBufOfs) % SMUSH_CACHE_SIZE; - uint32 cpyLen = _bytesInCache - (from - _cacheFilePos); - if (cpyLen > len) - cpyLen = len; - if (cpyOfs + cpyLen > SMUSH_CACHE_SIZE) - cpyLen = SMUSH_CACHE_SIZE - cpyOfs; - memcpy(destBuf, _cacheBuf + cpyOfs, cpyLen); - destBuf += cpyLen; - from += cpyLen; - len -= cpyLen; - } - if (len) { - sioprintf("Smush cache missed: read %d -> %d, cache %d -> %d", from, len, _cacheFilePos, _bytesInCache); - assert(fio.seek(_fd, 0, SEEK_CUR) == _cacheFilePos + _bytesInCache); - fio.seek(_fd, from, SEEK_SET); - int rdRes; - do { - fio.read(_fd, destBuf, len); - rdRes = fio.sync(_fd); - destBuf += rdRes; - from += rdRes; - len -= rdRes; - } while (len && rdRes); - fio.seek(_fd, _cacheFilePos + _bytesInCache, SEEK_SET); - break; - } - } - processCache(false); - SignalSema(_sema); - return destBuf - (uint8*)dest; -} - -void SmushReader::virtSeek(uint32 from, uint32 to) { - WaitSema(_sema); - if (_lastRead[0] == from) - _lastRead[0] = to; - else if (_lastRead[1] == from) - _lastRead[1] = to; - SignalSema(_sema); -} - -uint32 SmushReader::size(void) { - assert(_fd >= 0); - return _fileSize; -} - -bool SmushReader::keepOpened(void) { - return _refCount > 0; -} - -#define MAX_READERS 3 - -static SmushReader *g_smushReaders[MAX_READERS] = { NULL, NULL, NULL }; - -static int g_openSema = -1; - -Ps2SmushFile::Ps2SmushFile(int64 cacheId) : Ps2File(cacheId) { - _filePos = _fileSize = 0; - _id = -1; - if (g_openSema < 0) { - ee_sema_t newSema; - newSema.init_count = 1; - newSema.max_count = 1; - g_openSema = CreateSema(&newSema); - assert(g_openSema >= 0); - } -} - -Ps2SmushFile::~Ps2SmushFile(void) { - WaitSema(g_openSema); - if (_id >= 0) { - g_smushReaders[_id]->close(); - if (!g_smushReaders[_id]->keepOpened()) { - delete g_smushReaders[_id]; - g_smushReaders[_id] = NULL; - } - } - SignalSema(g_openSema); -} - -bool Ps2SmushFile::open(const char *name) { - WaitSema(g_openSema); - int opSlot = MAX_READERS; - for (int i = 0; i < MAX_READERS; i++) { - if (g_smushReaders[i]) { - sioprintf("attaching to reader in slot %d", i); - if (g_smushReaders[i]->open(name) == 0) { - _id = i; - _fileSize = g_smushReaders[i]->size(); - sioprintf("attach ok"); - break; - } - } else if (opSlot == MAX_READERS) - opSlot = i; - } - if (_id < 0) { // smush file wasn't opened before - sioprintf("creating new reader in slot %d", opSlot); - if (opSlot < MAX_READERS) { - g_smushReaders[opSlot] = new SmushReader(); - if (g_smushReaders[opSlot]->open(name) == 0) { - _id = opSlot; - _fileSize = g_smushReaders[opSlot]->size(); - } else { - // can't open file - delete g_smushReaders[opSlot]; - g_smushReaders[opSlot] = NULL; - } - } else - printf("Ran out of reader slots\n"); - } - SignalSema(g_openSema); - return (_id >= 0); -} - -uint32 Ps2SmushFile::read(void *dest, uint32 len) { - int res = g_smushReaders[_id]->read(dest, _filePos, len); - _filePos += res; - return res; -} - -uint32 Ps2SmushFile::write(const void *src, uint32 len) { - printf("ERROR: Received write request on Smush reader\n"); - SleepThread(); - return 0; -} - -uint32 Ps2SmushFile::tell(void) { - return _filePos; -} - -uint32 Ps2SmushFile::size(void) { - return _fileSize; -} - -int Ps2SmushFile::seek(int32 offset, int origin) { - int32 res; - switch (origin) { - case SEEK_SET: - res = offset; - break; - case SEEK_CUR: - res = _filePos + offset; - break; - case SEEK_END: - res = _fileSize + offset; - break; - default: - return -1; - } - if ((res >= 0) && (res <= _fileSize)) { - if (offset != 0) - g_smushReaders[_id]->virtSeek(_filePos, res); - _filePos = res; - return 0; - } - return -1; -} - -bool Ps2SmushFile::eof(void) { - return _filePos == _fileSize; -} - diff --git a/backends/ps2/systemps2.cpp b/backends/ps2/systemps2.cpp index 96913132c4..27b88d30ea 100644 --- a/backends/ps2/systemps2.cpp +++ b/backends/ps2/systemps2.cpp @@ -43,6 +43,7 @@ #include "common/file.h" #include "backends/ps2/sysdefs.h" #include <libmc.h> +#include <libpad.h> #include "backends/ps2/cd.h" #include <sio.h> #include <fileXio_rpc.h> @@ -53,8 +54,8 @@ #define SOUND_STACK_SIZE (1024 * 32) #define SMP_PER_BLOCK 800 #define FROM_BCD(a) ((a >> 4) * 10 + (a & 0xF)) -#define BUS_CLOCK (150 * 1000 * 1000) // 150 Mhz Bus clock -#define CLK_DIVIS 5859 // the timer IRQ handler gets called (BUS_CLOCK / 256) / CLK_DIVIS times per second (~100 times) +#define BUS_CLOCK 147456000 // bus clock, a little less than 150 mhz +#define CLK_DIVIS 5760 // the timer IRQ handler gets called (BUS_CLOCK / 256) / CLK_DIVIS times per second (100 times) #ifdef USE_PS2LINK #define IRX_PREFIX "host:" @@ -67,14 +68,14 @@ static int g_TimerThreadSema = -1, g_SoundThreadSema = -1; static int g_MainWaitSema = -1, g_TimerWaitSema = -1; static volatile int32 g_MainWakeUp = 0, g_TimerWakeUp = 0; -static volatile uint64 msecCount = 0; +static volatile uint32 msecCount = 0; OSystem_PS2 *g_systemPs2 = NULL; -void readRtcTime(void); - int gBitFormat = 555; +#define FOREVER 2147483647 + namespace Graphics { extern const NewFont g_sysfont; }; @@ -84,7 +85,7 @@ void sioprintf(const char *zFormat, ...) { char resStr[2048]; va_start(ap,zFormat); - int res = vsnprintf(resStr, 2048, zFormat, ap); + vsnprintf(resStr, 2048, zFormat, ap); va_end(ap); sio_puts(resStr); @@ -113,7 +114,7 @@ extern "C" int main(int argc, char *argv[]) { sio_puts("IOP synced."); SifInitRpc(0); SifLoadFileInit(); - cdvdInit(CDVD_INIT_NOWAIT); + cdvdInit(CDVD_INIT_NOWAIT); #endif ee_thread_t thisThread; @@ -143,8 +144,8 @@ extern "C" int main(int argc, char *argv[]) { } s32 timerInterruptHandler(s32 cause) { - msecCount += (((uint64)256 * CLK_DIVIS) << 32) / (BUS_CLOCK / 1000); T0_MODE = 0xDC2; // same value as in initialization. + msecCount += 10; iSignalSema(g_SoundThreadSema); iSignalSema(g_TimerThreadSema); @@ -175,54 +176,66 @@ void systemSoundThread(OSystem_PS2 *system) { } OSystem_PS2::OSystem_PS2(void) { - sioprintf("OSystem_PS2 constructor\n"); - _soundStack = _timerStack = NULL; _scummTimerProc = NULL; _scummSoundProc = NULL; _scummSoundParam = NULL; + _printY = 0; + _msgClearTime = 0; + _systemQuit = false; _screen = new Gs2dScreen(320, 200, TV_DONT_CARE); - _width = 320; - _height = 200; - sioprintf("Initializing timer\n"); + sioprintf("Initializing system..."); initTimer(); _screen->wantAnim(true); - char errorStr[256]; - if (!loadModules(errorStr)) - fatalError(errorStr); + sioprintf("Loading IOP modules..."); + loadModules(); - sioprintf("Initializing SjPCM"); - if (SjPCM_Init(0) < 0) - fatalError("SjPCM Bind failed"); + int res; + if ((res = SjPCM_Init(0)) < 0) { + msgPrintf(FOREVER, "SjPCM Bind failed: %d", res); + quit(); + } - if (CDVD_Init() != 0) - fatalError("CDVD_Init failed"); + if ((res = CDVD_Init()) != 0) { + msgPrintf(FOREVER, "CDVD Init failed: %d", res); + quit(); + } + + if ((res = fileXioInit()) < 0) { + msgPrintf(FOREVER, "FXIO Init failed: %d", res); + quit(); + } + fileXioSetBlockMode(FXIO_NOWAIT); _mouseVisible = false; sioprintf("reading RTC"); readRtcTime(); - sioprintf("Initializing FXIO"); - if (fileXioInit() < 0) - fatalError("Can't init fileXio"); - - fileXioSetBlockMode(FXIO_NOWAIT); - sioprintf("Starting SavefileManager"); _saveManager = new Ps2SaveFileManager(this, _screen); - _soundBufL = (int16*)malloc(SMP_PER_BLOCK * sizeof(int16)); - _soundBufR = (int16*)malloc(SMP_PER_BLOCK * sizeof(int16)); - sioprintf("Initializing ps2Input"); _input = new Ps2Input(this, _useMouse, _useKbd); +#ifdef _REC_MUTEX_ + _mutex = new Ps2Mutex[MAX_MUTEXES]; + + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _mutexSema = CreateSema(&newSema); + for (int i = 0; i < MAX_MUTEXES; i++) { + _mutex[i].sema = -1; + _mutex[i].count = _mutex[i].owner = 0; + } +#endif _screen->wantAnim(false); + _screen->clearScreen(); } OSystem_PS2::~OSystem_PS2(void) { @@ -267,7 +280,7 @@ void OSystem_PS2::initTimer(void) { StartThread(_timerTid, this); StartThread(_soundTid, this); - // these semaphores are used for OSystem::delay() + // these semaphores are used for OSystem::delayMillis() threadSema.init_count = 0; threadSema.max_count = 1; g_MainWaitSema = CreateSema(&threadSema); @@ -275,20 +288,22 @@ void OSystem_PS2::initTimer(void) { assert((g_MainWaitSema >= 0) && (g_TimerWaitSema >= 0)); // threads done, start the interrupt handler - AddIntcHandler( INT_TIMER0, timerInterruptHandler, 0); // 0=first handler + _intrId = AddIntcHandler( INT_TIMER0, timerInterruptHandler, 0); // 0=first handler + assert(_intrId >= 0); EnableIntc(INT_TIMER0); T0_HOLD = 0; T0_COUNT = 0; - T0_COMP = CLK_DIVIS; // (busclock / 256) / 5859 = ~ 100.0064 + T0_COMP = CLK_DIVIS; // (BUS_CLOCK / 256) / CLK_DIVIS = 100 T0_MODE = TIMER_MODE( 2, 0, 0, 0, 1, 1, 1, 0, 1, 1); } void OSystem_PS2::timerThread(void) { - while (1) { + while (!_systemQuit) { WaitSema(g_TimerThreadSema); if (_scummTimerProc) _scummTimerProc(0); } + ExitThread(); } void OSystem_PS2::soundThread(void) { @@ -298,9 +313,12 @@ void OSystem_PS2::soundThread(void) { _soundSema = CreateSema(&soundSema); assert(_soundSema >= 0); + int16 *soundBufL = (int16*)memalign(64, SMP_PER_BLOCK * sizeof(int16) * 2); + int16 *soundBufR = soundBufL + SMP_PER_BLOCK; + int bufferedSamples = 0; int cycles = 0; - while (1) { + while (!_systemQuit) { WaitSema(g_SoundThreadSema); if (!(cycles & 31)) @@ -311,7 +329,7 @@ void OSystem_PS2::soundThread(void) { WaitSema(_soundSema); if (_scummSoundProc) { - if (bufferedSamples <= 8 * SMP_PER_BLOCK) { + if (bufferedSamples <= 4 * SMP_PER_BLOCK) { // we have to produce more samples, call sound mixer // the scratchpad at 0x70000000 is used as temporary soundbuffer _scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); @@ -343,20 +361,25 @@ void OSystem_PS2::soundThread(void) { " addiu $t8, 32\n\t" " bnez $t9, loop\n\t" // loop : // outputs - : "r"(_soundBufL), "r"(_soundBufR) // inputs + : "r"(soundBufL), "r"(soundBufR) // inputs // : "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "$t9" // destroyed : "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25" // destroyed ); // and feed it into the SPU - SjPCM_Enqueue((short int*)_soundBufL, (short int*)_soundBufR, SMP_PER_BLOCK, 0); + // non-blocking call, the function will return before the buffer's content + // was transferred. + SjPCM_Enqueue((short int*)soundBufL, (short int*)soundBufR, SMP_PER_BLOCK, 0); bufferedSamples += SMP_PER_BLOCK; } } SignalSema(_soundSema); } + free(soundBufL); + DeleteSema(_soundSema); + ExitThread(); } -char *irxModules[] = { +const char *irxModules[] = { "rom0:SIO2MAN", "rom0:MCMAN", "rom0:MCSERV", @@ -370,40 +393,37 @@ char *irxModules[] = { IRX_PREFIX "SJPCM.IRX" IRX_SUFFIX }; -bool OSystem_PS2::loadModules(char *errorStr) { +void OSystem_PS2::loadModules(void) { - _useHdd = _useMouse = _useKbd = false; + _useMouse = _useKbd = false; int res; for (int i = 0; i < ARRAYSIZE(irxModules); i++) { if ((res = SifLoadModule(irxModules[i], 0, NULL)) < 0) { - sprintf(errorStr, "Can't load module %s (%d)", irxModules[i], res); - return false; + msgPrintf(FOREVER, "Unable to load module %s, Error %d", irxModules[i], res); + _screen->wantAnim(false); + updateScreen(); + SleepThread(); } } - printf("Modules loaded\n"); + // now try to load optional IRXs - if ((res = SifLoadModule(IRX_PREFIX "USBD.IRX" IRX_SUFFIX, 0, NULL)) < 0) - sioprintf("Cannot load module: USBD.IRX (%d)\n", res); - else { + if ((res = SifLoadModule(IRX_PREFIX "USBD.IRX" IRX_SUFFIX, 0, NULL)) >= 0) { if ((res = SifLoadModule(IRX_PREFIX "PS2MOUSE.IRX" IRX_SUFFIX, 0, NULL)) < 0) - sioprintf("Cannot load module: PS2MOUSE.IRX (%d)\n", res); + sioprintf("Cannot load module: PS2MOUSE.IRX (%d)", res); else _useMouse = true; if ((res = SifLoadModule(IRX_PREFIX "RPCKBD.IRX" IRX_SUFFIX, 0, NULL)) < 0) - sioprintf("Cannot load module: RPCKBD.IRX (%d)\n", res); + sioprintf("Cannot load module: RPCKBD.IRX (%d)", res); else _useKbd = true; } - sioprintf("Modules: UsbMouse %sloaded, UsbKbd %sloaded, Hdd %sloaded.", _useMouse ? "" : "not ", _useKbd ? "" : "not ", _useHdd ? "" : "not "); - return true; + sioprintf("Modules: UsbMouse %sloaded, UsbKbd %sloaded.", _useMouse ? "" : "not ", _useKbd ? "" : "not "); } void OSystem_PS2::initSize(uint width, uint height, int overscale) { printf("initializing new size: (%d/%d)...", width, height); _screen->newScreenSize(width, height); - _width = width; - _height = height; _screen->setMouseXy(width / 2, height / 2); _input->newRange(0, 0, width - 1, height - 1); _input->warpTo(width / 2, height / 2); @@ -422,30 +442,24 @@ void OSystem_PS2::grabPalette(byte *colors, uint start, uint num) { } void OSystem_PS2::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - if (x < 0) { - w += x; - buf -= x; - x = 0; - } - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - if (x + w > _width) - w = _width - x; - if (y + h > _height) - h = _height - y; - if ((w > 0) && (h > 0)) - _screen->copyScreenRect((const uint8*)buf, (uint16)pitch, (uint16)x, (uint16)y, (uint16)w, (uint16)h); + _screen->copyScreenRect((const uint8*)buf, pitch, x, y, w, h); +} + +bool OSystem_PS2::grabRawScreen(Graphics::Surface *surf) { + _screen->grabScreen(surf); + return true; } void OSystem_PS2::updateScreen(void) { + if (_msgClearTime && (_msgClearTime < getMillis())) { + _screen->clearPrintfOverlay(); + _msgClearTime = 0; + } _screen->updateScreen(); } uint32 OSystem_PS2::getMillis(void) { - return (uint32)(msecCount >> 32); + return msecCount; } void OSystem_PS2::delayMillis(uint msecs) { @@ -500,6 +514,7 @@ Common::SaveFileManager *OSystem_PS2::getSavefileManager(void) { return _saveManager; } +#ifndef _REC_MUTEX_ OSystem::MutexRef OSystem_PS2::createMutex(void) { ee_sema_t newSema; newSema.init_count = 1; @@ -521,6 +536,68 @@ void OSystem_PS2::unlockMutex(MutexRef mutex) { void OSystem_PS2::deleteMutex(MutexRef mutex) { DeleteSema((int)mutex); } +#else +OSystem::MutexRef OSystem_PS2::createMutex(void) { + WaitSema(_mutexSema); + Ps2Mutex *mutex = NULL; + for (int i = 0; i < MAX_MUTEXES; i++) + if (_mutex[i].sema < 0) { + mutex = _mutex + i; + break; + } + if (mutex) { + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + mutex->sema = CreateSema(&newSema); + mutex->owner = mutex->count = 0; + } else + printf("OSystem_PS2::createMutex: ran out of Mutex slots!\n"); + SignalSema(_mutexSema); + return (OSystem::MutexRef)mutex; +} + +void OSystem_PS2::lockMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + int tid = GetThreadId(); + assert(tid != 0); + if (sysMutex->owner && (sysMutex->owner == tid)) + sysMutex->count++; + else { + SignalSema(_mutexSema); + WaitSema(sysMutex->sema); + WaitSema(_mutexSema); + sysMutex->owner = tid; + sysMutex->count = 0; + } + SignalSema(_mutexSema); +} + +void OSystem_PS2::unlockMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + int tid = GetThreadId(); + if (sysMutex->owner && sysMutex->count && (sysMutex->owner == tid)) + sysMutex->count--; + else { + assert(sysMutex->count == 0); + SignalSema(sysMutex->sema); + sysMutex->owner = 0; + } + SignalSema(_mutexSema); +} + +void OSystem_PS2::deleteMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + if (sysMutex->owner || sysMutex->count) + printf("WARNING: Deleting LOCKED mutex!\n"); + DeleteSema(sysMutex->sema); + sysMutex->sema = -1; + SignalSema(_mutexSema); +} +#endif void OSystem_PS2::setShakePos(int shakeOffset) { _screen->setShakePos(shakeOffset); @@ -615,40 +692,90 @@ void OSystem_PS2::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { } int16 OSystem_PS2::getHeight(void) { - return _height; + return _screen->getHeight(); } int16 OSystem_PS2::getWidth(void) { - return _width; + return _screen->getWidth(); } -void OSystem_PS2::quit(void) { - printf("OSystem_PS2::quit\n"); - clearSoundCallback(); - setTimerCallback(NULL, 0); - SleepThread(); -} +void OSystem_PS2::msgPrintf(int millis, char *format, ...) { + va_list ap; + char resStr[1024]; + memset(resStr, 0, 1024); + + va_start(ap, format); + vsnprintf(resStr, 1023, format, ap); + va_end(ap); + + uint16 posY = 2; + int maxWidth = 0; -void OSystem_PS2::fatalError(char *errorStr) { - sioprintf("ERROR: %s", errorStr); - printf("ERROR: %s\n", errorStr); Graphics::Surface surf; surf.create(300, 200, 1); - Common::String str(errorStr); - Graphics::g_sysfont.drawString(&surf, str, 0, 0, 300, 0xFF); - uint32 palette[256]; - palette[0] = 0x00400000; - for (int i = 1; i < 256; i++) - palette[i] = 0xFFFFFFFF; + char *lnSta = resStr; + while (*lnSta && (posY < 180)) { + char *lnEnd = lnSta; + while ((*lnEnd) && (*lnEnd != '\n')) + lnEnd++; + *lnEnd = '\0'; + + Common::String str(lnSta); + int width = Graphics::g_sysfont.getStringWidth(str); + if (width > maxWidth) + maxWidth = width; + int posX = (300 - width) / 2; + Graphics::g_sysfont.drawString(&surf, str, posX, posY, 300 - posX, 1); + posY += 14; + + lnSta = lnEnd + 1; + } - _screen->setPalette(palette, 0, 256); - _screen->hideOverlay(); - _screen->wantAnim(false); + uint8 *scrBuf = (uint8*)memalign(64, 320 * 200); + memset(scrBuf, 4, 320 * 200); - _screen->copyScreenRect((uint8*)surf.getBasePtr(0, 0), surf.pitch, 10, 10, 300, 100); - _screen->updateScreen(); - SleepThread(); + uint8 *dstPos = scrBuf + ((200 - posY) >> 1) * 320 + (320 - maxWidth) / 2; + for (int y = 0; y < posY; y++) { + uint8 *srcPos = (uint8*)surf.getBasePtr((300 - maxWidth) / 2, y); + for (int x = 0; x < maxWidth; x++) + dstPos[x] = srcPos[x] + 5; + dstPos += 320; + } + surf.free(); + _screen->copyPrintfOverlay(scrBuf); + free(scrBuf); + _msgClearTime = millis + getMillis(); +} + +void OSystem_PS2::quit(void) { + sioprintf("OSystem_PS2::quit"); + clearSoundCallback(); + setTimerCallback(NULL, 0); + _screen->wantAnim(false); + _systemQuit = true; + ee_thread_t statSound, statTimer; + do { // wait until both threads called ExitThread() + ReferThreadStatus(_timerTid, &statTimer); + ReferThreadStatus(_soundTid, &statSound); + } while ((statSound.status != 0x10) || (statTimer.status != 0x10)); + DeleteThread(_timerTid); + DeleteThread(_soundTid); + free(_timerStack); + free(_soundStack); + DisableIntc(INT_TIMER0); + RemoveIntcHandler(INT_TIMER0, _intrId); + + _saveManager->quit(); + _screen->quit(); + + padEnd(); // stop pad library + cdvdInit(CDVD_EXIT); + cdvdExit(); + SifExitIopHeap(); + SifLoadFileExit(); + SifExitRpc(); + LoadExecPS2("cdrom0:\\SCUMMVM.ELF", 0, NULL); // resets the console and executes the ELF } static uint32 g_timeSecs; @@ -687,13 +814,13 @@ void buildNewDate(int dayDiff) { #define SECONDS_PER_DAY (24 * 60 * 60) -void readRtcTime(void) { +void OSystem_PS2::readRtcTime(void) { struct CdClock cdClock; CDVD_ReadClock(&cdClock); - g_lastTimeCheck = (uint32)(msecCount >> 32); + g_lastTimeCheck = msecCount; if (cdClock.stat) { - printf("Unable to read RTC time, EC: %d\n", cdClock.stat); + msgPrintf(5000, "Unable to read RTC time, EC: %d\n", cdClock.stat); g_day = g_month = 1; g_year = 0; g_timeSecs = 0; @@ -717,7 +844,6 @@ void readRtcTime(void) { buildNewDate(+1); timeSecs -= SECONDS_PER_DAY; } - g_timeSecs = (uint32)timeSecs; } @@ -726,17 +852,15 @@ void readRtcTime(void) { } extern time_t time(time_t *p) { - time_t blah; - memset(&blah, 0, sizeof(time_t)); - return blah; + return (time_t)g_timeSecs; } extern struct tm *localtime(const time_t *p) { - uint32 currentSecs = g_timeSecs + ((msecCount >> 32) - g_lastTimeCheck) / 1000; + uint32 currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; if (currentSecs >= SECONDS_PER_DAY) { buildNewDate(+1); - g_timeSecs -= SECONDS_PER_DAY; - currentSecs = g_timeSecs + ((msecCount >> 32) - g_lastTimeCheck) / 1000; + g_lastTimeCheck += SECONDS_PER_DAY * 1000; + currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; } static struct tm retStruct; @@ -747,7 +871,7 @@ extern struct tm *localtime(const time_t *p) { retStruct.tm_sec = currentSecs % 60; retStruct.tm_year = g_year + 100; retStruct.tm_mday = g_day; - retStruct.tm_mon = g_month; + retStruct.tm_mon = g_month - 1; // tm_wday, tm_yday and tm_isdst are zero for now return &retStruct; } diff --git a/backends/ps2/systemps2.h b/backends/ps2/systemps2.h index 9e0d9ccd84..1ddf01f1c5 100644 --- a/backends/ps2/systemps2.h +++ b/backends/ps2/systemps2.h @@ -29,6 +29,17 @@ class Gs2dScreen; class Ps2Input; class Ps2SaveFileManager; +#define _REC_MUTEX_ + +#ifdef _REC_MUTEX_ +#define MAX_MUTEXES 32 +struct Ps2Mutex { + int sema; + int owner; + int count; +}; +#endif + class OSystem_PS2 : public OSystem { public: OSystem_PS2(void); @@ -38,11 +49,17 @@ public: virtual int16 getHeight(void); virtual int16 getWidth(void); virtual void setPalette(const byte *colors, uint start, uint num); - virtual void grabPalette(byte *colors, uint start, uint num); virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - - virtual void updateScreen(); virtual void setShakePos(int shakeOffset); + virtual void grabPalette(byte *colors, uint start, uint num); + virtual bool grabRawScreen(Graphics::Surface *surf); + virtual void updateScreen(); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); virtual bool showMouse(bool visible); @@ -69,12 +86,6 @@ public: virtual void unlockMutex(MutexRef mutex); virtual void deleteMutex(MutexRef mutex); - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); - virtual const GraphicsMode *getSupportedGraphicsModes() const; virtual int getDefaultGraphicsMode() const; virtual bool setGraphicsMode(int mode); @@ -90,30 +101,36 @@ public: void timerThread(void); void soundThread(void); + void msgPrintf(int millis, char *format, ...); + private: volatile OSystem::TimerProc _scummTimerProc; volatile OSystem::SoundProc _scummSoundProc; void *_scummSoundParam; - int16 *_soundBufL, *_soundBufR; int _soundSema; void initTimer(void); - void fatalError(char *str); + void readRtcTime(void); - bool loadModules(char *errorStr); + void loadModules(void); bool _mouseVisible; - bool _useHdd, _useMouse, _useKbd; + bool _useMouse, _useKbd; Ps2SaveFileManager *_saveManager; - uint16 _width, _height; - Gs2dScreen *_screen; Ps2Input *_input; uint16 _oldMouseX, _oldMouseY; - + uint32 _msgClearTime; + uint16 _printY; +#ifdef _REC_MUTEX_ + int _mutexSema; + Ps2Mutex *_mutex; +#endif uint8 *_timerStack, *_soundStack; - int32 _timerTid, _soundTid; + int _timerTid, _soundTid; + int _intrId; + volatile bool _systemQuit; static const GraphicsMode _graphicsMode; }; |