aboutsummaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
authorRobert Göffringmann2005-11-09 19:51:57 +0000
committerRobert Göffringmann2005-11-09 19:51:57 +0000
commit1f647b48bc8b955cfb5c36534ef221e3c3002cba (patch)
treebe98eb9ce6790524d94fd0ac53e44953ceb2a84f /backends
parent2b4c9b00b06a83972426b90114b3c598701b5859 (diff)
downloadscummvm-rg350-1f647b48bc8b955cfb5c36534ef221e3c3002cba.tar.gz
scummvm-rg350-1f647b48bc8b955cfb5c36534ef221e3c3002cba.tar.bz2
scummvm-rg350-1f647b48bc8b955cfb5c36534ef221e3c3002cba.zip
sync HEAD with 0-8-0 branch.
svn-id: r19534
Diffstat (limited to 'backends')
-rw-r--r--backends/ps2/DmaPipe.cpp2
-rw-r--r--backends/ps2/Gs2dScreen.cpp285
-rw-r--r--backends/ps2/Gs2dScreen.h25
-rw-r--r--backends/ps2/READ_PS2.TXT68
-rw-r--r--backends/ps2/asyncfio.cpp6
-rw-r--r--backends/ps2/fileio.cpp72
-rw-r--r--backends/ps2/ps2input.cpp77
-rw-r--r--backends/ps2/ps2input.h3
-rw-r--r--backends/ps2/ps2pad.cpp3
-rw-r--r--backends/ps2/savefile.cpp487
-rw-r--r--backends/ps2/savefile.h24
-rw-r--r--backends/ps2/smushio.cpp376
-rw-r--r--backends/ps2/systemps2.cpp332
-rw-r--r--backends/ps2/systemps2.h51
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;
};