diff options
Diffstat (limited to 'backends/platform/psp')
31 files changed, 1833 insertions, 1159 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 617ef7c8cc..7f9ae153eb 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -148,6 +148,7 @@ OBJS := powerman.o \ thread.o \ rtc.o \ mp3.o \ + png_loader.o \ tests.o BACKEND := psp @@ -199,4 +200,4 @@ SCEkxploit: $(TARGET).elf $(PSP_EBOOT_SFO) $(PACK_PBP) "%__SCE__$(TARGET)/$(PSP_EBOOT)" $(PSP_EBOOT_SFO) $(PSP_EBOOT_ICON) \ $(PSP_EBOOT_ICON1) $(PSP_EBOOT_PIC0) $(PSP_EBOOT_PIC1) \ $(PSP_EBOOT_SND0) NULL $(PSP_EBOOT_PSAR) - + diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP index f4d5bae6d6..0849d68c78 100644 --- a/backends/platform/psp/README.PSP +++ b/backends/platform/psp/README.PSP @@ -1,81 +1,97 @@ -ScummVM-PSP 1.2.0svn README +ScummVM-PSP 1.3.0svn README ============================================================================== Installation ============ - - Copy the relevant game datafiles to your memory stick (location - doesn't matter). - - Install ScummVM like any other homebrew - - Run ScummVM and use the launcher to add games and run them - + - Copy the relevant game datafiles to your memory stick (location doesn't matter). + - Install ScummVM like any other homebrew. + - Run ScummVM and use the launcher to add games and run them. Controls ======== - -Left trigger - ESC Right trigger - Modifier key (see below for uses) +Left trigger - ESC (Usually skips cutscenes. Depends on game) Analog - Mouse movement -Right trigger + Analog - Fine control mouse -Directions - Arrow keys -Directions + Right Trigger - Diagonal arrow keys -Triangle - Enter -Cross - Mouse button 1 -Circle - Mouse button 2 -Square - '.' (skip dialogue in some games) -Start - F5 (Main Menu) -Right trigger + Start - Return-To-Launcher menu - -Virtual Keyboard -================ - -Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen. -Start - Enter -Right trigger - Switch to/between letter modes -Left trigger - Switch to/between numbers and symbols -D-Pad - Select square of characters -Buttons/Triggers - Choose a specific character +Right trigger + Analog - Fine mouse movement +D-Pad - Arrow keys (useful mostly in SCI and AGI games) +D-Pad + Right Trigger - Diagonal arrow keys (it's hard to input diagonals on some PSPs) +Triangle - Enter (useful for some dialogs) +Cross - Left Mouse Button (usually the main button) +Circle - Right Mouse Button (secondary button in some games) +Square - '.' (skip dialogue in some games e.g. Scumm) +Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games) +Start - Global Menu. Allows you to 'Return To Launcher' to play another game +Right trigger + Start - F5 (Main Menu in some games) +Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad). + +Virtual Keyboard Mode +===================== +Start - Enter key. Also exits virtual keyboard mode +Select - Exit the virtual keyboard mode +Right trigger - Input letters: lowercase/uppercase (press to toggle) +Left trigger - Input numbers/symbols (press to toggle) +D-Pad - Select square of characters (up, down, left or right) +Buttons/Triggers - Choose a specific character in the square. The four center characters are chosen + by the button in the corresponding position. The 2 top characters are chosen by the + triggers. +Analog - Moves in a direction (left/right/up/down) (Useful to keep moving + while typing in AGI games among other things) + +1st Person Game Mode (Can be ignored by most users) +==================== +This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can +safely ignore this mode. To enter or leave this mode, use the combo: + +Right Trigger + Left Trigger + Square + +Some buttons have been switched around to make these games more playable: +Square - Is the modifier key instead of Right Trigger. +Left/Right Trigger - Strafe left/right +D-Pad Left/Right - Turn left/right +Square + D-Pad - F1/F2/F3/F4 +Square + Start - Esc (shows game menu) + Notes ===== +- Notice that you can switch between games! This is much faster than quitting + and having to start ScummVM all over again. Go to the global menu and choose 'Return To Launcher'. + (Some games may not have the Return To Launcher option available yet.) + +- The PSP version of ScummVM uses the Media Engine to accelerate decoding of MP3 files. This means + that if you have the choice of compressing using Ogg files or MP3 files, choose MP3 -- the game + will generally run faster. -- Plugin files are NOT interchangeable between versions! You must copy ALL the - plugin files that come with every version of scummvm. They sit in the /plugin +- Plugin files are NOT interchangeable between ScummVM versions! You must copy ALL the + plugin files that come with every version of ScummVM. They sit in the /plugin subdirectory. If you get a crash upon startup, try deleting all the existing plugin files in the plugin directory and copying the new ones over again. -- While it's possible to compress certain game resources to reduce their size, - this can (and usually will) cause games (especially animation) to be choppy - sometimes, as it ofcourse needs extra CPU power to decode these files. - As such, it is recommended to play games in their original, uncompressed, - form whenever possible. - - This README may be outdated, for more up-to-date instructions and notes see the PSP Port Wiki: http://wiki.scummvm.org/index.php/PlayStation_Portable Frequently Asked Questions ========================== -Q: Pressing select doesn't make the virtual keyboard show up on screen! -A: You need to make sure that the kbd.zip file is in the same directory as the scummvm executable. - Q: Scummvm crashes upon starting up! A: See the first note above. +Q: Pressing select doesn't make the virtual keyboard show up on screen! +A: You need to make sure that the kbd.zip file is in the same directory as the ScummVM executable. + Q: What do I need to run the games? -A: A 1.00 or 1.50 firmware PSP (or an EBOOT loader on firmware 2.00 or - higher), and the necessary datafiles for the game you want to play and - obviously this ScummVM port. +A: A PSP that can run homebrew and the necessary datafiles for the game you want to play. Q: Can I run game X with this? A: You can find the list of supported games on the compatibility page - on http://www.scummvm.org. - Note that ScummVM is NOT a 'DOS (game) emulator', but written - specifically for certain games/engines. + at http://www.scummvm.org + Note that ScummVM is NOT an emulator. The supported games engines have been painstakingly rewritten. + It's not easy to add support for a game you want that currently isn't supported. Q: My Monkey Island 1 doesn't have any music, what gives? A: If your version of Monkey Island came on a CD then it has the music - as CD Audio tracks. You need to rip those to MP3/Ogg and copy them - to the same directory as the game datafiles for music to work. + as CD Audio tracks. You need to rip those to MP3/Ogg (MP3 is preferred), naming them track1.mp3 track2.mp3 + etc. and copy them to the same directory as the game datafiles for music to work. Q: Game X crashes, or feature Y doesn't work. Can you fix this? A: Possibly. @@ -83,21 +99,23 @@ A: Possibly. played them all start-to-finish on the PSP, so it's possible there are bugs or issues that we're not aware of. When you encounter such a bug, please use the "Bug Tracker" you find linked - on the ScummVM website, and mention all relevant info (i.e. that you're + on the ScummVM website, and mention all relevant info i.e. that you're using the PSP version, which ScummVM version it is, if the problem exists - in a recent PC SVN version, a detailed description of the problem, - and if at all possible a nearby savegame), this will make it much easier + in a recent PC version, a detailed description of the problem, + and if at all possible a nearby savegame. This will make it much easier for us to reproduce (and hopefully fix) the problem. Building the source code ======================== To build ScummVM for PSP you need: +- ScummVM source code (svn co https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk) + - PSP toolchain (svn co svn://svn.pspdev.org/psp/trunk/psptoolchain) - PSPSDK (svn co svn://svn.pspdev.org/psp/trunk/pspsdk) - Note: This usually gets installed by the PSP toolchain, - so you don't have to do it manually. + Note: This usually gets installed by the PSP toolchain, + so you don't have to do it manually. - zlib (svn co svn://svn.pspdev.org/psp/trunk/zlib) @@ -107,21 +125,15 @@ To build ScummVM for PSP you need: - libTremor(*) (svn co svn://svn.pspdev.org/psp/trunk/libTremor) - - (*) = optional -When you've installed these libraries (read their README.PSP for instructions), -type "make" in the backends/platform/psp directory to build a 1.00 firmware -EBOOT.PBP, or "make kxploit" to build the 1.50/kxploit EBOOT.PBPs - -You can control most of the build process (engines and libraries used) from -the Makefile. - +Once you've installed these libraries (read their README.PSP for instructions), +create a subdirectory in your ScummVM folder called 'builds/psp'. Then, in this folder, type +'../../configure --host=psp --enable-plugins --default-dynamic'. If everything is installed +correctly, ScummVM will inform you as it finds the right components. Finally type 'make' to build. Port Authors ============ - Joost Peters (joostp@scummvm.org) Paolo Costabel (paoloc@pacbell.net) Thomas Mayer (tommybear@internode.on.net) diff --git a/backends/platform/psp/README.PSP.in b/backends/platform/psp/README.PSP.in index 2d53fd3b47..57058abd85 100644 --- a/backends/platform/psp/README.PSP.in +++ b/backends/platform/psp/README.PSP.in @@ -3,79 +3,95 @@ ScummVM-PSP @VERSION@ README Installation ============ - - Copy the relevant game datafiles to your memory stick (location - doesn't matter). - - Install ScummVM like any other homebrew - - Run ScummVM and use the launcher to add games and run them - + - Copy the relevant game datafiles to your memory stick (location doesn't matter). + - Install ScummVM like any other homebrew. + - Run ScummVM and use the launcher to add games and run them. Controls ======== - -Left trigger - ESC Right trigger - Modifier key (see below for uses) +Left trigger - ESC (Usually skips cutscenes. Depends on game) Analog - Mouse movement -Right trigger + Analog - Fine control mouse -Directions - Arrow keys -Directions + Right Trigger - Diagonal arrow keys -Triangle - Enter -Cross - Mouse button 1 -Circle - Mouse button 2 -Square - '.' (skip dialogue in some games) -Start - F5 (Main Menu) -Right trigger + Start - Return-To-Launcher menu - -Virtual Keyboard -================ - -Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen. -Start - Enter -Right trigger - Switch to/between letter modes -Left trigger - Switch to/between numbers and symbols -D-Pad - Select square of characters -Buttons/Triggers - Choose a specific character +Right trigger + Analog - Fine mouse movement +D-Pad - Arrow keys (useful mostly in SCI and AGI games) +D-Pad + Right Trigger - Diagonal arrow keys (it's hard to input diagonals on some PSPs) +Triangle - Enter (useful for some dialogs) +Cross - Left Mouse Button (usually the main button) +Circle - Right Mouse Button (secondary button in some games) +Square - '.' (skip dialogue in some games e.g. Scumm) +Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games) +Start - Global Menu. Allows you to 'Return To Launcher' to play another game +Right trigger + Start - F5 (Main Menu in some games) +Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad). + +Virtual Keyboard Mode +===================== +Start - Enter key. Also exits virtual keyboard mode +Select - Exit the virtual keyboard mode +Right trigger - Input letters: lowercase/uppercase (press to toggle) +Left trigger - Input numbers/symbols (press to toggle) +D-Pad - Select square of characters (up, down, left or right) +Buttons/Triggers - Choose a specific character in the square. The four center characters are chosen + by the button in the corresponding position. The 2 top characters are chosen by the + triggers. +Analog - Moves in a direction (left/right/up/down) (Useful to keep moving + while typing in AGI games among other things) + +1st Person Game Mode (Can be ignored by most users) +==================== +This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can +safely ignore this mode. To enter or leave this mode, use the combo: + +Right Trigger + Left Trigger + Square + +Some buttons have been switched around to make these games more playable: +Square - Is the modifier key instead of Right Trigger. +Left/Right Trigger - Strafe left/right +D-Pad Left/Right - Turn left/right +Square + D-Pad - F1/F2/F3/F4 +Square + Start - Esc (shows game menu) + Notes ===== +- Notice that you can switch between games! This is much faster than quitting + and having to start ScummVM all over again. Go to the global menu and choose 'Return To Launcher'. + (Some games may not have the Return To Launcher option available yet.) + +- The PSP version of ScummVM uses the Media Engine to accelerate decoding of MP3 files. This means + that if you have the choice of compressing using Ogg files or MP3 files, choose MP3 -- the game + will generally run faster. -- Plugin files are NOT interchangeable between versions! You must copy ALL the - plugin files that come with every version of scummvm. They sit in the /plugin +- Plugin files are NOT interchangeable between ScummVM versions! You must copy ALL the + plugin files that come with every version of ScummVM. They sit in the /plugin subdirectory. If you get a crash upon startup, try deleting all the existing plugin files in the plugin directory and copying the new ones over again. -- While it's possible to compress certain game resources to reduce their size, - this can (and usually will) cause games (especially animation) to be choppy - sometimes, as it ofcourse needs extra CPU power to decode these files. - As such, it is recommended to play games in their original, uncompressed, - form whenever possible. - - This README may be outdated, for more up-to-date instructions and notes see the PSP Port Wiki: http://wiki.scummvm.org/index.php/PlayStation_Portable Frequently Asked Questions ========================== -Q: Pressing select doesn't make the virtual keyboard show up on screen! -A: You need to make sure that the kbd.zip file is in the same directory as the scummvm executable. - Q: Scummvm crashes upon starting up! A: See the first note above. +Q: Pressing select doesn't make the virtual keyboard show up on screen! +A: You need to make sure that the kbd.zip file is in the same directory as the ScummVM executable. + Q: What do I need to run the games? -A: A 1.00 or 1.50 firmware PSP (or an EBOOT loader on firmware 2.00 or - higher), and the necessary datafiles for the game you want to play and - obviously this ScummVM port. +A: A PSP that can run homebrew and the necessary datafiles for the game you want to play. Q: Can I run game X with this? A: You can find the list of supported games on the compatibility page - on http://www.scummvm.org. - Note that ScummVM is NOT a 'DOS (game) emulator', but written - specifically for certain games/engines. + at http://www.scummvm.org + Note that ScummVM is NOT an emulator. The supported games engines have been painstakingly rewritten. + It's not easy to add support for a game you want that currently isn't supported. Q: My Monkey Island 1 doesn't have any music, what gives? A: If your version of Monkey Island came on a CD then it has the music - as CD Audio tracks. You need to rip those to MP3/Ogg and copy them - to the same directory as the game datafiles for music to work. + as CD Audio tracks. You need to rip those to MP3/Ogg (MP3 is preferred), naming them track1.mp3 track2.mp3 + etc. and copy them to the same directory as the game datafiles for music to work. Q: Game X crashes, or feature Y doesn't work. Can you fix this? A: Possibly. @@ -83,21 +99,23 @@ A: Possibly. played them all start-to-finish on the PSP, so it's possible there are bugs or issues that we're not aware of. When you encounter such a bug, please use the "Bug Tracker" you find linked - on the ScummVM website, and mention all relevant info (i.e. that you're + on the ScummVM website, and mention all relevant info i.e. that you're using the PSP version, which ScummVM version it is, if the problem exists - in a recent PC SVN version, a detailed description of the problem, - and if at all possible a nearby savegame), this will make it much easier + in a recent PC version, a detailed description of the problem, + and if at all possible a nearby savegame. This will make it much easier for us to reproduce (and hopefully fix) the problem. Building the source code ======================== To build ScummVM for PSP you need: +- ScummVM source code (svn co https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk) + - PSP toolchain (svn co svn://svn.pspdev.org/psp/trunk/psptoolchain) - PSPSDK (svn co svn://svn.pspdev.org/psp/trunk/pspsdk) - Note: This usually gets installed by the PSP toolchain, - so you don't have to do it manually. + Note: This usually gets installed by the PSP toolchain, + so you don't have to do it manually. - zlib (svn co svn://svn.pspdev.org/psp/trunk/zlib) @@ -107,21 +125,15 @@ To build ScummVM for PSP you need: - libTremor(*) (svn co svn://svn.pspdev.org/psp/trunk/libTremor) - - (*) = optional -When you've installed these libraries (read their README.PSP for instructions), -type "make" in the backends/platform/psp directory to build a 1.00 firmware -EBOOT.PBP, or "make kxploit" to build the 1.50/kxploit EBOOT.PBPs - -You can control most of the build process (engines and libraries used) from -the Makefile. - +Once you've installed these libraries (read their README.PSP for instructions), +create a subdirectory in your ScummVM folder called 'builds/psp'. Then, in this folder, type +'../../configure --host=psp --enable-plugins --default-dynamic'. If everything is installed +correctly, ScummVM will inform you as it finds the right components. Finally type 'make' to build. Port Authors ============ - Joost Peters (joostp@scummvm.org) Paolo Costabel (paoloc@pacbell.net) Thomas Mayer (tommybear@internode.on.net) diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index e540733162..d7487b0c1a 100644 --- a/backends/platform/psp/audio.cpp +++ b/backends/platform/psp/audio.cpp @@ -23,10 +23,10 @@ * */ -#include <pspthreadman.h> +#include <pspthreadman.h> #include <pspaudio.h> - -#include "common/scummsys.h" + +#include "common/scummsys.h" #include "backends/platform/psp/audio.h" //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ @@ -39,37 +39,37 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call if (_init) { PSP_ERROR("audio device already initialized\n"); return true; - } + } - PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n", + PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n", freq, numOfChannels, numOfSamples, callback, (uint32)userData); - + numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples); uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16); - + PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen); - + _buffers[0] = (byte *)memalign(64, bufLen); if (!_buffers[0]) { PSP_ERROR("failed to allocate memory for audio buffers\n"); return false; } memset(_buffers[0], 0, bufLen); // clean the buffer - + // Fill in the rest of the buffer pointers byte *pBuffer = _buffers[0]; for (int i = 1; i < NUM_BUFFERS; i++) { pBuffer += numOfSamples * numOfChannels * sizeof(uint16); _buffers[i] = pBuffer; } - + // Reserve a HW channel for our audio _pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO); if (_pspChannel < 0) { PSP_ERROR("failed to reserve audio channel\n"); return false; } - + PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel); // Save our data @@ -80,17 +80,17 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call _userData = userData; _bufferToFill = 0; _bufferToPlay = 0; - + _init = true; _paused = true; // start in paused mode - + threadCreateAndStart("audioThread", PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD); // start the consumer thread - + return true; } // The real thread function -void PspAudio::threadFunction() { +void PspAudio::threadFunction() { assert(_callback); PSP_DEBUG_PRINT_FUNC("audio thread started\n"); @@ -108,12 +108,12 @@ void PspAudio::threadFunction() { PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill); _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in data nextBuffer(_bufferToFill); - + PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay); playBuffer(); nextBuffer(_bufferToPlay); } // while _init - + // destroy everything free(_buffers[0]); sceAudioChRelease(_pspChannel); @@ -136,7 +136,7 @@ inline bool PspAudio::playBuffer() { ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); else ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); - + if (ret < 0) { PSP_ERROR("failed to output audio. Error[%d]\n", ret); return false; @@ -146,5 +146,5 @@ inline bool PspAudio::playBuffer() { void PspAudio::close() { PSP_DEBUG_PRINT("close has been called ***************\n"); - _init = false; + _init = false; } diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h index eeba598fed..ec9801185f 100644 --- a/backends/platform/psp/audio.h +++ b/backends/platform/psp/audio.h @@ -35,9 +35,9 @@ public: FREQUENCY = 44100 /* only frequency we allow */ }; typedef void (* callbackFunc)(void *userData, byte *samples, int len); // audio callback to call - PspAudio() : _pspChannel(0), - _numOfChannels(0), _numOfSamples(0), _callback(0), - _bufferToPlay(0), _bufferToFill(0), + PspAudio() : _pspChannel(0), + _numOfChannels(0), _numOfSamples(0), _callback(0), + _bufferToPlay(0), _bufferToFill(0), _init(false), _paused(true) { for (int i=0; i<NUM_BUFFERS; i++) _buffers[i] = 0; @@ -51,7 +51,7 @@ public: void pause() { _paused = true; } void unpause() { _paused = false; } virtual void threadFunction(); // actual audio thread - + private: int _pspChannel; // chosen hardware output channel uint32 _numOfChannels; // 1 for mono; 2 for stereo diff --git a/backends/platform/psp/cursor.h b/backends/platform/psp/cursor.h index c3d4d76803..2ff0415c6c 100644 --- a/backends/platform/psp/cursor.h +++ b/backends/platform/psp/cursor.h @@ -26,6 +26,8 @@ #ifndef MOUSE_H #define MOUSE_H +#include "backends/platform/psp/default_display_client.h" + class Cursor : public DefaultDisplayClient { private: int _hotspotX, _hotspotY; diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp index 71b505ec7c..916b6c1aae 100644 --- a/backends/platform/psp/display_client.cpp +++ b/backends/platform/psp/display_client.cpp @@ -32,6 +32,7 @@ #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/display_manager.h" +#define PSP_INCLUDE_SWAP #include "backends/platform/psp/memory.h" //#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ @@ -341,14 +342,14 @@ void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, u if (pitch == realWidthInBytes && pitch == recWidthInBytes) { //memcpy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth)); if (_pixelFormat.swapRB) - PspMemory::fastSwap(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth), _pixelFormat); + PspMemorySwap::fastSwap(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth), _pixelFormat); else PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth)); } else { do { //memcpy(dst, buf, recWidthInBytes); if (_pixelFormat.swapRB) - PspMemory::fastSwap(dst, buf, recWidthInBytes, _pixelFormat); + PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat); else PspMemory::fastCopy(dst, buf, recWidthInBytes); buf += pitch; @@ -370,7 +371,7 @@ void Buffer::copyToArray(byte *dst, int pitch) { do { //memcpy(dst, src, sourceWidthInBytes); if (_pixelFormat.swapRB) - PspMemory::fastSwap(dst, src, sourceWidthInBytes, _pixelFormat); + PspMemorySwap::fastSwap(dst, src, sourceWidthInBytes, _pixelFormat); else PspMemory::fastCopy(dst, src, sourceWidthInBytes); src += realWidthInBytes; @@ -698,14 +699,14 @@ void GuRenderer::fillVertices(Vertex *vertices) { // Save scaled offset on screen float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x); float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y); - + float imageStartX, imageStartY, imageEndX, imageEndY; imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x)); imageStartY = gapY + scaledOffsetOnScreenY; if (_fullScreen) { // shortcut - imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX; + imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX; imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake } else { /* !fullScreen */ imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width); diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h index d05b0b046c..feec477282 100644 --- a/backends/platform/psp/display_client.h +++ b/backends/platform/psp/display_client.h @@ -30,6 +30,7 @@ #include "graphics/surface.h" #include "common/system.h" #include "backends/platform/psp/memory.h" +#include "backends/platform/psp/psppixelformat.h" #define MAX_TEXTURE_SIZE 512 diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index 5037543f12..5d75ac531e 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -53,35 +53,99 @@ uint32 __attribute__((aligned(16))) MasterGuRenderer::_displayList[2048]; const OSystem::GraphicsMode DisplayManager::_supportedModes[] = { - { "320x200 (centered)", "320x200 16-bit centered", CENTERED_320X200 }, - { "435x272 (best-fit, centered)", "435x272 16-bit centered", CENTERED_435X272 }, - { "480x272 (full screen)", "480x272 16-bit stretched", STRETCHED_480X272 }, - { "362x272 (4:3, centered)", "362x272 16-bit centered", CENTERED_362X272 }, + { "Original Resolution", "Original Resolution", ORIGINAL_RESOLUTION }, + { "Keep Aspect Ratio", "Keep Aspect Ratio", KEEP_ASPECT_RATIO }, + { "Full Screen", "Full Screen", STRETCHED_FULL_SCREEN }, {0, 0, 0} }; + +// Class VramAllocator ----------------------------------- + +DECLARE_SINGLETON(VramAllocator) + +//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ +//#define __PSP_DEBUG_PRINT__ + +#include "backends/platform/psp/trace.h" + + +void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) { + DEBUG_ENTER_FUNC(); + assert(size > 0); + + byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS; + Common::List<Allocation>::iterator i; + + // Find a block that fits, starting from the beginning + for (i = _allocList.begin(); i != _allocList.end(); ++i) { + byte *currAddress = (*i).address; + + if (currAddress - lastAddress >= size) // We found a match + break; + + if ((*i).getEnd() > lastAddress) + lastAddress = (byte *)(*i).getEnd(); + } + + if (lastAddress + size > (byte *)VRAM_END_ADDRESS) { + PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n", + size, _bytesAllocated); + return NULL; + } + + _allocList.insert(i, Allocation(lastAddress, size)); + _bytesAllocated += size; + + PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress); + PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated); + + return lastAddress; +} + +// Deallocate a block from VRAM +void VramAllocator::deallocate(void *address) { + DEBUG_ENTER_FUNC(); + address = (byte *)CACHED(address); // Make sure all addresses are the same + + Common::List<Allocation>::iterator i; + + // Find the Allocator to deallocate + for (i = _allocList.begin(); i != _allocList.end(); ++i) { + if ((*i).address == address) { + _bytesAllocated -= (*i).size; + _allocList.erase(i); + PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size); + return; + } + } + + PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address); +} + + // Class MasterGuRenderer ---------------------------------------------- void MasterGuRenderer::setupCallbackThread() { DEBUG_ENTER_FUNC(); - + // start the thread that updates the display - threadCreateAndStart("DisplayCbThread", PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD); + threadCreateAndStart("DisplayCbThread", PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD); } // this function gets called by PspThread when starting the new thread void MasterGuRenderer::threadFunction() { DEBUG_ENTER_FUNC(); - + // Create the callback. It should always get the pointer to MasterGuRenderer _callbackId = sceKernelCreateCallback("Display Callback", guCallback, this); if (_callbackId < 0) { - PSP_ERROR("failed to create display callback\n"); + PSP_ERROR("failed to create display callback\n"); } - + PSP_DEBUG_PRINT("created callback. Going to sleep\n"); - sceKernelSleepThreadCB(); // sleep until we get a callback + sceKernelSleepThreadCB(); // sleep until we get a callback } // This callback is called when the render is finished. It swaps the buffers @@ -89,12 +153,12 @@ int MasterGuRenderer::guCallback(int, int, void *__this) { MasterGuRenderer *_this = (MasterGuRenderer *)__this; - sceGuSync(0, 0); // make sure we wait for GU to finish + sceGuSync(0, 0); // make sure we wait for GU to finish sceDisplayWaitVblankStartCB(); // wait for v-blank without eating main thread cycles sceGuSwapBuffers(); // swap the back and front buffers _this->_renderFinished = true; // Only this thread can set the variable to true - + return 0; } @@ -150,7 +214,7 @@ inline void MasterGuRenderer::guPreRender() { DEBUG_ENTER_FUNC(); _renderFinished = false; // set to synchronize with callback thread - + #ifdef ENABLE_RENDER_MEASURE _lastRenderTime = g_system->getMillis(); #endif /* ENABLE_RENDER_MEASURE */ @@ -179,7 +243,7 @@ inline void MasterGuRenderer::guPostRender() { else sceKernelNotifyCallback(_callbackId, 0); // notify the callback. Nothing extra to pass #else - sceGuSync(0, 0); + sceGuSync(0, 0); #ifdef ENABLE_RENDER_MEASURE uint32 now = g_system->getMillis(); @@ -189,7 +253,7 @@ inline void MasterGuRenderer::guPostRender() { sceDisplayWaitVblankStart(); sceGuSwapBuffers(); _renderFinished = true; -#endif /* !USE_DISPLAY_CALLBACK */ +#endif /* !USE_DISPLAY_CALLBACK */ } void MasterGuRenderer::guShutDown() { @@ -217,7 +281,7 @@ void DisplayManager::init() { #ifdef USE_DISPLAY_CALLBACK _masterGuRenderer.setupCallbackThread(); #endif - + } void DisplayManager::setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format) { @@ -263,38 +327,50 @@ bool DisplayManager::setGraphicsMode(int mode) { _graphicsMode = mode; + calculateScaleParams(); + + return true; +} + +void DisplayManager::calculateScaleParams() { + + if (!_displayParams.screenSource.width || !_displayParams.screenSource.height) + return; // we can't calculate anything without these + switch (_graphicsMode) { - case CENTERED_320X200: - _displayParams.screenOutput.width = 320; - _displayParams.screenOutput.height = 200; - break; - case CENTERED_435X272: - _displayParams.screenOutput.width = 435; - _displayParams.screenOutput.height = 272; + case ORIGINAL_RESOLUTION: + // check if we can fit the original resolution inside the screen + if ((_displayParams.screenSource.width < PSP_SCREEN_WIDTH) && + (_displayParams.screenSource.height < PSP_SCREEN_HEIGHT)) { + _displayParams.screenOutput.width = _displayParams.screenSource.width; + _displayParams.screenOutput.height = _displayParams.screenSource.height; + } else { // revert to stretch to fit + _displayParams.screenOutput.width = PSP_SCREEN_WIDTH; + _displayParams.screenOutput.height = PSP_SCREEN_HEIGHT; + } break; - case STRETCHED_480X272: - _displayParams.screenOutput.width = 480; - _displayParams.screenOutput.height = 272; + case KEEP_ASPECT_RATIO: { // maximize the height while keeping aspect ratio + float aspectRatio = (float)_displayParams.screenSource.width / (float)_displayParams.screenSource.height; + + _displayParams.screenOutput.height = PSP_SCREEN_HEIGHT; // always full height + _displayParams.screenOutput.width = (uint32)(PSP_SCREEN_HEIGHT * aspectRatio); + + if (_displayParams.screenOutput.width > PSP_SCREEN_WIDTH) // we can't have wider than the screen + _displayParams.screenOutput.width = PSP_SCREEN_WIDTH; + } break; - case CENTERED_362X272: - _displayParams.screenOutput.width = 362; - _displayParams.screenOutput.height = 272; + case STRETCHED_FULL_SCREEN: // we simply stretch to the whole screen + _displayParams.screenOutput.width = PSP_SCREEN_WIDTH; + _displayParams.screenOutput.height = PSP_SCREEN_HEIGHT; break; default: PSP_ERROR("Unsupported graphics mode[%d].\n", _graphicsMode); } - calculateScaleParams(); - - return true; -} + // calculate scale factors for X and Y + _displayParams.scaleX = ((float)_displayParams.screenOutput.width) / _displayParams.screenSource.width; + _displayParams.scaleY = ((float)_displayParams.screenOutput.height) / _displayParams.screenSource.height; -void DisplayManager::calculateScaleParams() { - if (_displayParams.screenOutput.width && _displayParams.screenSource.width && - _displayParams.screenOutput.height && _displayParams.screenSource.height) { - _displayParams.scaleX = ((float)_displayParams.screenOutput.width) / _displayParams.screenSource.width; - _displayParams.scaleY = ((float)_displayParams.screenOutput.height) / _displayParams.screenSource.height; - } } // return true if we really rendered or no dirty. False otherwise @@ -305,9 +381,9 @@ bool DisplayManager::renderAll() { if (!_masterGuRenderer.isRenderFinished()) { PSP_DEBUG_PRINT("Callback render not finished.\n"); return false; // didn't render - } + } #endif /* USE_DISPLAY_CALLBACK */ - + // This is cheaper than checking time, so we do it first if (!_screen->isDirty() && (!_overlay->isDirty()) && @@ -317,7 +393,7 @@ bool DisplayManager::renderAll() { return true; // nothing to render } - if (!isTimeToUpdate()) + if (!isTimeToUpdate()) return false; // didn't render PSP_DEBUG_PRINT("screen[%s], overlay[%s], cursor[%s], keyboard[%s]\n", @@ -349,7 +425,7 @@ bool DisplayManager::renderAll() { _keyboard->setClean(); _masterGuRenderer.guPostRender(); - + return true; // rendered successfully } diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h index 1f7320902c..00d3851243 100644 --- a/backends/platform/psp/display_manager.h +++ b/backends/platform/psp/display_manager.h @@ -27,6 +27,48 @@ #define PSP_DISPLAY_MAN_H #include "backends/platform/psp/thread.h" +#include "common/list.h" + +#define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */ +#define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */ + +/** + * Class that allocates memory in the VRAM + */ +class VramAllocator : public Common::Singleton<VramAllocator> { +public: + VramAllocator() : _bytesAllocated(0) {} + void *allocate(int32 size, bool smallAllocation = false); // smallAllocation e.g. palettes + void deallocate(void *pointer); + + static inline bool isAddressInVram(void *address) { + if ((uint32)(CACHED(address)) >= VRAM_START_ADDRESS && (uint32)(CACHED(address)) < VRAM_END_ADDRESS) + return true; + return false; + } + + +private: + /** + * Used to allocate in VRAM + */ + struct Allocation { + byte *address; + uint32 size; + void *getEnd() { return address + size; } + Allocation(void *Address, uint32 Size) : address((byte *)Address), size(Size) {} + Allocation() : address(0), size(0) {} + }; + + enum { + VRAM_START_ADDRESS = 0x04000000, + VRAM_END_ADDRESS = 0x04200000, + VRAM_SMALL_ADDRESS = VRAM_END_ADDRESS - (4 * 1024) // 4K in the end for small allocations + }; + Common::List <Allocation> _allocList; // List of allocations + uint32 _bytesAllocated; +}; + /** * Class used only by DisplayManager to start/stop GU rendering @@ -39,7 +81,7 @@ public: void guPostRender(); void guShutDown(); bool isRenderFinished() { return _renderFinished; } - void setupCallbackThread(); + void setupCallbackThread(); private: virtual void threadFunction(); // for the display callback thread static uint32 _displayList[]; @@ -47,7 +89,7 @@ private: void guProgramDisplayBufferSizes(); static int guCallback(int, int, void *__this); // for the display callback bool _renderFinished; // for sync with render callback - int _callbackId; // to keep track of render callback + int _callbackId; // to keep track of render callback }; class Screen; @@ -61,10 +103,9 @@ class PSPKeyboard; class DisplayManager { public: enum GraphicsModeID { ///> Possible output formats onscreen - CENTERED_320X200, - CENTERED_435X272, - STRETCHED_480X272, - CENTERED_362X272 + ORIGINAL_RESOLUTION, + KEEP_ASPECT_RATIO, + STRETCHED_FULL_SCREEN }; DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {} ~DisplayManager(); @@ -74,7 +115,7 @@ public: bool setGraphicsMode(int mode); bool setGraphicsMode(const char *name); int getGraphicsMode() const { return _graphicsMode; } - uint32 getDefaultGraphicsMode() const { return STRETCHED_480X272; } + uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; } const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; } // Setters diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp index 4fe7cb3f92..ed868ef375 100644 --- a/backends/platform/psp/input.cpp +++ b/backends/platform/psp/input.cpp @@ -23,238 +23,272 @@ * */ -// Todo: handle events that should fire because of shift going off -// Solution: handle shift on a button-by-button basis, only allowing it when the button is up. Also a inputmap-wide button. At buttonup, shiftstate is inspected per button. +#include <pspctrl.h> +#include "gui/message.h" +#include "backends/platform/psp/input.h" //#define __PSP_DEBUG_FUNCS__ /* Uncomment for debugging the stack */ //#define __PSP_DEBUG_PRINT__ /* Uncomment for debug prints */ - #include "backends/platform/psp/trace.h" -#include "backends/platform/psp/psppixelformat.h" -#include "backends/platform/psp/input.h" - // Defines for working with PSP buttons -#define CHANGED(x) (_buttonsChanged & (x)) -#define PRESSED(x) ((_buttonsChanged & (x)) && (pad.Buttons & (x))) -#define UNPRESSED(x) ((_buttonsChanged & (x)) && !(pad.Buttons & (x))) -#define DOWN(x) (pad.Buttons & (x)) +#define DOWN(x) ((pad.Buttons & (x)) == (x)) #define UP(x) (!(pad.Buttons & (x))) #define PSP_DPAD (PSP_CTRL_DOWN|PSP_CTRL_UP|PSP_CTRL_LEFT|PSP_CTRL_RIGHT) #define PSP_4BUTTONS (PSP_CTRL_CROSS | PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_SQUARE) #define PSP_TRIGGERS (PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER) +#define PSP_ALL_BUTTONS (PSP_DPAD | PSP_4BUTTONS | PSP_TRIGGERS | PSP_CTRL_START | PSP_CTRL_SELECT) #define PAD_CHECK_TIME 53 -void InputHandler::init() { - sceCtrlSetSamplingCycle(0); // set sampling to vsync. n = n usecs - sceCtrlSetSamplingMode(1); // analog +Button::Button() { + clear(); } -bool InputHandler::getAllInputs(Common::Event &event) { - DEBUG_ENTER_FUNC(); +inline void Button::clear() { + _key = Common::KEYCODE_INVALID; + _ascii = 0; + _flag = 0; + _pspEventDown.clear(); + _pspEventUp.clear(); +} - uint32 time = g_system->getMillis(); // may not be necessary with read - if (time - _lastPadCheckTime < PAD_CHECK_TIME) { - return false; +inline bool Button::getEvent(Common::Event &event, PspEvent &pspEvent, bool down) { + if (down) { + if (!_pspEventDown.isEmpty()) + pspEvent = _pspEventDown; + } else { // up + if (!_pspEventUp.isEmpty()) + pspEvent = _pspEventUp; } + if (_key != Common::KEYCODE_INVALID) { + event.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; + event.kbd.keycode = _key; + event.kbd.ascii = _ascii; + event.kbd.flags |= _flag; + return true; + } else if (_flag) { // handle flag only events + event.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; + event.kbd.flags |= down ? _flag : 0; + return true; + } + return false; +} - _lastPadCheckTime = time; - SceCtrlData pad; - - sceCtrlPeekBufferPositive(&pad, 1); // Peek ignores sleep. Read sleeps thread - - bool haveEvent; - - memset(&event, 0, sizeof(event)); +void Button::setPspEvent(PspEventType typeDown, uint32 dataDown, PspEventType typeUp, uint32 dataUp) { + _pspEventDown.type = typeDown; + _pspEventDown.data = dataDown; + _pspEventUp.type = typeUp; + _pspEventUp.data = dataUp; +} - if (_keyboard->isVisible()) - haveEvent = _keyboard->processInput(event, pad); - else - haveEvent = getEvent(event, pad); +// Translates bitfields to our constants +// We put combined bitfields first to make sure we pick up diagonals +const uint32 ButtonPad::_buttonMap[] = { + PSP_CTRL_UP | PSP_CTRL_LEFT, + PSP_CTRL_UP | PSP_CTRL_RIGHT, + PSP_CTRL_DOWN | PSP_CTRL_RIGHT, + PSP_CTRL_DOWN | PSP_CTRL_LEFT, + PSP_CTRL_RIGHT, PSP_CTRL_DOWN, PSP_CTRL_LEFT, PSP_CTRL_UP, + PSP_CTRL_CROSS, PSP_CTRL_CIRCLE, PSP_CTRL_TRIANGLE, PSP_CTRL_SQUARE, + PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER, PSP_CTRL_START, PSP_CTRL_SELECT +}; + +ButtonPad::ButtonPad() : _prevButtonState(0), _shifted(UNSHIFTED), _padMode(PAD_MODE_NORMAL), + _comboMode(false) { + for (int i = UNSHIFTED; i < SHIFTED_MODE_LAST; i++) + _buttonsChanged[i] = 0; + clearButtons(); +} - if (haveEvent) { - PSP_DEBUG_PRINT("Have event[%s]\n", haveEvent ? "true" : "false"); - PSP_DEBUG_PRINT("event.type[%d]\n", event.type); +void ButtonPad::clearButtons() { + for (int i = BTN_UP_LEFT; i < BTN_LAST; i++) { + _button[i][UNSHIFTED].clear(); + _button[i][SHIFTED].clear(); } +} - return haveEvent; +void ButtonPad::initButtons() { + switch (_padMode) { + case PAD_MODE_NORMAL: + initButtonsNormalMode(); + break; + case PAD_MODE_LOL: + initButtonsLolMode(); + break; + default: + break; + } } -bool InputHandler::getEvent(Common::Event &event, SceCtrlData &pad) { +void ButtonPad::initButtonsNormalMode() { DEBUG_ENTER_FUNC(); + PSP_DEBUG_PRINT("initializing buttons for normal mode\n"); + clearButtons(); + + // Dpad + _button[BTN_UP_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP7, '7'); + _button[BTN_LEFT][SHIFTED].setKey(Common::KEYCODE_KP7, '7'); // same as up_left + _button[BTN_UP][UNSHIFTED].setKey(Common::KEYCODE_KP8, '8'); + _button[BTN_UP_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP9, '9'); + _button[BTN_UP][SHIFTED].setKey(Common::KEYCODE_KP9, '9'); // same as up_right + _button[BTN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP4, '4'); + _button[BTN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP6, '6'); + _button[BTN_DOWN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP1, '1'); + _button[BTN_DOWN][SHIFTED].setKey(Common::KEYCODE_KP1, '1'); // same as down_left + _button[BTN_DOWN][UNSHIFTED].setKey(Common::KEYCODE_KP2, '2'); + _button[BTN_DOWN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP3, '3'); + _button[BTN_RIGHT][SHIFTED].setKey(Common::KEYCODE_KP3, '3'); // same as down_right + + // Other buttons + _button[BTN_CROSS][UNSHIFTED].setPspEvent(PSP_EVENT_LBUTTON, true, PSP_EVENT_LBUTTON, false); + _button[BTN_CIRCLE][UNSHIFTED].setPspEvent(PSP_EVENT_RBUTTON, true, PSP_EVENT_RBUTTON, false); + _button[BTN_TRIANGLE][UNSHIFTED].setKey(Common::KEYCODE_RETURN, '\r'); + _button[BTN_SQUARE][UNSHIFTED].setKey(Common::KEYCODE_PERIOD, '.'); + _button[BTN_SQUARE][SHIFTED].setKey(Common::KEYCODE_SPACE, ' '); + _button[BTN_LTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_ESCAPE, 27); + _button[BTN_RTRIGGER][SHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false); + _button[BTN_RTRIGGER][UNSHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false); + _button[BTN_RTRIGGER][SHIFTED].setKey(Common::KEYCODE_INVALID, 0, Common::KBD_SHIFT); + _button[BTN_RTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_INVALID, 0, Common::KBD_SHIFT); + _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5); + _button[BTN_START][UNSHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL); + _button[BTN_SELECT][UNSHIFTED].setPspEvent(PSP_EVENT_SHOW_VIRTUAL_KB, true, PSP_EVENT_NONE, 0); +} - _buttonsChanged = pad.Buttons ^ _prevButtons; - bool haveEvent = false; +void ButtonPad::initButtonsLolMode() { + DEBUG_ENTER_FUNC(); + initButtonsNormalMode(); // set normal button configuration + PSP_DEBUG_PRINT("initializing buttons for LOL mode\n"); + + // Square is our new shift button + _button[BTN_SQUARE][UNSHIFTED].clear(); + _button[BTN_SQUARE][UNSHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false); + _button[BTN_SQUARE][SHIFTED].clear(); + _button[BTN_SQUARE][SHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false); + + // Dpad + _button[BTN_LEFT][UNSHIFTED].clear(); + _button[BTN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP7, '7'); + _button[BTN_LEFT][SHIFTED].clear(); + _button[BTN_LEFT][SHIFTED].setKey(Common::KEYCODE_F1, Common::ASCII_F1); + _button[BTN_UP][SHIFTED].clear(); + _button[BTN_UP][SHIFTED].setKey(Common::KEYCODE_F2, Common::ASCII_F2); + _button[BTN_RIGHT][UNSHIFTED].clear(); + _button[BTN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP9, '9'); + _button[BTN_RIGHT][SHIFTED].clear(); + _button[BTN_RIGHT][SHIFTED].setKey(Common::KEYCODE_F3, Common::ASCII_F3); + _button[BTN_DOWN][SHIFTED].clear(); + _button[BTN_DOWN][SHIFTED].setKey(Common::KEYCODE_F4, Common::ASCII_F4); + + // Buttons + _button[BTN_LTRIGGER][UNSHIFTED].clear(); + _button[BTN_LTRIGGER][SHIFTED].clear(); + _button[BTN_LTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_KP4, '4'); // Triggers turn + _button[BTN_RTRIGGER][UNSHIFTED].clear(); + _button[BTN_RTRIGGER][SHIFTED].clear(); + _button[BTN_RTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_KP6, '6'); + _button[BTN_START][SHIFTED].clear(); + _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_ESCAPE, 27); +} - // Collect events from different sources - haveEvent = getDpadEvent(event, pad); +bool ButtonPad::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); - if (!haveEvent) - haveEvent = getButtonEvent(event, pad); + //PSP_DEBUG_PRINT("buttons[%x]\n", pad.Buttons); - if (!haveEvent) - haveEvent = getNubEvent(event, pad); + uint32 curButtonState = PSP_ALL_BUTTONS & pad.Buttons; // we only care about these - _prevButtons = pad.Buttons; + modifyButtonsForCombos(pad); // change buttons for combos - return haveEvent; + return getEventFromButtonState(event, pspEvent, curButtonState); } -bool InputHandler::getDpadEvent(Common::Event &event, SceCtrlData &pad) { +bool ButtonPad::getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState) { DEBUG_ENTER_FUNC(); + _buttonsChanged[_shifted] |= buttonState ^ _prevButtonState; // add any buttons that changed + _prevButtonState = buttonState; + + for (int shiftState = UNSHIFTED; shiftState < SHIFTED_MODE_LAST; shiftState++) { + if (_buttonsChanged[shiftState]) { // any button to address? + PSP_DEBUG_PRINT("found changed buttons\n"); + ButtonType buttonType = BTN_LAST; + bool buttonDown = false; // normally we release a button (as in when we're in a different shiftmode) + + for (int i = BTN_UP_LEFT; i < BTN_LAST; i++) { + uint32 buttonCode = _buttonMap[i]; + if ((_buttonsChanged[shiftState] & buttonCode) == buttonCode) { // check for this changed button + buttonType = (ButtonType)i; // we know which button changed + _buttonsChanged[shiftState] &= ~buttonCode; // save the fact that we treated this button + if (shiftState == _shifted) + buttonDown = buttonState & buttonCode ? true : false; // pressed or released? + + PSP_DEBUG_PRINT("button[%i] pressed\n", i); + break; + } + } - int newDpadX = 0, newDpadY = 0; - bool haveEvent = false; - - if (DOWN(PSP_CTRL_UP)) { - newDpadY++; - if (DOWN(PSP_CTRL_RTRIGGER)) // Shifting causes diagonals - newDpadX++; - } - if (DOWN(PSP_CTRL_RIGHT)) { - newDpadX++; - if (DOWN(PSP_CTRL_RTRIGGER)) - newDpadY--; - } - if (DOWN(PSP_CTRL_DOWN)) { - newDpadY--; - if (DOWN(PSP_CTRL_RTRIGGER)) - newDpadX--; - } - if (DOWN(PSP_CTRL_LEFT)) { - newDpadX--; - if (DOWN(PSP_CTRL_RTRIGGER)) - newDpadY++; - } - - if (newDpadX != _dpadX || newDpadY != _dpadY) { - if (_dpadX == 0 && _dpadY == 0) { // We were in the middle so we pressed dpad - event.type = Common::EVENT_KEYDOWN; - event.kbd.keycode = translateDpad(newDpadX, newDpadY); - event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; // Get ascii - _dpadX = newDpadX; - _dpadY = newDpadY; - } else if (newDpadX == 0 && newDpadY == 0) {// We're now centered so we unpressed dpad - event.type = Common::EVENT_KEYUP; - event.kbd.keycode = translateDpad(_dpadX, _dpadY); - event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; - _dpadX = newDpadX; - _dpadY = newDpadY; - } else { // we moved from one pressed dpad direction to another one - event.type = Common::EVENT_KEYUP; // first release the last dpad direction - event.kbd.keycode = translateDpad(_dpadX, _dpadY); - event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; - _dpadX = 0; // so that we'll pick up a new dpad movement the next round - _dpadY = 0; + assert (buttonType < BTN_LAST); + bool haveEvent = _button[buttonType][shiftState].getEvent(event, pspEvent, buttonDown); + if (haveEvent) + PSP_DEBUG_PRINT("have event. key[%d] flag[%x] %s\n", event.kbd.ascii, event.kbd.flags, buttonDown ? "down" : "up"); + return haveEvent; } - - PSP_DEBUG_PRINT("Keypad event. DpadX[%d], DpadY[%d]\n", _dpadX, _dpadY); - haveEvent = true; } - return haveEvent; + return false; } -inline Common::KeyCode InputHandler::translateDpad(int x, int y) { - DEBUG_ENTER_FUNC(); - Common::KeyCode key; - - if (x == -1) { - if (y == -1) - key = Common::KEYCODE_KP1; - else if (y == 0) - key = Common::KEYCODE_KP4; - else /* y == 1 */ - key = Common::KEYCODE_KP7; - } else if (x == 0) { - if (y == -1) - key = Common::KEYCODE_KP2; - else /* y == 1 */ - key = Common::KEYCODE_KP8; - } else {/* x == 1 */ - if (y == -1) - key = Common::KEYCODE_KP3; - else if (y == 0) - key = Common::KEYCODE_KP6; - else /* y == 1 */ - key = Common::KEYCODE_KP9; +void ButtonPad::modifyButtonsForCombos(SceCtrlData &pad) { + if (DOWN(PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER)) { + if (!_comboMode) { // we're entering combo mode + PSP_DEBUG_PRINT("entering combo mode\n"); + _button[BTN_SQUARE][UNSHIFTED].clear(); + _button[BTN_SQUARE][SHIFTED].clear(); + _button[BTN_DOWN][SHIFTED].clear(); + _button[BTN_DOWN][UNSHIFTED].clear(); + _button[BTN_UP][SHIFTED].clear(); + _button[BTN_UP][UNSHIFTED].clear(); + _button[BTN_SQUARE][UNSHIFTED].setPspEvent(PSP_EVENT_MODE_SWITCH, true, PSP_EVENT_NONE, true); + _button[BTN_SQUARE][SHIFTED].setPspEvent(PSP_EVENT_MODE_SWITCH, true, PSP_EVENT_NONE, true); + _button[BTN_DOWN][UNSHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, false, PSP_EVENT_NONE, true); + _button[BTN_DOWN][SHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, false, PSP_EVENT_NONE, true); + _button[BTN_UP][UNSHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, true, PSP_EVENT_NONE, true); + _button[BTN_UP][SHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, true, PSP_EVENT_NONE, true); + _comboMode = true; + } + } else { // no combo buttons are pressed now + if (_comboMode) { // we have been running in combo mode + initButtons(); // reset the button configuration + _comboMode = false; + } } - - return key; } - -bool InputHandler::getButtonEvent(Common::Event &event, SceCtrlData &pad) { +bool Nub::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); - bool haveEvent = false; - if (PRESSED(PSP_CTRL_SELECT)) - _keyboard->setVisible(true); - - else if (CHANGED(PSP_4BUTTONS | PSP_TRIGGERS | PSP_CTRL_START)) { - if (CHANGED(PSP_CTRL_CROSS)) { - event.type = DOWN(PSP_CTRL_CROSS) ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP; - event.mouse.x = _cursor->getX(); // Could this have to do with SCI enter problem? - event.mouse.y = _cursor->getY(); - PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "LButtonDown" : "LButtonUp"); - } else if (CHANGED(PSP_CTRL_CIRCLE)) { - event.type = DOWN(PSP_CTRL_CIRCLE) ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP; - event.mouse.x = _cursor->getX(); - event.mouse.y = _cursor->getY(); - PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "RButtonDown" : "RButtonUp"); - } else { - //any of the other buttons. - event.type = _buttonsChanged & pad.Buttons ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; - event.kbd.ascii = 0; - event.kbd.flags = 0; - - if (CHANGED(PSP_CTRL_LTRIGGER)) { - event.kbd.keycode = Common::KEYCODE_ESCAPE; - event.kbd.ascii = 27; - } else if (CHANGED(PSP_CTRL_START)) { - event.kbd.keycode = Common::KEYCODE_F5; - event.kbd.ascii = Common::ASCII_F5; - if (DOWN(PSP_CTRL_RTRIGGER)) { - event.kbd.flags |= Common::KBD_CTRL; // Main menu to allow RTL - } - } else if (CHANGED(PSP_CTRL_SQUARE)) { - event.kbd.keycode = Common::KEYCODE_PERIOD; - event.kbd.ascii = '.'; - } else if (CHANGED(PSP_CTRL_TRIANGLE)) { - event.kbd.keycode = Common::KEYCODE_RETURN; - event.kbd.ascii = '\r'; - } else if (DOWN(PSP_CTRL_RTRIGGER)) { // An event - event.kbd.flags |= Common::KBD_SHIFT; - } - PSP_DEBUG_PRINT("Ascii[%d]. Key %s.\n", event.kbd.ascii, event.type == Common::EVENT_KEYDOWN ? "down" : "up"); - } - - haveEvent = true; + if (_dpadMode) { // Convert the nub to a D-Pad + uint32 buttonState; + translateToDpadState(pad.Lx, pad.Ly, buttonState); + return _buttonPad.getEventFromButtonState(event, pspEvent, buttonState); } - return haveEvent; -} - -bool InputHandler::getNubEvent(Common::Event &event, SceCtrlData &pad) { - DEBUG_ENTER_FUNC(); - - bool haveEvent = false; int32 analogStepX = pad.Lx; // Goes up to 255. int32 analogStepY = pad.Ly; - int32 oldX = _cursor->getX(); - int32 oldY = _cursor->getY(); - analogStepX = modifyNubAxisMotion(analogStepX); analogStepY = modifyNubAxisMotion(analogStepY); + int32 oldX = _cursor->getX(); + int32 oldY = _cursor->getY(); + if (analogStepX != 0 || analogStepY != 0) { PSP_DEBUG_PRINT("raw x[%d], y[%d]\n", analogStepX, analogStepY); // If no movement then this has no effect - if (DOWN(PSP_CTRL_RTRIGGER)) { + if (_shifted) { // Fine control mode for analog if (analogStepX != 0) { if (analogStepX > 0) @@ -281,15 +315,29 @@ bool InputHandler::getNubEvent(Common::Event &event, SceCtrlData &pad) { event.type = Common::EVENT_MOUSEMOVE; event.mouse.x = newX; event.mouse.y = newY; - haveEvent = true; - PSP_DEBUG_PRINT("Nub event. X[%d], Y[%d]\n", newX, newY); + return true; } } - return haveEvent; + return false; +} + +void Nub::translateToDpadState(int dpadX, int dpadY, uint32 &buttonState) { + #define MIN_NUB_POSITION 70 + buttonState = 0; + + if (dpadX > 127 + MIN_NUB_POSITION) + buttonState |= PSP_CTRL_RIGHT; + else if (dpadX < 127 - MIN_NUB_POSITION) + buttonState |= PSP_CTRL_LEFT; + + if (dpadY > 127 + MIN_NUB_POSITION) + buttonState |= PSP_CTRL_DOWN; + else if (dpadY < 127 - MIN_NUB_POSITION) + buttonState |= PSP_CTRL_UP; } -inline int32 InputHandler::modifyNubAxisMotion(int32 input) { +inline int32 Nub::modifyNubAxisMotion(int32 input) { DEBUG_ENTER_FUNC(); const int MIN_NUB_MOTION = 30; @@ -304,3 +352,160 @@ inline int32 InputHandler::modifyNubAxisMotion(int32 input) { return input; } + +inline bool Nub::isButtonDown() { + if (_dpadMode) // only relevant in dpad mode + return _buttonPad.isButtonDown(); + return false; +} + +const char *InputHandler::_padModeText[] = { + "Normal Button Mode", + "1st Person RPG Button Mode" +}; + +void InputHandler::init() { + sceCtrlSetSamplingCycle(0); // set sampling to vsync. n = n usecs + sceCtrlSetSamplingMode(1); // analog + + _buttonPad.initButtons(); +} + +bool InputHandler::getAllInputs(Common::Event &event) { + DEBUG_ENTER_FUNC(); + + uint32 time = g_system->getMillis(); // may not be necessary with read + if (time - _lastPadCheckTime < PAD_CHECK_TIME) { + return false; + } + + _lastPadCheckTime = time; + SceCtrlData pad; + + sceCtrlPeekBufferPositive(&pad, 1); // Peek doesn't sleep. Read sleeps the thread + + bool haveEvent; + //memset(&event, 0, sizeof(event)); + + haveEvent = getEvent(event, pad); + + if (haveEvent) { + PSP_DEBUG_PRINT("Have event[%s]. Type[%d]\n", haveEvent ? "true" : "false", event.type); + } + + return haveEvent; +} + +bool InputHandler::getEvent(Common::Event &event, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + + PspEvent pspEvent; + bool haveEvent = false; + + if (_keyboard->isVisible()) { + haveEvent = _keyboard->processInput(event, pspEvent, pad); + } else { // only process buttonpad if keyboard invisible + haveEvent = _buttonPad.getEvent(event, pspEvent, pad); + } + + if (!haveEvent && pspEvent.isEmpty()) + haveEvent = _nub.getEvent(event, pspEvent, pad); + + // handle any pending PSP events + if (!haveEvent && pspEvent.isEmpty()) { + if (!_pendingPspEvent.isEmpty()) { + pspEvent = _pendingPspEvent; + _pendingPspEvent.clear(); + } + } + + // handle any PSP events we might have + if (!pspEvent.isEmpty()) + haveEvent |= handlePspEvent(event, pspEvent); // overrides any event we might have + + return haveEvent; +} + +bool InputHandler::handlePspEvent(Common::Event &event, PspEvent &pspEvent) { + bool haveEvent = false; + + PSP_DEBUG_PRINT("have pspEvent[%d] data[%d]\n", pspEvent.type, pspEvent.data); + + switch (pspEvent.type) { + case PSP_EVENT_SHIFT: + handleShiftEvent((ShiftMode)pspEvent.data); + break; + case PSP_EVENT_SHOW_VIRTUAL_KB: + _keyboard->setVisible((bool)pspEvent.data); + if ((pspEvent.data && _keyboard->isVisible()) || !pspEvent.data) // don't change mode if keyboard didn't load + _nub.setDpadMode((bool)pspEvent.data); // set nub to keypad/regular mode + break; + case PSP_EVENT_LBUTTON: + haveEvent = true; + if (pspEvent.data) // down + handleMouseEvent(event, Common::EVENT_LBUTTONDOWN, "LButtonDown"); + else + handleMouseEvent(event, Common::EVENT_LBUTTONUP, "LButtonUp"); + break; + case PSP_EVENT_RBUTTON: + haveEvent = true; + if (pspEvent.data) // down + handleMouseEvent(event, Common::EVENT_RBUTTONDOWN, "RButtonDown"); + else + handleMouseEvent(event, Common::EVENT_RBUTTONUP, "RButtonUp"); + break; + case PSP_EVENT_MODE_SWITCH: + handleModeSwitchEvent(); + break; + /*case PSP_EVENT_CHANGE_SPEED: + handleSpeedChange(pspEvent.data); + break;*/ + default: + PSP_ERROR("Unhandled PSP Event[%d]\n", pspEvent.type); + break; + } + + return haveEvent; +} + +void InputHandler::handleMouseEvent(Common::Event &event, Common::EventType type, const char *string) { + event.type = type; + event.mouse.x = _cursor->getX(); + event.mouse.y = _cursor->getY(); + PSP_DEBUG_PRINT("%s event, x[%d], y[%d]\n", string, event.mouse.x, event.mouse.y); +} + +void InputHandler::handleShiftEvent(ShiftMode shifted) { + _buttonPad.setShifted(shifted); + _nub.setShifted(shifted); +} + +void InputHandler::handleModeSwitchEvent() { + // check if we can't switch modes right now + if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet + PSP_DEBUG_PRINT("postponing mode switch event\n"); + _pendingPspEvent.type = PSP_EVENT_MODE_SWITCH; // queue it to be done later + } else { // we can switch + PSP_DEBUG_PRINT("mode switch event\n"); + _padMode = (PspPadMode)(_padMode + 1); + if (_padMode >= PAD_MODE_LAST) + _padMode = PAD_MODE_NORMAL; + + GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500); + dialog.runModal(); + + _buttonPad.setPadMode(_padMode); + _buttonPad.initButtons(); + } +} + +/* +void InputHandler::handleSpeedChange(bool up) { + char *dialogMsg; + + if (up) { + dialogMsg = " + + GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500); + dialog.runModal(); +}*/ diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h index cd686d9e02..acca04f376 100644 --- a/backends/platform/psp/input.h +++ b/backends/platform/psp/input.h @@ -28,36 +28,154 @@ #include "common/scummsys.h" #include "common/events.h" -#include "backends/platform/psp/display_client.h" -#include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/pspkeyboard.h" #include "backends/platform/psp/cursor.h" #include <pspctrl.h> +enum PspEventType { + PSP_EVENT_NONE = 0, + PSP_EVENT_SHIFT, + PSP_EVENT_SHOW_VIRTUAL_KB, + PSP_EVENT_LBUTTON, + PSP_EVENT_RBUTTON, + PSP_EVENT_MODE_SWITCH, + PSP_EVENT_CHANGE_SPEED, + PSP_EVENT_LAST +}; + + +struct PspEvent { + PspEventType type; + uint32 data; + PspEvent() { clear(); } + void clear() { + type = PSP_EVENT_NONE; + data = 0; + } + bool isEmpty() { return type == PSP_EVENT_NONE; } +}; + +enum PspPadMode { + PAD_MODE_NORMAL, + PAD_MODE_LOL, + PAD_MODE_LAST +}; + +enum ShiftMode { + UNSHIFTED = 0, + SHIFTED = 1, + SHIFTED_MODE_LAST +}; + + +class Button { +private: + Common::KeyCode _key; + uint32 _ascii; + uint32 _flag; + PspEvent _pspEventDown; // event when we press + PspEvent _pspEventUp; // event when we release +public: + Button(); + void clear(); + bool getEvent(Common::Event &event, PspEvent &pspEvent, bool buttonDown); + void setKey(Common::KeyCode key, uint32 ascii = 0, uint32 flag = 0) { _key = key; _ascii = ascii; _flag = flag; } + void setPspEvent(PspEventType typeDown, uint32 dataDown, PspEventType typeUp, uint32 dataUp); +}; + +class ButtonPad { +public: + enum ButtonType { // must match the buttonMap + BTN_UP_LEFT, + BTN_UP_RIGHT, + BTN_DOWN_RIGHT, + BTN_DOWN_LEFT, + BTN_RIGHT, + BTN_DOWN, + BTN_LEFT, + BTN_UP, + BTN_CROSS, + BTN_CIRCLE, + BTN_TRIANGLE, + BTN_SQUARE, + BTN_LTRIGGER, + BTN_RTRIGGER, + BTN_START, + BTN_SELECT, + BTN_LAST + }; + +private: + Button _button[BTN_LAST][SHIFTED_MODE_LAST]; + uint32 _buttonsChanged[SHIFTED_MODE_LAST]; // normal and shifted + uint32 _prevButtonState; + ShiftMode _shifted; + PspPadMode _padMode; + bool _comboMode; // are we in the middle of combos + static const uint32 _buttonMap[]; // maps the buttons to their values + + void initButtonsNormalMode(); + void initButtonsLolMode(); + void modifyButtonsForCombos(SceCtrlData &pad); + void clearButtons(); + +public: + ButtonPad(); + bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); + bool getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState); + void setShifted(ShiftMode shifted) { _shifted = shifted; } + void setPadMode(PspPadMode mode) { _padMode = mode; } + bool isButtonDown() { return _prevButtonState; } + void initButtons(); +}; + +class Nub { +private: + Cursor *_cursor; // to enable changing/getting cursor position + + ButtonPad _buttonPad; // private buttonpad for dpad mode + ShiftMode _shifted; + bool _dpadMode; + +public: + Nub() : _shifted(UNSHIFTED), _dpadMode(false) { _buttonPad.initButtons(); } + + void setCursor(Cursor *cursor) { _cursor = cursor; } + void setDpadMode(bool active) { _dpadMode = active; } + void setShifted(ShiftMode shifted) { _shifted = shifted; } + bool isButtonDown(); + + bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); + int32 modifyNubAxisMotion(int32 input); + void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data +}; + class InputHandler { public: - InputHandler() : _cursor(0), _keyboard(0), _prevButtons(0), _lastPadCheckTime(0), _buttonsChanged(0), _dpadX(0), _dpadY(0) {} + InputHandler() : _keyboard(0), _cursor(0), _padMode(PAD_MODE_NORMAL), _lastPadCheckTime(0) {} + void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } + void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); } void init(); bool getAllInputs(Common::Event &event); - void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } - void setCursor(Cursor *cursor) { _cursor = cursor; } private: - Cursor *_cursor; PSPKeyboard *_keyboard; - uint32 _prevButtons; + Cursor *_cursor; + + Nub _nub; + ButtonPad _buttonPad; + + PspPadMode _padMode; // whice mode we're in + PspEvent _pendingPspEvent; // an event that can't be handled yet uint32 _lastPadCheckTime; - uint32 _buttonsChanged; - int32 _dpadX, _dpadY; - int32 _accelX, _accelY; + static const char *_padModeText[]; bool getEvent(Common::Event &event, SceCtrlData &pad); - bool getDpadEvent(Common::Event &event, SceCtrlData &pad); - bool getButtonEvent(Common::Event &event, SceCtrlData &pad); - bool getNubEvent(Common::Event &event, SceCtrlData &pad); - int32 modifyNubAxisMotion(int32 input); - Common::KeyCode translateDpad(int x, int y); + bool handlePspEvent(Common::Event &event, PspEvent &pspEvent); + void handleMouseEvent(Common::Event &event, Common::EventType type, const char *string); + void handleShiftEvent(ShiftMode shifted); + void handleModeSwitchEvent(); }; #endif /* PSP_INPUT_H */ diff --git a/backends/platform/psp/memory.cpp b/backends/platform/psp/memory.cpp index 29d0482d9a..924ab356e8 100644 --- a/backends/platform/psp/memory.cpp +++ b/backends/platform/psp/memory.cpp @@ -25,8 +25,8 @@ #include "common/scummsys.h" #include "common/singleton.h" -#include "common/list.h" #include "backends/platform/psp/psppixelformat.h" +#define PSP_INCLUDE_SWAP #include "backends/platform/psp/memory.h" // Class Copier -------------------------------------------------------------------------- @@ -37,23 +37,6 @@ //#define TEST_MEMORY_COPY -extern "C" { - -#ifdef TEST_MEMORY_COPY /* we won't be able to run in this case b/c of printouts */ -extern void *__real_memcpy(void *dst, void *src, size_t bytes); -#endif - -void *__wrap_memcpy(void *dst, void *src, size_t bytes) { -#ifdef TEST_MEMORY_COPY /* we won't be able to run in this case */ - return __real_memcpy(dst, src, bytes); -#else - PspMemory::fastCopy((byte *)dst, (byte *)src, bytes); - return dst; -#endif -} - -} - void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) { DEBUG_ENTER_FUNC(); @@ -66,29 +49,29 @@ void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) { // align the destination pointer first uint32 prefixDst = (((uint32)dst) & 0x3); - + if (prefixDst) { - prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0 + prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0 PSP_DEBUG_PRINT("prefixDst[%d]\n", prefixDst); bytes -= prefixDst; // remember we assume bytes >= 4 - + if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue copy8(dst, src, bytes + prefixDst); #ifdef TEST_MEMORY_COPY testCopy(debugDst, debugSrc, debugBytes); -#endif +#endif return; } - + while (prefixDst--) { *dst++ = *src++; - } + } } - + // check the source pointer alignment now uint32 alignSrc = (((uint32)src) & 0x3); - + if (alignSrc) { // we'll need to realign our reads copy32Misaligned((uint32 *)dst, src, bytes, alignSrc); } else { @@ -97,104 +80,14 @@ void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) { #ifdef TEST_MEMORY_COPY testCopy(debugDst, debugSrc, debugBytes); -#endif -} - -void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) { - - bool mismatch = false; - PSP_INFO_PRINT("testing fastCopy..."); - - for (uint32 i = 0; i < debugBytes; i++) { - if (debugDst[i] != debugSrc[i]) { - if (!mismatch) { - PSP_INFO_PRINT("**** mismatch in copy! ****\n"); - PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes); - mismatch = true; - } - PSP_INFO_PRINT("[%d]%x!=%x ", i, debugSrc[i], debugDst[i]); - } - } - if (mismatch) { - PSP_INFO_PRINT("\n"); - } else { - PSP_INFO_PRINT("ok\n"); - } -} - -// -// used to swap red and blue -void PspMemory::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { - DEBUG_ENTER_FUNC(); - -#ifdef TEST_MEMORY_COPY - uint32 debugBytes = bytes; - const uint16 *debugDst = dst16, *debugSrc = src16; #endif - - // align the destination pointer first - uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix - - if (prefixDst) { - bytes -= prefixDst; // remember we assume bytes > 4 - *dst16++ = format.swapRedBlue16(*src16++); - - if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue - swap16(dst16, src16, bytes, format); - -#ifdef TEST_MEMORY_COPY - testSwap(debugDst, debugSrc, debugBytes, format); -#endif - return; - } - } - - // check the source pointer alignment now - uint32 alignSrc = (((uint32)src16) & 0x3); - - if (alignSrc) { // we'll need to realign our reads - PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16); - swap32Misaligned((uint32 *)dst16, src16, bytes, format); - } else { - swap32Aligned((uint32 *)dst16, (const uint32 *)src16, bytes, format); - } - -#ifdef TEST_MEMORY_COPY - testSwap(debugDst, debugSrc, debugBytes, format); -#endif - -} - -void PspMemory::testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format) { - - bool mismatch = false; - PSP_INFO_PRINT("testing fastSwap..."); - - uint32 shorts = debugBytes >> 1; - - for (uint32 i = 0; i < shorts; i++) { - if (debugDst[i] != format.swapRedBlue16(debugSrc[i])) { - if (!mismatch) { - PSP_INFO_PRINT("**** mismatch in swap! ****\n"); - PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes); - mismatch = true; - } - PSP_INFO_PRINT("[%d]%x!=%x ", i<<1, format.swapRedBlue16(debugSrc[i]), debugDst[i]); - } - } - if (mismatch) { - PSP_INFO_PRINT("\n"); - } else { - PSP_INFO_PRINT("ok\n"); - } } - void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) { PSP_DEBUG_PRINT("copy32Aligned(): dst32[%p], src32[%p], bytes[%d]\n", dst32, src32, bytes); int words8 = bytes >> 5; - + // try blocks of 8 words at a time if (words8) { while (words8--) { @@ -217,11 +110,11 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) dst32[7] = d; dst32 += 8; src32 += 8; - } + } } - + int words4 = (bytes & 0x1F) >> 4; - + // try blocks of 4 words at a time if (words4) { uint32 a, b, c, d; @@ -236,10 +129,10 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) dst32 += 4; src32 += 4; } - + int bytesLeft = (bytes & 0xF); // only look at bytes left after we did the above int wordsLeft = bytesLeft >> 2; - + // now just do single words while (wordsLeft) { *dst32++ = *src32++; @@ -252,55 +145,20 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) byte *dst = (byte *)dst32; byte *src = (byte *)src32; - + while (bytesLeft--) { *dst++ = *src++; } } -void PspMemory::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) { - DEBUG_ENTER_FUNC(); - int words4 = bytes >> 4; - - // try blocks of 4 words at a time - while (words4--) { - uint32 a, b, c, d; - a = format.swapRedBlue32(src32[0]); - b = format.swapRedBlue32(src32[1]); - c = format.swapRedBlue32(src32[2]); - d = format.swapRedBlue32(src32[3]); - dst32[0] = a; - dst32[1] = b; - dst32[2] = c; - dst32[3] = d; - dst32 += 4; - src32 += 4; - } - - uint32 bytesLeft = bytes & 0xF; - uint32 words = bytesLeft >> 2; - - // now just do words - while (words--) { - *dst32++ = format.swapRedBlue32(*src32++); - } - - bytesLeft = bytes & 0x3; - - if (bytesLeft) { // for swap, can only be 1 short left - *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32)); - } -} - - // More challenging -- need to shift // Assume dst is aligned void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc) { PSP_DEBUG_PRINT("copy32Misaligned: dst32[%p], src[%p], bytes[%d], alignSrc[%d]\n", dst32, src, bytes, alignSrc); - + uint32 *src32 = (uint32 *)(((uint32)src) & 0xFFFFFFFC); // remove misalignment uint32 shiftValue, lastShiftValue; - + switch (alignSrc) { case 1: shiftValue = 8; @@ -320,9 +178,9 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u // Try to do groups of 4 words uint32 words4 = bytes >> 4; - + srcWord = *src32; // preload 1st word so we read ahead - + for (; words4; words4--) { dstWord = srcWord >> shiftValue; srcWord = src32[1]; @@ -343,12 +201,12 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u src32 += 4; dst32 += 4; } - + uint32 words = (bytes & 0xF) >> 2; // now get remaining words - + // we read one word ahead of what we write // setup the first read - + for (; words ;words--) { dstWord = srcWord >> shiftValue; srcWord = src32[1]; // we still go one ahead @@ -356,9 +214,9 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u dstWord |= srcWord << lastShiftValue; *dst32++ = dstWord; } - + uint32 bytesLeft = bytes & 3; // and remaining bytes - + if (bytesLeft) { byte *dst8 = (byte *)dst32; byte *src8 = ((byte *)src32) + ((uint32)src & 0x3); // get exact location we should be at @@ -369,14 +227,137 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u } } +void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) { + + bool mismatch = false; + PSP_INFO_PRINT("testing fastCopy..."); + + for (uint32 i = 0; i < debugBytes; i++) { + if (debugDst[i] != debugSrc[i]) { + if (!mismatch) { + PSP_INFO_PRINT("**** mismatch in copy! ****\n"); + PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes); + mismatch = true; + } + PSP_INFO_PRINT("[%d]%x!=%x ", i, debugSrc[i], debugDst[i]); + } + } + if (mismatch) { + PSP_INFO_PRINT("\n"); + } else { + PSP_INFO_PRINT("ok\n"); + } +} + +// +// used to swap red and blue +void PspMemorySwap::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { + DEBUG_ENTER_FUNC(); + +#ifdef TEST_MEMORY_COPY + uint32 debugBytes = bytes; + const uint16 *debugDst = dst16, *debugSrc = src16; +#endif + + // align the destination pointer first + uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix + + if (prefixDst) { + bytes -= prefixDst; // remember we assume bytes > 4 + *dst16++ = format.swapRedBlue16(*src16++); + + if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue + swap16(dst16, src16, bytes, format); + +#ifdef TEST_MEMORY_COPY + testSwap(debugDst, debugSrc, debugBytes, format); +#endif + return; + } + } + + // check the source pointer alignment now + uint32 alignSrc = (((uint32)src16) & 0x3); + + if (alignSrc) { // we'll need to realign our reads + PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16); + swap32Misaligned((uint32 *)dst16, src16, bytes, format); + } else { + swap32Aligned((uint32 *)dst16, (const uint32 *)src16, bytes, format); + } + +#ifdef TEST_MEMORY_COPY + testSwap(debugDst, debugSrc, debugBytes, format); +#endif + +} + +void PspMemorySwap::testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format) { + + bool mismatch = false; + PSP_INFO_PRINT("testing fastSwap..."); + + uint32 shorts = debugBytes >> 1; + + for (uint32 i = 0; i < shorts; i++) { + if (debugDst[i] != format.swapRedBlue16(debugSrc[i])) { + if (!mismatch) { + PSP_INFO_PRINT("**** mismatch in swap! ****\n"); + PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes); + mismatch = true; + } + PSP_INFO_PRINT("[%d]%x!=%x ", i<<1, format.swapRedBlue16(debugSrc[i]), debugDst[i]); + } + } + if (mismatch) { + PSP_INFO_PRINT("\n"); + } else { + PSP_INFO_PRINT("ok\n"); + } +} + +void PspMemorySwap::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) { + DEBUG_ENTER_FUNC(); + int words4 = bytes >> 4; + + // try blocks of 4 words at a time + while (words4--) { + uint32 a, b, c, d; + a = format.swapRedBlue32(src32[0]); + b = format.swapRedBlue32(src32[1]); + c = format.swapRedBlue32(src32[2]); + d = format.swapRedBlue32(src32[3]); + dst32[0] = a; + dst32[1] = b; + dst32[2] = c; + dst32[3] = d; + dst32 += 4; + src32 += 4; + } + + uint32 bytesLeft = bytes & 0xF; + uint32 words = bytesLeft >> 2; + + // now just do words + while (words--) { + *dst32++ = format.swapRedBlue32(*src32++); + } + + bytesLeft = bytes & 0x3; + + if (bytesLeft) { // for swap, can only be 1 short left + *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32)); + } +} + // More challenging -- need to shift // We assume dst is aligned -void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { +void PspMemorySwap::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { DEBUG_ENTER_FUNC(); const uint32 shiftValue = 16; uint32 *src32 = (uint32 *)(((uint32)src16) & 0xFFFFFFFC); // remove misalignment - + // Try to do groups of 4 words uint32 words4 = bytes >> 4; uint32 srcWord = src32[0]; // preload @@ -401,15 +382,15 @@ void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 byte src32 += 4; dst32 += 4; } - + uint32 words = (bytes & 0xF) >> 2; - + // we read one word ahead of what we write // setup the first read if (words) { //srcWord = *src32++; // don't need this. already loaded src32++; // we already have the value loaded in - + while (words--) { uint32 dstWord = srcWord >> shiftValue; srcWord = *src32++; @@ -417,86 +398,10 @@ void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 byte *dst32++ = format.swapRedBlue32(dstWord); } } - + uint32 bytesLeft = bytes & 3; - + if (bytesLeft) { // for swap, can only be 1 short left *((uint16 *)dst32) = format.swapRedBlue16((uint16)(srcWord >> shiftValue)); } } - -inline void PspMemory::copy16(uint16 *dst16, const uint16 *src16, uint32 bytes) { - PSP_DEBUG_PRINT("copy16(): dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes); - - uint32 shorts = bytes >> 1; - uint32 remainingBytes = bytes & 1; - - for (; shorts > 0 ; shorts--) { - *dst16++ = *src16++; - } - if (remainingBytes) - *(byte *)dst16 = *(byte *)src16; -} - -// Class VramAllocator ----------------------------------- - -DECLARE_SINGLETON(VramAllocator) - -//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ -//#define __PSP_DEBUG_PRINT__ - -#include "backends/platform/psp/trace.h" - - -void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) { - DEBUG_ENTER_FUNC(); - assert(size > 0); - - byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS; - Common::List<Allocation>::iterator i; - - // Find a block that fits, starting from the beginning - for (i = _allocList.begin(); i != _allocList.end(); ++i) { - byte *currAddress = (*i).address; - - if (currAddress - lastAddress >= size) // We found a match - break; - - if ((*i).getEnd() > lastAddress) - lastAddress = (byte *)(*i).getEnd(); - } - - if (lastAddress + size > (byte *)VRAM_END_ADDRESS) { - PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n", - size, _bytesAllocated); - return NULL; - } - - _allocList.insert(i, Allocation(lastAddress, size)); - _bytesAllocated += size; - - PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress); - PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated); - - return lastAddress; -} - -// Deallocate a block from VRAM -void VramAllocator::deallocate(void *address) { - DEBUG_ENTER_FUNC(); - address = (byte *)CACHED(address); // Make sure all addresses are the same - - Common::List<Allocation>::iterator i; - - // Find the Allocator to deallocate - for (i = _allocList.begin(); i != _allocList.end(); ++i) { - if ((*i).address == address) { - _bytesAllocated -= (*i).size; - _allocList.erase(i); - PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size); - return; - } - } - - PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address); -} diff --git a/backends/platform/psp/memory.h b/backends/platform/psp/memory.h index 793bc94888..54e9225b2e 100644 --- a/backends/platform/psp/memory.h +++ b/backends/platform/psp/memory.h @@ -27,18 +27,24 @@ #ifndef PSP_MEMORY_H #define PSP_MEMORY_H -#include "backends/platform/psp/psppixelformat.h" -#include "common/list.h" - -#define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */ -#define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */ - #define MIN_AMOUNT_FOR_COMPLEX_COPY 8 #define MIN_AMOUNT_FOR_MISALIGNED_COPY 8 //#define __PSP_DEBUG_PRINT__ -#include "backends/platform/psp/trace.h" +//#include "backends/platform/psp/trace.h" + +// These instructions don't generate automatically but are faster then copying byte by byte +inline void lwl_copy(byte *dst, const byte *src) { + register uint32 data; + asm volatile ("lwr %0,0(%1)\n\t" + "lwl %0,3(%1)\n\t" + : "=&r" (data) : "r" (src), "m" (*src)); + + asm volatile ("swr %1,0(%2)\n\t" + "swl %1,3(%2)\n\t" + : "=m" (*dst) : "r" (data), "r" (dst)); +} /** * Class that does memory copying and swapping if needed @@ -46,42 +52,69 @@ class PspMemory { private: static void testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes); - static void testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format); static void copy(byte *dst, const byte *src, uint32 bytes); - static void swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format); static void copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes); - static void swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format); static void copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc); - static void swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format); - static void copy16(uint16 *dst, const uint16 *src, uint32 bytes); - - // For swapping, we know that we have multiples of 16 bits - static void swap16(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { - PSP_DEBUG_PRINT("swap16 called with dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes); - uint32 shorts = bytes >> 1; - while (shorts--) { - *dst16++ = format.swapRedBlue16(*src16++); + static inline void copy8(byte *dst, const byte *src, int32 bytes) { + //PSP_DEBUG_PRINT("copy8 called with dst[%p], src[%p], bytes[%d]\n", dst, src, bytes); + uint32 words = bytes >> 2; + for (; words; words--) { + lwl_copy(dst, src); + dst += 4; + src += 4; } - } - - static void copy8(byte *dst, const byte *src, uint32 bytes) { - PSP_DEBUG_PRINT("copy8 called with dst[%p], src[%p], bytes[%d]\n", dst, src, bytes); - while (bytes--) { + + uint32 bytesLeft = bytes & 0x3; + for (; bytesLeft; bytesLeft--) { *dst++ = *src++; } } -public: +public: // This is the interface to the outside world - static void fastCopy(byte *dst, const byte *src, uint32 bytes) { + static void *fastCopy(void *dstv, const void *srcv, int32 bytes) { + byte *dst = (byte *)dstv; + byte *src = (byte *)srcv; + if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { copy8(dst, src, bytes); } else { // go to more powerful copy copy(dst, src, bytes); } + + return dstv; } +}; + +inline void *psp_memcpy(void *dst, const void *src, int32 bytes) { + return PspMemory::fastCopy(dst, src, bytes); +} + +#endif /* PSP_MEMORY_H */ + +#if defined(PSP_INCLUDE_SWAP) && !defined(PSP_MEMORY_SWAP_H) +#define PSP_MEMORY_SWAP_H +//#include "backends/platform/psp/psppixelformat.h" + +class PspMemorySwap { +private: + static void testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format); + static void swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format); + static void swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format); + static void swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format); + // For swapping, we know that we have multiples of 16 bits + static void swap16(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) { + PSP_DEBUG_PRINT("swap16 called with dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes); + uint32 shorts = bytes >> 1; + + while (shorts--) { + *dst16++ = format.swapRedBlue16(*src16++); + } +} + +public: static void fastSwap(byte *dst, const byte *src, uint32 bytes, PSPPixelFormat &format) { if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY * 2) { swap16((uint16 *)dst, (uint16 *)src, bytes, format); @@ -91,41 +124,6 @@ public: } }; -/** - * Class that allocates memory in the VRAM - */ -class VramAllocator : public Common::Singleton<VramAllocator> { -public: - VramAllocator() : _bytesAllocated(0) {} - void *allocate(int32 size, bool smallAllocation = false); // smallAllocation e.g. palettes - void deallocate(void *pointer); - - static inline bool isAddressInVram(void *address) { - if ((uint32)(CACHED(address)) >= VRAM_START_ADDRESS && (uint32)(CACHED(address)) < VRAM_END_ADDRESS) - return true; - return false; - } - +#endif /* PSP_INCLUDE_SWAP */ -private: - /** - * Used to allocate in VRAM - */ - struct Allocation { - byte *address; - uint32 size; - void *getEnd() { return address + size; } - Allocation(void *Address, uint32 Size) : address((byte *)Address), size(Size) {} - Allocation() : address(0), size(0) {} - }; - - enum { - VRAM_START_ADDRESS = 0x04000000, - VRAM_END_ADDRESS = 0x04200000, - VRAM_SMALL_ADDRESS = VRAM_END_ADDRESS - (4 * 1024) // 4K in the end for small allocations - }; - Common::List <Allocation> _allocList; // List of allocations - uint32 _bytesAllocated; -}; -#endif /* PSP_MEMORY_H */ diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index 4652189ab4..f96c4ef583 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -17,6 +17,7 @@ MODULE_OBJS := powerman.o \ thread.o \ rtc.o \ mp3.o \ + png_loader.o \ tests.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp index a2fe9a62f3..0e88418f13 100644 --- a/backends/platform/psp/mp3.cpp +++ b/backends/platform/psp/mp3.cpp @@ -38,13 +38,13 @@ #include <pspsysmem.h> #include <pspmodulemgr.h> #include <psputility_avmodules.h> -#include <mad.h> +#include <mad.h> #include "backends/platform/psp/mp3.h" //#define DISABLE_PSP_MP3 // to make us use the regular MAD decoder instead //#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ -//#define __PSP_DEBUG_PRINT__ +//#define __PSP_DEBUG_PRINT__ #include "backends/platform/psp/trace.h" //#define PRINT_BUFFERS /* to debug MP3 buffers */ @@ -60,9 +60,24 @@ bool Mp3PspStream::_decoderFail = true; // pretend the decoder failed bool Mp3PspStream::_decoderFail = false; // has the decoder failed to load #endif +// Arranged in groups of 3 (layers), starting with MPEG-1 and ending with MPEG 2.5 +static uint32 mp3SamplesPerFrame[9] = {384, 1152, 1152, 384, 1152, 576, 384, 1152, 576}; + +// The numbering below doesn't correspond to the way they are in the header +enum { + MPEG_VER1 = 0, + MPEG_VER1_HEADER = 0x3, + MPEG_VER2 = 1, + MPEG_VER2_HEADER = 0x2, + MPEG_VER2_5 = 2, + MPEG_VER2_5_HEADER = 0x0 +}; + +#define HEADER_GET_MPEG_VERSION(x) ((((x)[1])>>3) & 0x3) + bool Mp3PspStream::initDecoder() { DEBUG_ENTER_FUNC(); - + if (_decoderInit) { PSP_ERROR("Already initialized!"); return true; @@ -82,15 +97,15 @@ bool Mp3PspStream::initDecoder() { PSP_ERROR("failed to load audiocodec.prx. ME cannot start.\n"); _decoderFail = true; return false; - } - } else { + } + } else { if (sceUtilityLoadAvModule(PSP_AV_MODULE_AVCODEC) < 0) { PSP_ERROR("failed to load AVCODEC module. ME cannot start.\n"); _decoderFail = true; return false; } } - + PSP_DEBUG_PRINT("Using PSP's ME for MP3\n"); // important to know this is happening _decoderInit = true; @@ -99,12 +114,12 @@ bool Mp3PspStream::initDecoder() { bool Mp3PspStream::stopDecoder() { DEBUG_ENTER_FUNC(); - + if (!_decoderInit) return true; - + // Based on PSP firmware version, we need to do different things to do Media Engine processing - if (sceKernelDevkitVersion() == 0x01050001){ + if (sceKernelDevkitVersion() == 0x01050001){ // TODO: how do we unload? /* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) || !unloadAudioModule("flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL) { PSP_ERROR("failed to unload audio module\n"); @@ -115,10 +130,10 @@ bool Mp3PspStream::stopDecoder() { if (sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) < 0) { PSP_ERROR("failed to unload avcodec module\n"); return false; - } + } } - - _decoderInit = false; + + _decoderInit = false; return true; } @@ -161,28 +176,28 @@ Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse _length(0, 1000), _sampleRate(0), _totalTime(mad_timer_zero) { - + DEBUG_ENTER_FUNC(); assert(_decoderInit); // must be initialized by now - + // let's leave the buffer guard -- who knows, it may be good? memset(_buf, 0, sizeof(_buf)); memset(_codecInBuffer, 0, sizeof(_codecInBuffer)); - + initStream(); // init needed stuff for the stream + findValidHeader(); // get a first header so we can read basic stuff + + _sampleRate = _header.samplerate; // copy it before it gets destroyed + _stereo = (MAD_NCHANNELS(&_header) == 2); + while (_state != MP3_STATE_EOS) findValidHeader(); // get a first header so we can read basic stuff - - _sampleRate = _header.samplerate; // copy it before it gets destroyed - + _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); - - //initStreamME(); // init the stuff needed for the ME to work - + deinitStream(); - //releaseStreamME(); _state = MP3_STATE_INIT; } @@ -207,7 +222,7 @@ int Mp3PspStream::initStream() { // Read the first few sample bytes into the buffer readMP3DataIntoBuffer(); - + return true; } @@ -215,7 +230,7 @@ bool Mp3PspStream::initStreamME() { // The following will eventually go into the thread memset(_codecParams, 0, sizeof(_codecParams)); - + // Init the MP3 hardware int ret = 0; ret = sceAudiocodecCheckNeedMem(_codecParams, 0x1002); @@ -230,22 +245,22 @@ bool Mp3PspStream::initStreamME() { return false; } PSP_DEBUG_PRINT("sceAudioCodecGetEDRAM returned %d\n", ret); - + PSP_DEBUG_PRINT("samplerate[%d]\n", _sampleRate); _codecParams[10] = _sampleRate; - + ret = sceAudiocodecInit(_codecParams, 0x1002); if (ret < 0) { PSP_ERROR("failed to init MP3 ME module. sceAudiocodecInit returned 0x%x.\n", ret); return false; } - + return true; } Mp3PspStream::~Mp3PspStream() { DEBUG_ENTER_FUNC(); - + deinitStream(); releaseStreamME(); // free the memory used for this stream @@ -262,17 +277,17 @@ void Mp3PspStream::deinitStream() { // Deinit MAD mad_header_finish(&_header); mad_stream_finish(&_stream); - + _state = MP3_STATE_EOS; } void Mp3PspStream::releaseStreamME() { sceAudiocodecReleaseEDRAM(_codecParams); -} +} void Mp3PspStream::decodeMP3Data() { DEBUG_ENTER_FUNC(); - + do { if (_state == MP3_STATE_INIT) { initStream(); @@ -281,31 +296,27 @@ void Mp3PspStream::decodeMP3Data() { if (_state == MP3_STATE_EOS) return; - + findValidHeader(); // seach for next valid header - while (_state == MP3_STATE_READY) { + while (_state == MP3_STATE_READY) { // not a real 'while'. Just for easy flow _stream.error = MAD_ERROR_NONE; uint32 frame_size = _stream.next_frame - _stream.this_frame; - uint32 samplesPerFrame = _header.layer == MAD_LAYER_III ? 576 : 1152; // Varies by layer - // calculate frame size -- try - //uint32 calc_frame_size = ((144 * _header.bitrate) / 22050) + (_header.flags & MAD_FLAG_PADDING ? 1 : 0); - - // Get stereo/mono - uint32 multFactor = 1; - if (_header.mode != MAD_MODE_SINGLE_CHANNEL) // mono - x2 for 16bit - multFactor *= 2; // stereo - x4 for 16bit - - PSP_DEBUG_PRINT("MP3 frame size[%d]. Samples[%d]. Multfactor[%d] pad[%d]\n", frame_size, samplesPerFrame, multFactor, _header.flags & MAD_FLAG_PADDING); + + updatePcmLength(); // Retrieve the number of PCM samples. + // We seem to change this, so it needs to be dynamic + + PSP_DEBUG_PRINT("MP3 frame size[%d]. pcmLength[%d]\n", frame_size, _pcmLength); + memcpy(_codecInBuffer, _stream.this_frame, frame_size); // we need it aligned // set up parameters for ME _codecParams[6] = (unsigned long)_codecInBuffer; _codecParams[8] = (unsigned long)_pcmSamples; _codecParams[7] = frame_size; - _codecParams[9] = samplesPerFrame * multFactor; // x2 for stereo - + _codecParams[9] = _pcmLength * 2; // x2 for stereo, though this one's not so important + // debug #ifdef PRINT_BUFFERS PSP_DEBUG_PRINT("mp3 frame:\n"); @@ -319,7 +330,6 @@ void Mp3PspStream::decodeMP3Data() { int ret = sceAudiocodecDecode(_codecParams, 0x1002); if (ret < 0) { PSP_INFO_PRINT("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret); - // handle error here } #ifdef PRINT_BUFFERS @@ -329,7 +339,6 @@ void Mp3PspStream::decodeMP3Data() { } PSP_DEBUG_PRINT("\n"); #endif - _pcmLength = samplesPerFrame; _posInFrame = 0; break; } @@ -339,6 +348,27 @@ void Mp3PspStream::decodeMP3Data() { _state = MP3_STATE_EOS; } +inline void Mp3PspStream::updatePcmLength() { + uint32 mpegVer = HEADER_GET_MPEG_VERSION(_stream.this_frame); // sadly, MAD can't do this for us + PSP_DEBUG_PRINT("mpeg ver[%x]\n", mpegVer); + switch (mpegVer) { + case MPEG_VER1_HEADER: + mpegVer = MPEG_VER1; + break; + case MPEG_VER2_HEADER: + mpegVer = MPEG_VER2; + break; + case MPEG_VER2_5_HEADER: + mpegVer = MPEG_VER2_5; + break; + default: + PSP_ERROR("Unknown MPEG version %x\n", mpegVer); + break; + } + PSP_DEBUG_PRINT("layer[%d]\n", _header.layer); + _pcmLength = mp3SamplesPerFrame[(mpegVer * 3) + _header.layer - 1]; +} + void Mp3PspStream::readMP3DataIntoBuffer() { DEBUG_ENTER_FUNC(); @@ -386,16 +416,15 @@ bool Mp3PspStream::seek(const Timestamp &where) { mad_timer_t destination; mad_timer_set(&destination, time / 1000, time % 1000, 1000); + // Important to release and re-init the ME + releaseStreamME(); + initStreamME(); + // Check if we need to rewind if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) { initStream(); - initStreamME(); } - // The ME will need clear data no matter what once we seek? - //if (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) - // initStreamME(); - // Skip ahead while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) findValidHeader(); @@ -444,43 +473,38 @@ int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) { DEBUG_ENTER_FUNC(); int samples = 0; -#ifdef PRINT_BUFFERS +#ifdef PRINT_BUFFERS int16 *debugBuffer = buffer; -#endif - +#endif + // Keep going as long as we have input available while (samples < numSamples && _state != MP3_STATE_EOS) { const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header)); - + while (samples < len) { *buffer++ = _pcmSamples[_posInFrame << 1]; samples++; if (MAD_NCHANNELS(&_header) == 2) { *buffer++ = _pcmSamples[(_posInFrame << 1) + 1]; samples++; - } + } _posInFrame++; // always skip an extra sample since ME always outputs stereo } - - //memcpy(buffer, &_pcmSamples[_posInFrame], len << 1); // 16 bits - //_posInFrame += len; // next time we start from the middle if (_posInFrame >= _pcmLength) { // We used up all PCM data in the current frame -- read & decode more decodeMP3Data(); } } - + #ifdef PRINT_BUFFERS PSP_INFO_PRINT("buffer:\n"); for (int i = 0; i<numSamples; i++) PSP_INFO_PRINT("%d ", debugBuffer[i]); PSP_INFO_PRINT("\n\n"); -#endif - +#endif + return samples; } } // End of namespace Audio - - diff --git a/backends/platform/psp/mp3.h b/backends/platform/psp/mp3.h index 029b3e498c..1d2fe5ec2f 100644 --- a/backends/platform/psp/mp3.h +++ b/backends/platform/psp/mp3.h @@ -46,36 +46,37 @@ protected: MP3_STATE_EOS // end of data reached (may need to loop) }; - #define MAX_SAMPLES_PER_FRAME 2048 * 2 + #define MAX_SAMPLES_PER_FRAME 1152 * 2 /* x2 for stereo */ int16 _pcmSamples[MAX_SAMPLES_PER_FRAME] __attribute__((aligned(64))); // samples to output PCM data into byte _codecInBuffer[3072] __attribute__((aligned(64))); // the codec always needs alignment unsigned long _codecParams[65]__attribute__((aligned(64))); // TODO: change to struct Common::SeekableReadStream *_inStream; DisposeAfterUse::Flag _disposeAfterUse; - - uint32 _pcmLength; // how many pcm samples we have (/2 for mono) - + + uint32 _pcmLength; // how many pcm samples we have for this type of file (x2 this for stereo) + uint _posInFrame; // position in frame State _state; // what state the stream is in Timestamp _length; uint32 _sampleRate; + bool _stereo; mad_timer_t _totalTime; mad_stream _stream; // mad_header _header; // This is all we need from libmad - + static bool _decoderInit; // has the decoder been initialized static bool _decoderFail; // has the decoder failed to load - + enum { BUFFER_SIZE = 5 * 8192 }; // This buffer contains a slab of input data byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD]; - + void decodeMP3Data(); void readMP3DataIntoBuffer(); @@ -83,19 +84,20 @@ protected: int initStream(); void findValidHeader(); void deinitStream(); + void updatePcmLength(); // to init and uninit ME decoder static bool initDecoder(); static bool stopDecoder(); - + // ME functions for stream bool initStreamME(); void releaseStreamME(); - + public: Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose); ~Mp3PspStream(); - + // This function avoids having to create streams when it's not possible static inline bool isOkToCreateStream() { if (_decoderFail) // fatal failure @@ -103,13 +105,13 @@ public: if (!_decoderInit) // if we're not initialized if (!initDecoder()) // check if we failed init return false; - return true; + return true; } int readBuffer(int16 *buffer, const int numSamples); bool endOfData() const { return _state == MP3_STATE_EOS; } - bool isStereo() const { return MAD_NCHANNELS(&_header) == 2; } + bool isStereo() const { return _stereo; } int getRate() const { return _sampleRate; } bool seek(const Timestamp &where); diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index b09d9c0c00..047ec1957f 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -67,7 +67,7 @@ void OSystem_PSP::initBackend() { // Instantiate real time clock PspRtc::instance(); - + _cursor.enableCursorPalette(false); _cursor.setXY(PSP_SCREEN_WIDTH >> 1, PSP_SCREEN_HEIGHT >> 1); // Mouse in the middle of the screen @@ -148,7 +148,7 @@ Common::List<Graphics::PixelFormat> OSystem_PSP::getSupportedFormats() const { void OSystem_PSP::initSize(uint width, uint height, const Graphics::PixelFormat *format) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _displayManager.setSizeAndPixelFormat(width, height, format); _cursor.setVisible(false); @@ -167,7 +167,7 @@ int16 OSystem_PSP::getHeight() { void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _screen.setPartialPalette(colors, start, num); _cursor.setScreenPalette(colors, start, num); _cursor.clearKeyColor(); @@ -175,7 +175,7 @@ void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) { void OSystem_PSP::setCursorPalette(const byte *colors, uint start, uint num) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _cursor.setCursorPalette(colors, start, num); _cursor.enableCursorPalette(true); _cursor.clearKeyColor(); // Do we need this? @@ -183,25 +183,25 @@ void OSystem_PSP::setCursorPalette(const byte *colors, uint start, uint num) { void OSystem_PSP::disableCursorPalette(bool disable) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _cursor.enableCursorPalette(!disable); } void OSystem_PSP::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _screen.copyFromRect(buf, pitch, x, y, w, h); } Graphics::Surface *OSystem_PSP::lockScreen() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; return _screen.lockAndGetForEditing(); } void OSystem_PSP::unlockScreen() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; // The screen is always completely updated anyway, so we don't have to force a full update here. _screen.unlock(); } @@ -219,7 +219,7 @@ void OSystem_PSP::setShakePos(int shakeOffset) { void OSystem_PSP::showOverlay() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _overlay.setVisible(true); _cursor.setLimits(_overlay.getWidth(), _overlay.getHeight()); _cursor.useGlobalScaler(false); // mouse with overlay is 1:1 @@ -227,7 +227,7 @@ void OSystem_PSP::showOverlay() { void OSystem_PSP::hideOverlay() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _overlay.setVisible(false); _cursor.setLimits(_screen.getWidth(), _screen.getHeight()); _cursor.useGlobalScaler(true); // mouse needs to be scaled with screen @@ -235,7 +235,7 @@ void OSystem_PSP::hideOverlay() { void OSystem_PSP::clearOverlay() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _overlay.clearBuffer(); } @@ -246,7 +246,7 @@ void OSystem_PSP::grabOverlay(OverlayColor *buf, int pitch) { void OSystem_PSP::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _overlay.copyFromRect(buf, pitch, x, y, w, h); } @@ -266,7 +266,7 @@ void OSystem_PSP::grabPalette(byte *colors, uint start, uint num) { bool OSystem_PSP::showMouse(bool v) { DEBUG_ENTER_FUNC(); _pendingUpdate = false; - + PSP_DEBUG_PRINT("%s\n", v ? "true" : "false"); bool last = _cursor.isVisible(); _cursor.setVisible(v); @@ -276,14 +276,14 @@ bool OSystem_PSP::showMouse(bool v) { void OSystem_PSP::warpMouse(int x, int y) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _cursor.setXY(x, y); } void OSystem_PSP::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; - + _pendingUpdate = false; + PSP_DEBUG_PRINT("pbuf[%p], w[%u], h[%u], hotspot:X[%d], Y[%d], keycolor[%d], scale[%d], pformat[%p]\n", buf, w, h, hotspotX, hotspotY, keycolor, cursorTargetScale, format); if (format) { PSP_DEBUG_PRINT("format: bpp[%d], rLoss[%d], gLoss[%d], bLoss[%d], aLoss[%d], rShift[%d], gShift[%d], bShift[%d], aShift[%d]\n", format->bytesPerPixel, format->rLoss, format->gLoss, format->bLoss, format->aLoss, format->rShift, format->gShift, format->bShift, format->aShift); @@ -310,16 +310,16 @@ bool OSystem_PSP::pollEvent(Common::Event &event) { // Time between event polls is usually 5-10ms, so waiting for 4 calls before checking to update the screen should be fine if (_pendingUpdate) { _pendingUpdateCounter++; - + if (_pendingUpdateCounter >= 4) { PSP_DEBUG_PRINT("servicing pending update\n"); updateScreen(); if (!_pendingUpdate) // we handled the update - _pendingUpdateCounter = 0; + _pendingUpdateCounter = 0; } - } else + } else _pendingUpdateCounter = 0; // reset the counter, no pending - + return _inputHandler.getAllInputs(event); } diff --git a/backends/platform/psp/plugin.ld b/backends/platform/psp/plugin.ld index db4df45264..7534c15290 100644 --- a/backends/platform/psp/plugin.ld +++ b/backends/platform/psp/plugin.ld @@ -208,7 +208,7 @@ SECTIONS .debug_varnames 0 : { *(.debug_varnames) } /DISCARD/ : { *(.comment) *(.pdr) } /DISCARD/ : { *(.note.GNU-stack) } - + . = __plugin_hole_start; .got : { *(.got.plt) *(.got) } : shorts /* We want the small data sections together, so single-instruction offsets @@ -235,5 +235,5 @@ SECTIONS PROVIDE (___sbss_end = .); } - + } diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp new file mode 100644 index 0000000000..978db3eaf9 --- /dev/null +++ b/backends/platform/psp/png_loader.cpp @@ -0,0 +1,187 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/scummsys.h" +#include "common/stream.h" +#include "backends/platform/psp/psppixelformat.h" +#include "backends/platform/psp/display_client.h" +#include "backends/platform/psp/png_loader.h" + +PngLoader::Status PngLoader::allocate() { + if (!findImageDimensions()) { + PSP_ERROR("failed to get image dimensions\n"); + return BAD_FILE; + } + + PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d]\n", _width, _height, _paletteSize, _bitDepth); + _buffer->setSize(_width, _height, _sizeBy); + + if (_paletteSize) { // 8 or 4-bit image + if (_paletteSize <= 16) { // 4 bit + _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit); + _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); + _paletteSize = 16; + } else if (_paletteSize <= 256) { // 8-bit image + _paletteSize = 256; + _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit); + _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); + } else { + PSP_ERROR("palette of %d too big!\n", _paletteSize); + return BAD_FILE; + } + + } else { // 32-bit image + _buffer->setPixelFormat(PSPPixelFormat::Type_8888); + } + + if (!_buffer->allocate()) { + PSP_ERROR("failed to allocate buffer\n"); + return OUT_OF_MEMORY; + } + if (!_palette->allocate()) { + PSP_ERROR("failed to allocate palette\n"); + return OUT_OF_MEMORY; + } + return OK; +} + +bool PngLoader::load() { + // Try to load the image + _file->seek(0); // Go back to start + + if (!loadImageIntoBuffer()) { + PSP_DEBUG_PRINT("failed to load image\n"); + return false; + } + + PSP_DEBUG_PRINT("succeded in loading image\n"); + + if (_paletteSize == 16) // 4-bit + _buffer->flipNibbles(); // required because of PNG 4-bit format + return true; +} + +void PngLoader::warningFn(png_structp png_ptr, png_const_charp warning_msg) { + // ignore PNG warnings +} + +// Read function for png library to be able to read from our SeekableReadStream +// +void PngLoader::libReadFunc(png_structp pngPtr, png_bytep data, png_size_t length) { + Common::SeekableReadStream *file; + + file = (Common::SeekableReadStream *)pngPtr->io_ptr; + + file->read(data, length); +} + +bool PngLoader::basicImageLoad() { + _pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!_pngPtr) + return false; + + png_set_error_fn(_pngPtr, (png_voidp) NULL, (png_error_ptr) NULL, warningFn); + + _infoPtr = png_create_info_struct(_pngPtr); + if (!_infoPtr) { + png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL); + return false; + } + // Set the png lib to use our read function + png_set_read_fn(_pngPtr, (void *)_file, libReadFunc); + + unsigned int sig_read = 0; + + png_set_sig_bytes(_pngPtr, sig_read); + png_read_info(_pngPtr, _infoPtr); + int interlaceType; + png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth, + &_colorType, &interlaceType, int_p_NULL, int_p_NULL); + + if (_colorType & PNG_COLOR_MASK_PALETTE) + _paletteSize = _infoPtr->num_palette; + + return true; +} + +/* Get the width and height of a png image */ +bool PngLoader::findImageDimensions() { + DEBUG_ENTER_FUNC(); + + if (!basicImageLoad()) + return false; + + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); + return true; +} + +// +// Load a texture from a png image +// +bool PngLoader::loadImageIntoBuffer() { + DEBUG_ENTER_FUNC(); + + if (!basicImageLoad()) + return false; + + // Strip off 16 bit channels. Not really needed but whatever + png_set_strip_16(_pngPtr); + + if (_paletteSize) { + // Copy the palette + png_colorp srcPal = _infoPtr->palette; + for (int i = 0; i < (int)_paletteSize; i++) { + unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF; // Load alpha if it's there + _palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal); + srcPal++; + } + } else { // Not a palettized image + if (_colorType == PNG_COLOR_TYPE_GRAY && _bitDepth < 8) + png_set_gray_1_2_4_to_8(_pngPtr); // Round up grayscale images + if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(_pngPtr); // Convert trans channel to alpha for 32 bits + + png_set_filler(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha? + } + + unsigned char *line = (unsigned char*) malloc(_infoPtr->rowbytes); + if (!line) { + png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL); + PSP_ERROR("Couldn't allocate line\n"); + return false; + } + + for (size_t y = 0; y < _height; y++) { + png_read_row(_pngPtr, line, png_bytep_NULL); + _buffer->copyFromRect(line, _infoPtr->rowbytes, 0, y, _width, 1); // Copy into buffer + } + + free(line); + + png_read_end(_pngPtr, _infoPtr); + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); + + return true; +} diff --git a/backends/platform/psp/png_loader.h b/backends/platform/psp/png_loader.h new file mode 100644 index 0000000000..6b0282621a --- /dev/null +++ b/backends/platform/psp/png_loader.h @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef PSP_PNG_IMAGE_H +#define PSP_PNG_IMAGE_H + +#include <png.h> + +class PngLoader { +private: + bool basicImageLoad(); // common operation + bool findImageDimensions(); // find dimensions of a given PNG file + bool loadImageIntoBuffer(); + + static void warningFn(png_structp png_ptr, png_const_charp warning_msg); + static void libReadFunc(png_structp pngPtr, png_bytep data, png_size_t length); + + Common::SeekableReadStream *_file; + Buffer *_buffer; + Palette *_palette; + + uint32 _width; + uint32 _height; + uint32 _paletteSize; + int _bitDepth; + Buffer::HowToSize _sizeBy; + png_structp _pngPtr; + png_infop _infoPtr; + int _colorType; + +public: + enum Status { + OK, + OUT_OF_MEMORY, + BAD_FILE + }; + + PngLoader(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette, + Buffer::HowToSize sizeBy = Buffer::kSizeByTextureSize) : + _file(file), _buffer(&buffer), _palette(&palette), + _width(0), _height(0), _paletteSize(0), + _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), _infoPtr(0), _colorType(0) {} + + PngLoader::Status allocate(); + bool load(); +}; + +#endif /* PSP_PNG_IMAGE_H */ diff --git a/backends/platform/psp/powerman.cpp b/backends/platform/psp/powerman.cpp index eaadad16c5..869d9b3023 100644 --- a/backends/platform/psp/powerman.cpp +++ b/backends/platform/psp/powerman.cpp @@ -84,7 +84,7 @@ bool PowerManager::unregisterForSuspend(Suspendable *item) { // Unregister from stream list _listMutex.lock(); - + _suspendList.remove(item); _listCounter--; @@ -114,11 +114,11 @@ PowerManager::~PowerManager() { ********************************************/ void PowerManager::pollPauseEngine() { DEBUG_ENTER_FUNC(); - - + + bool pause = _pauseFlag; // We copy so as not to have multiple values - if (pause != _pauseFlagOld) { + if (pause != _pauseFlagOld) { if (g_engine) { // Check to see if we have an engine if (pause && _pauseClientState == UNPAUSED) { _pauseClientState = PAUSING; // Tell PM we're in the middle of pausing @@ -147,7 +147,7 @@ bool PowerManager::beginCriticalSection() { DEBUG_ENTER_FUNC(); bool ret = false; - + _flagMutex.lock(); // Check the access flag @@ -156,7 +156,7 @@ bool PowerManager::beginCriticalSection() { PSP_DEBUG_PRINT("I got blocked. ThreadId[%x]\n", sceKernelGetThreadId()); debugPM(); - + _threadSleep.wait(_flagMutex); PSP_DEBUG_PRINT_FUNC("I got released. ThreadId[%x]\n", sceKernelGetThreadId()); @@ -184,11 +184,11 @@ void PowerManager::endCriticalSection() { if (_suspendFlag) { // If the PM is sleeping, this flag must be set PSP_DEBUG_PRINT_FUNC("PM is asleep. Waking it up.\n"); debugPM(); - + _pmSleep.releaseAll(); - + PSP_DEBUG_PRINT_FUNC("Woke up the PM\n"); - + debugPM(); } @@ -198,7 +198,7 @@ void PowerManager::endCriticalSection() { } } - _flagMutex.unlock(); + _flagMutex.unlock(); } /******************************************* @@ -209,7 +209,7 @@ void PowerManager::endCriticalSection() { void PowerManager::suspend() { DEBUG_ENTER_FUNC(); - if (_pauseFlag) + if (_pauseFlag) return; // Very important - make sure we only suspend once scePowerLock(0); // Also critical to make sure PSP doesn't suspend before we're done @@ -232,9 +232,9 @@ void PowerManager::suspend() { PspThread::delayMicros(50000); // We wait 50 msec at a time } - // It's possible that the polling thread missed our pause event, but there's + // It's possible that the polling thread missed our pause event, but there's // nothing we can do about that. - // We can't know if there's polling going on or not. + // We can't know if there's polling going on or not. // It's usually not a critical thing anyway. _PMStatus = kGettingFlagMutexSuspend; @@ -249,12 +249,12 @@ void PowerManager::suspend() { // Check if anyone is in a critical section. If so, we'll wait for them if (_criticalCounter > 0) { _PMStatus = kWaitCritSectionSuspend; - + _pmSleep.wait(_flagMutex); - + _PMStatus = kDoneWaitingCritSectionSuspend; - } - + } + _flagMutex.unlock(); _PMStatus = kGettingListMutexSuspend; @@ -275,7 +275,7 @@ void PowerManager::suspend() { _PMStatus = kDoneSuspend; scePowerUnlock(0); // Allow the PSP to go to sleep now - + _PMStatus = kDonePowerUnlock; } @@ -286,22 +286,22 @@ void PowerManager::suspend() { ********************************************/ void PowerManager::resume() { DEBUG_ENTER_FUNC(); - + _PMStatus = kBeginResume; // Make sure we can't get another suspend scePowerLock(0); _PMStatus = kCheckingPauseFlag; - - if (!_pauseFlag) + + if (!_pauseFlag) return; // Make sure we can only resume once _PMStatus = kGettingListMutexResume; // First we notify our Suspendables. Loop over list, calling resume() _listMutex.lock(); - + _PMStatus = kIteratingListResume; // Iterate @@ -314,12 +314,12 @@ void PowerManager::resume() { _PMStatus = kDoneIteratingListResume; _listMutex.unlock(); - + _PMStatus = kGettingFlagMutexResume; // Now we set the suspend flag to false _flagMutex.lock(); - + _PMStatus = kGotFlagMutexResume; _suspendFlag = false; @@ -328,11 +328,11 @@ void PowerManager::resume() { // Signal the threads to wake up _threadSleep.releaseAll(); - + _PMStatus = kDoneSignallingSuspendedThreadsResume; _flagMutex.unlock(); - + _PMStatus = kDoneResume; _pauseFlag = false; // Signal engine to unpause -- no mutex needed diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index dba9a8fc2b..d24c614e33 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -104,7 +104,7 @@ int exit_callback(void) { #ifdef ENABLE_PROFILING gprof_cleanup(); -#endif +#endif sceKernelExitGame(); return 0; @@ -171,12 +171,12 @@ int main(void) { #endif /* unit/speed tests */ -#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) +#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) PSP_INFO_PRINT("running tests\n"); psp_tests(); sceKernelSleepThread(); // that's it. That's all we're doing #endif - + int res = scummvm_main(argc, argv); g_system->quit(); // TODO: Consider removing / replacing this! diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp index eb081fc5f4..3dd5e9789b 100644 --- a/backends/platform/psp/pspkeyboard.cpp +++ b/backends/platform/psp/pspkeyboard.cpp @@ -26,16 +26,17 @@ //#define PSP_KB_SHELL /* Need a hack to properly load the keyboard from the PSP shell */ #ifdef PSP_KB_SHELL -#define PSP_KB_SHELL_PATH "ms0:/psp/game4xx/scummvm-solid/" /* path to kbd.zip */ +#define PSP_KB_SHELL_PATH "ms0:/psp/game5xx/scummvm-solid/" /* path to kbd.zip */ #endif #include <malloc.h> #include <pspkernel.h> -#include <png.h> #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/png_loader.h" +#include "backends/platform/psp/input.h" #include "common/keyboard.h" #include "common/fs.h" #include "common/unzip.h" @@ -91,16 +92,6 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = { } }; -// Read function for png library to be able to read from our SeekableReadStream -// -void pngReadStreamRead(png_structp png_ptr, png_bytep data, png_size_t length) { - Common::SeekableReadStream *file; - - file = (Common::SeekableReadStream *)png_ptr->io_ptr; - - file->read(data, length); -} - // Array with file names const char *PSPKeyboard::_guiStrings[] = { "keys4.png", "keys_s4.png", @@ -281,8 +272,6 @@ bool PSPKeyboard::load() { // Loop through all png images for (i = 0; i < guiStringsSize; i++) { - uint32 height = 0, width = 0, paletteSize = 0; - PSP_DEBUG_PRINT("Opening %s.\n", _guiStrings[i]); // Look for the file in the kbd directory @@ -309,49 +298,18 @@ bool PSPKeyboard::load() { goto ERROR; } - if (getPngImageSize(file, &width, &height, &paletteSize) == 0) { // Check image size and palette size - // Allocate memory for image - PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d]\n", width, height, paletteSize); - _buffers[i].setSize(width, height, Buffer::kSizeByTextureSize); - - if (paletteSize) { // 8 or 4-bit image - if (paletteSize <= 16) { // 4 bit - _buffers[i].setPixelFormat(PSPPixelFormat::Type_Palette_4bit); - _palettes[i].setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); - paletteSize = 16; - } else if (paletteSize <= 256) { // 8-bit image - paletteSize = 256; - _buffers[i].setPixelFormat(PSPPixelFormat::Type_Palette_8bit); - _palettes[i].setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); - } else { - PSP_ERROR("palette of %d too big!\n", paletteSize); - goto ERROR; - } - - } else { // 32-bit image - _buffers[i].setPixelFormat(PSPPixelFormat::Type_8888); - } - - _buffers[i].allocate(); - _palettes[i].allocate(); + PngLoader image(file, _buffers[i], _palettes[i]); - // Try to load the image - file->seek(0); // Go back to start - - if (loadPngImage(file, _buffers[i], _palettes[i]) != 0) - goto ERROR; - else { // Success - PSP_DEBUG_PRINT("Managed to load the image\n"); - - if (paletteSize == 16) // 4-bit - _buffers[i].flipNibbles(); - - delete file; - } - } else { - PSP_ERROR("couldn't obtain PNG image size\n"); + if (image.allocate() != PngLoader::OK) { + PSP_ERROR("Failed to allocate memory for keyboard image %s\n", _guiStrings[i]); goto ERROR; } + if (!image.load()) { + PSP_ERROR("Failed to load image from file %s\n", _guiStrings[i]); + goto ERROR; + } + + delete file; } /* for loop */ _init = true; @@ -376,124 +334,6 @@ ERROR: return false; } -static void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) { - // ignore PNG warnings -} - -/* Get the width and height of a png image */ -int PSPKeyboard::getPngImageSize(Common::SeekableReadStream *file, uint32 *png_width, uint32 *png_height, u32 *paletteSize) { - DEBUG_ENTER_FUNC(); - - png_structp png_ptr; - png_infop info_ptr; - unsigned int sig_read = 0; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - return -1; - } - png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn); - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return -1; - } - // Set the png lib to use our read function - png_set_read_fn(png_ptr, (void *)file, pngReadStreamRead); - - png_set_sig_bytes(png_ptr, sig_read); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); - if (color_type & PNG_COLOR_MASK_PALETTE) - *paletteSize = info_ptr->num_palette; - else - *paletteSize = 0; - - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - *png_width = width; - *png_height = height; - - return 0; -} - -// Load a texture from a png image -// -int PSPKeyboard::loadPngImage(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette) { - DEBUG_ENTER_FUNC(); - - png_structp png_ptr; - png_infop info_ptr; - unsigned int sig_read = 0; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - size_t y; - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - PSP_ERROR("Couldn't create read struct to load keyboard\n"); - return -1; - } - // Use dummy error function - png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn); - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - PSP_ERROR("Couldn't create info struct to load keyboard\n"); - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return -1; - } - - // Set the png lib to use our customized read function - png_set_read_fn(png_ptr, (void *)file, pngReadStreamRead); - - png_set_sig_bytes(png_ptr, sig_read); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); - - // Strip off 16 bit channels. Not really needed but whatever - png_set_strip_16(png_ptr); - - if (color_type == PNG_COLOR_TYPE_PALETTE) { - // Copy the palette - png_colorp srcPal = info_ptr->palette; - for (int i = 0; i < info_ptr->num_palette; i++) { - unsigned char alphaVal = (i < info_ptr->num_trans) ? info_ptr->trans[i] : 0xFF; // Load alpha if it's there - palette.setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal); - srcPal++; - } - } else { // Not a palettized image - // Round up grayscale images - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); - // Convert trans channel to alpha for 32 bits - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - // Filler for alpha? - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - } - - unsigned char *line = (unsigned char*) malloc(info_ptr->rowbytes); - if (!line) { - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - PSP_ERROR("Couldn't allocate line\n"); - return -1; - } - - for (y = 0; y < height; y++) { - png_read_row(png_ptr, line, png_bytep_NULL); - buffer.copyFromRect(line, info_ptr->rowbytes, 0, y, width, 1); // Copy into buffer - //memcpy(buffer.getPixels()[y * buffer.getWidthInBytes()], line, info_ptr->rowbytes); - } - - free(line); - - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - return 0; -} - // Defines for working with PSP buttons #define CHANGED(x) (_buttonsChanged & (x)) #define PRESSED(x) ((_buttonsChanged & (x)) && (pad.Buttons & (x))) @@ -508,10 +348,11 @@ int PSPKeyboard::loadPngImage(Common::SeekableReadStream *file, Buffer &buffer, * Uses the state machine. * returns whether we have an event */ -bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) { +bool PSPKeyboard::processInput(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); bool haveEvent = false; // Whether we have an event for the event manager to process + bool havePspEvent = false; event.kbd.flags = 0; _buttonsChanged = _prevButtons ^ pad.Buttons; @@ -530,11 +371,11 @@ bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) { haveEvent = true; _dirty = true; if (UP(PSP_CTRL_START)) - _state = kInvisible; // Make us invisible if unpressed + havePspEvent = true; } // Check for being in state of moving the keyboard onscreen or pressing select else if (_state == kMove) - handleMoveState(pad); + havePspEvent = handleMoveState(pad); else if (_state == kDefault) haveEvent = handleDefaultState(event, pad); else if (_state == kCornersSelected) @@ -544,12 +385,16 @@ bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) { else if (_state == kLTriggerDown) handleLTriggerDownState(pad); // Deal with trigger states + if (havePspEvent) { + pspEvent.type = PSP_EVENT_SHOW_VIRTUAL_KB; // tell the input handler we're off + pspEvent.data = false; + } _prevButtons = pad.Buttons; return haveEvent; } -void PSPKeyboard::handleMoveState(SceCtrlData &pad) { +bool PSPKeyboard::handleMoveState(SceCtrlData &pad) { DEBUG_ENTER_FUNC(); if (UP(PSP_CTRL_SELECT)) { // Toggle between visible and invisible @@ -560,6 +405,9 @@ void PSPKeyboard::handleMoveState(SceCtrlData &pad) { _state = kDefault; _moved = false; // reset moved flag } + if (_state == kInvisible) { + return true; // we become invisible + } } else if (DOWN(PSP_DPAD)) { // How we move the KB onscreen _moved = true; _dirty = true; @@ -573,6 +421,7 @@ void PSPKeyboard::handleMoveState(SceCtrlData &pad) { else /* DOWN(PSP_CTRL_RIGHT) */ increaseKeyboardLocationX(5); } + return false; } bool PSPKeyboard::handleDefaultState(Common::Event &event, SceCtrlData &pad) { diff --git a/backends/platform/psp/pspkeyboard.h b/backends/platform/psp/pspkeyboard.h index a30e7d0f32..ebf21cfd54 100644 --- a/backends/platform/psp/pspkeyboard.h +++ b/backends/platform/psp/pspkeyboard.h @@ -29,12 +29,15 @@ #include "common/events.h" #include "common/stream.h" #include "backends/platform/psp/display_client.h" +//#include "backends/platform/psp/input.h" #include <pspctrl.h> //number of modes #define MODE_COUNT 4 #define guiStringsSize 8 /* size of guistrings array */ +class PspEvent; + class PSPKeyboard : public DisplayClient { private: @@ -58,10 +61,9 @@ public: void setClean() { _dirty = false; } bool isVisible() const { return _state != kInvisible; } // Check if visible void setVisible(bool val); - bool processInput(Common::Event &event, SceCtrlData &pad); // Process input + bool processInput(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); // Process input void moveTo(const int newX, const int newY); // Move keyboard void render(); // Draw the keyboard onscreen - private: enum CursorDirections { kUp = 0, @@ -75,14 +77,11 @@ private: Palette _palettes[guiStringsSize]; GuRenderer _renderer; - int loadPngImage(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette); - int getPngImageSize(Common::SeekableReadStream *, uint32 *png_width, uint32 *png_height, uint32 *paletteSize); - uint32 convert_pow2(uint32 size); void increaseKeyboardLocationX(int amount); // Move keyboard onscreen void increaseKeyboardLocationY(int amount); void convertCursorToXY(CursorDirections cur, int &x, int &y); - void handleMoveState(SceCtrlData &pad); + bool handleMoveState(SceCtrlData &pad); bool handleDefaultState(Common::Event &event, SceCtrlData &pad); bool handleCornersSelectedState(Common::Event &event, SceCtrlData &pad); bool getInputChoice(Common::Event &event, SceCtrlData &pad); diff --git a/backends/platform/psp/rtc.cpp b/backends/platform/psp/rtc.cpp index 57edea7e49..f26e5770a6 100644 --- a/backends/platform/psp/rtc.cpp +++ b/backends/platform/psp/rtc.cpp @@ -23,13 +23,13 @@ * */ -#include <time.h> +#include <time.h> #include <psptypes.h> #include <psprtc.h> - -#include "common/scummsys.h" -#include "backends/platform/psp/rtc.h" - + +#include "common/scummsys.h" +#include "backends/platform/psp/rtc.h" + //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ @@ -51,13 +51,13 @@ void PspRtc::init() { // init our starting ticks #define MS_LOOP_AROUND 4294967 /* We loop every 2^32 / 1000 = 71 minutes */ #define MS_LOOP_CHECK 60000 /* Threading can cause weird mixups without this */ -// Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause +// Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause // unpredictable results uint32 PspRtc::getMillis() { uint32 ticks[2]; - + sceRtcGetCurrentTick((u64 *)ticks); // can introduce weird thread delays - + uint32 millis = ticks[0]/1000; millis -= _startMillis; // get ms since start of program @@ -66,22 +66,22 @@ uint32 PspRtc::getMillis() { _looped = true; _milliOffset += MS_LOOP_AROUND; // add the needed offset PSP_DEBUG_PRINT("looping around. last ms[%d], curr ms[%d]\n", _lastMillis, millis); - } + } } else { _looped = false; } - - _lastMillis = millis; - + + _lastMillis = millis; + return millis + _milliOffset; } uint32 PspRtc::getMicros() { uint32 ticks[2]; - + sceRtcGetCurrentTick((u64 *)ticks); ticks[0] -= _startMicros; - - return ticks[0]; + + return ticks[0]; } diff --git a/backends/platform/psp/rtc.h b/backends/platform/psp/rtc.h index 7c1a28474d..841d636e2b 100644 --- a/backends/platform/psp/rtc.h +++ b/backends/platform/psp/rtc.h @@ -27,7 +27,7 @@ #define _PSP_RTC_H_ #include "common/singleton.h" - + class PspRtc : public Common::Singleton<PspRtc> { private: uint32 _startMillis; @@ -47,4 +47,4 @@ public: uint32 getMicros(); }; -#endif
\ No newline at end of file +#endif diff --git a/backends/platform/psp/tests.cpp b/backends/platform/psp/tests.cpp index d1bdb9e640..4064ee1d98 100644 --- a/backends/platform/psp/tests.cpp +++ b/backends/platform/psp/tests.cpp @@ -23,13 +23,13 @@ * */ -// PSP speed and unit tests. Activate in tests.h -// You may also want to build without any engines. - +// PSP speed and unit tests. Activate in tests.h +// You may also want to build without any engines. + #include "backends/platform/psp/tests.h" -#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) - +#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) + #include "common/scummsys.h" #include <pspiofilemgr_fcntl.h> #include <pspiofilemgr_stat.h> @@ -43,20 +43,22 @@ #include "backends/platform/psp/rtc.h" #include "backends/platform/psp/thread.h" #include "backends/platform/psp/memory.h" - +#include "common/stream.h" +#include "common/file.h" +#include "common/fs.h" #define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */ #define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */ - + //#define __PSP_DEBUG_FUNCS__ //#define __PSP_DEBUG_PRINT__ - + // Results: (333Mhz/222Mhz) // Getting a tick: 1-2 us // Getting a time structure: 9/14us // ie. using a tick and just dividing by 1000 saves us time. - -#include "backends/platform/psp/trace.h" + +#include "backends/platform/psp/trace.h" class PspSpeedTests { public: @@ -65,11 +67,11 @@ public: void seekSpeed(); void msReadSpeed(); void threadFunctionsSpeed(); - void semaphoreSpeed(); + void semaphoreSpeed(); static int threadFunc(SceSize args, void *argp); void semaphoreManyThreadSpeed(); void fastCopySpeed(); - + private: enum { MEMCPY_BUFFER_SIZE = 8192 @@ -93,16 +95,16 @@ void PspSpeedTests::tickSpeed() { uint32 currentTicks1[2]; uint32 currentTicks2[2]; - + sceRtcGetCurrentTick((u64 *)currentTicks1); sceRtcGetCurrentTick((u64 *)currentTicks2); PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks1[0], currentTicks1[1], currentTicks1[0], currentTicks1[1]); PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks2[0], currentTicks2[1], currentTicks2[0], currentTicks2[1]); - + pspTime time; sceRtcSetTick(&time, (u64 *)currentTicks2); - PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds); - + PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds); + pspTime time1; pspTime time2; sceRtcGetCurrentClockLocalTime(&time1); @@ -117,7 +119,7 @@ void PspSpeedTests::getMicrosSpeed() { time2 = PspRtc::instance().getMicros(); time3 = PspRtc::instance().getMicros(); time4 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("getMicros() times: %d, %d, %d\n", time4-time3, time3-time2, time2-time1); } @@ -126,8 +128,8 @@ void PspSpeedTests::readAndTime(uint32 bytes, char *buffer, FILE *file) { // test minimal read fread(buffer, bytes, 1, file); uint32 time2 = PspRtc::instance().getMicros(); - - PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1); + + PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1); } /* @@ -156,7 +158,7 @@ void PspSpeedTests::msReadSpeed() { file = fopen("ms0:/psp/music/track1.mp3", "r"); char *buffer = (char *)malloc(2 * 1024 * 1024); - + readAndTime(1, buffer, file); readAndTime(10, buffer, file); readAndTime(50, buffer, file); @@ -168,32 +170,32 @@ void PspSpeedTests::msReadSpeed() { readAndTime(6000, buffer, file); readAndTime(7000, buffer, file); readAndTime(8000, buffer, file); - readAndTime(9000, buffer, file); + readAndTime(9000, buffer, file); readAndTime(10000, buffer, file); readAndTime(30000, buffer, file); readAndTime(50000, buffer, file); readAndTime(80000, buffer, file); readAndTime(100000, buffer, file); - + fclose(file); - free(buffer); + free(buffer); } - + void PspSpeedTests::seekAndTime(int bytes, int origin, FILE *file) { char buffer[1000]; - + uint32 time1 = PspRtc::instance().getMicros(); // test minimal read fseek(file, bytes, origin); uint32 time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("Seeking %d byte from %d took %dus\n", bytes, origin, time2-time1); time1 = PspRtc::instance().getMicros(); // test minimal read fread(buffer, 1000, 1, file); time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("Reading 1000 bytes took %dus\n", time2-time1); } @@ -244,9 +246,9 @@ int PspSpeedTests::getThreadIdSpeed() { uint32 time1 = PspRtc::instance().getMicros(); int threadId = sceKernelGetThreadId(); uint32 time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("Getting thread ID %d took %dus\n", threadId, time2-time1); - + return threadId; } @@ -255,7 +257,7 @@ void PspSpeedTests::getPrioritySpeed() { uint32 time1 = PspRtc::instance().getMicros(); int priority = sceKernelGetThreadCurrentPriority(); uint32 time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("Getting thread priority %d took %dus\n", priority, time2-time1); } @@ -264,7 +266,7 @@ void PspSpeedTests::changePrioritySpeed(int id, int priority) { uint32 time1 = PspRtc::instance().getMicros(); sceKernelChangeThreadPriority(id, priority); uint32 time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("Changing thread priority to %d for id %d took %dus\n", priority, id, time2-time1); } @@ -278,53 +280,53 @@ void PspSpeedTests::threadFunctionsSpeed() { changePrioritySpeed(id, 30); changePrioritySpeed(id, 35); changePrioritySpeed(id, 25); - + // test context switch time for (int i=0; i<10; i++) { uint time1 = PspRtc::instance().getMicros(); PspThread::delayMicros(0); uint time2 = PspRtc::instance().getMicros(); - PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1); // 10-15us - } + PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1); // 10-15us + } } - -void PspSpeedTests::semaphoreSpeed() { + +void PspSpeedTests::semaphoreSpeed() { PspSemaphore sem(1); - + uint32 time1 = PspRtc::instance().getMicros(); - + sem.take(); - + uint32 time2 = PspRtc::instance().getMicros(); - + PSP_INFO_PRINT("taking semaphore took %d us\n", time2-time1); // 10us - + uint32 time3 = PspRtc::instance().getMicros(); - + sem.give(); - + uint32 time4 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("releasing semaphore took %d us\n", time4-time3); //10us-55us } int PspSpeedTests::threadFunc(SceSize args, void *argp) { PSP_INFO_PRINT("thread %x created.\n", sceKernelGetThreadId()); - + _sem.take(); - + PSP_INFO_PRINT("grabbed semaphore. Quitting thread\n"); - + return 0; } -void PspSpeedTests::semaphoreManyThreadSpeed() { - +void PspSpeedTests::semaphoreManyThreadSpeed() { + // create 4 threads for (int i=0; i<4; i++) { int thid = sceKernelCreateThread("my_thread", PspSpeedTests::threadFunc, 0x18, 0x10000, THREAD_ATTR_USER, NULL); sceKernelStartThread(thid, 0, 0); } - + PSP_INFO_PRINT("main thread. created threads\n"); uint32 threads = _sem.numOfWaitingThreads(); @@ -332,10 +334,10 @@ void PspSpeedTests::semaphoreManyThreadSpeed() { threads = _sem.numOfWaitingThreads(); PSP_INFO_PRINT("main thread: waiting threads[%d]\n", threads); } - + PSP_INFO_PRINT("main: semaphore value[%d]\n", _sem.getValue()); PSP_INFO_PRINT("main thread: waiting threads[%d]\n", _sem.numOfWaitingThreads()); - + _sem.give(4); } @@ -344,31 +346,31 @@ void PspSpeedTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes) { uint32 fastcopyTime, memcpyTime; const int iterations = 2000; int intc; - + intc = pspSdkDisableInterrupts(); - + time1 = PspRtc::instance().getMicros(); for (int i=0; i<iterations; i++) { PspMemory::fastCopy(dst, src, bytes); - } + } time2 = PspRtc::instance().getMicros(); - + pspSdkEnableInterrupts(intc); - + fastcopyTime = time2-time1; - + intc = pspSdkDisableInterrupts(); - + time1 = PspRtc::instance().getMicros(); for (int i=0; i<iterations; i++) { memcpy(dst, src, bytes); - } + } time2 = PspRtc::instance().getMicros(); - + pspSdkEnableInterrupts(intc); - + memcpyTime = time2-time1; - + PSP_INFO_PRINT("%d bytes. memcpy[%d], fastcopy[%d]\n", bytes, memcpyTime, fastcopyTime); } @@ -395,16 +397,16 @@ void PspSpeedTests::fastCopySpeed() { uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE); uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE); - + // fill buffer 1 for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++) bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16); - + // print buffer for (int i=0; i<50; i++) PSP_INFO_PRINT("%x ", bufferSrc32[i]); PSP_INFO_PRINT("\n"); - + byte *bufferSrc = ((byte *)bufferSrc32); byte *bufferDst = ((byte *)bufferDst32); @@ -413,7 +415,7 @@ void PspSpeedTests::fastCopySpeed() { fastCopyDifferentSizes(bufferDst+1, bufferSrc+1); fastCopyDifferentSizes(bufferDst, bufferSrc+1); fastCopyDifferentSizes(bufferDst+1, bufferSrc); - + PSP_INFO_PRINT("\n\ndst cached, src uncached: -----------------\n"); bufferSrc = UNCACHED(bufferSrc); fastCopyDifferentSizes(bufferDst, bufferSrc); @@ -427,7 +429,7 @@ void PspSpeedTests::fastCopySpeed() { fastCopyDifferentSizes(bufferDst+1, bufferSrc+1); fastCopyDifferentSizes(bufferDst, bufferSrc+1); fastCopyDifferentSizes(bufferDst+1, bufferSrc); - + PSP_INFO_PRINT("\n\ndst uncached, src cached: -------------------\n"); bufferSrc = CACHED(bufferSrc); fastCopyDifferentSizes(bufferDst, bufferSrc); @@ -435,7 +437,7 @@ void PspSpeedTests::fastCopySpeed() { fastCopyDifferentSizes(bufferDst, bufferSrc+1); fastCopyDifferentSizes(bufferDst+1, bufferSrc); - + free(bufferSrc32); free(bufferDst32); } @@ -445,15 +447,17 @@ void PspSpeedTests::fastCopySpeed() { class PspUnitTests { public: void testFastCopy(); + bool testFileSystem(); private: enum { MEMCPY_BUFFER_SIZE = 8192 }; - + void fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap = false); void fastCopyDifferentSizes(byte *dst, byte *src, bool swap = false); -}; + +}; void PspUnitTests::testFastCopy() { PSP_INFO_PRINT("running fastcopy unit test ***********\n"); @@ -461,19 +465,19 @@ void PspUnitTests::testFastCopy() { uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE); uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE); - + // fill buffer 1 for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++) bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16); - + // print buffer for (int i=0; i<50; i++) PSP_INFO_PRINT("%x ", bufferSrc32[i]); PSP_INFO_PRINT("\n"); - + byte *bufferSrc = ((byte *)bufferSrc32); byte *bufferDst = ((byte *)bufferDst32); - + fastCopyDifferentSizes(bufferDst, bufferSrc, true); fastCopyDifferentSizes(bufferDst+1, bufferSrc+1); fastCopyDifferentSizes(bufferDst+2, bufferSrc+2, true); @@ -487,12 +491,12 @@ void PspUnitTests::testFastCopy() { fastCopyDifferentSizes(bufferDst+2, bufferSrc+1); fastCopyDifferentSizes(bufferDst+2, bufferSrc+3); fastCopyDifferentSizes(bufferDst+3, bufferSrc+1); - fastCopyDifferentSizes(bufferDst+3, bufferSrc+2); - + fastCopyDifferentSizes(bufferDst+3, bufferSrc+2); + free(bufferSrc32); free(bufferDst32); } - + void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) { fastCopySpecificSize(dst, src, 1); fastCopySpecificSize(dst, src, 2, swap); @@ -505,7 +509,7 @@ void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) { fastCopySpecificSize(dst, src, 12, swap); fastCopySpecificSize(dst, src, 13); fastCopySpecificSize(dst, src, 14, swap); - fastCopySpecificSize(dst, src, 15); + fastCopySpecificSize(dst, src, 15); fastCopySpecificSize(dst, src, 16, swap); fastCopySpecificSize(dst, src, 17); fastCopySpecificSize(dst, src, 18, swap); @@ -525,21 +529,186 @@ void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) { void PspUnitTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap) { memset(dst, 0, bytes); PspMemory::fastCopy(dst, src, bytes); - + if (swap) { // test swap also memset(dst, 0, bytes); - + // pixelformat for swap PSPPixelFormat format; format.set(PSPPixelFormat::Type_4444, true); - + PspMemory::fastSwap(dst, src, bytes, format); - } + } +} + +// This function leaks. For now I don't care +bool PspUnitTests::testFileSystem() { + // create memory + const uint32 BufSize = 32 * 1024; + char* buffer = new char[BufSize]; + int i; + Common::WriteStream *wrStream; + Common::SeekableReadStream *rdStream; + + PSP_INFO_PRINT("testing fileSystem...\n"); + + // fill buffer + for (i=0; i<(int)BufSize; i += 4) { + buffer[i] = 'A'; + buffer[i + 1] = 'B'; + buffer[i + 2] = 'C'; + buffer[i + 3] = 'D'; + } + + // create a file + const char *path = "./file.test"; + Common::FSNode file(path); + + PSP_INFO_PRINT("creating write stream...\n"); + + wrStream = file.createWriteStream(); + if (!wrStream) { + PSP_ERROR("%s couldn't be created.\n", path); + return false; + } + + // write contents + char* index = buffer; + int32 totalLength = BufSize; + int32 curLength = 50; + + PSP_INFO_PRINT("writing...\n"); + + while(totalLength - curLength > 0) { + if ((int)wrStream->write(index, curLength) != curLength) { + PSP_ERROR("couldn't write %d bytes\n", curLength); + return false; + } + totalLength -= curLength; + index += curLength; + //curLength *= 2; + //PSP_INFO_PRINT("write\n"); + } + + // write the rest + if ((int)wrStream->write(index, totalLength) != totalLength) { + PSP_ERROR("couldn't write %d bytes\n", curLength); + return false; + } + + delete wrStream; + + PSP_INFO_PRINT("reading...\n"); + + rdStream = file.createReadStream(); + if (!rdStream) { + PSP_ERROR("%s couldn't be created.\n", path); + return false; + } + + // seek to beginning + if (!rdStream->seek(0, SEEK_SET)) { + PSP_ERROR("couldn't seek to the beginning after writing the file\n"); + return false; + } + + // read the contents + char *readBuffer = new char[BufSize + 4]; + memset(readBuffer, 0, (BufSize + 4)); + index = readBuffer; + while (rdStream->read(index, 100) == 100) { + index += 100; + } + + if (!rdStream->eos()) { + PSP_ERROR("didn't find EOS at end of stream\n"); + return false; + } + + // compare + for (i=0; i<(int)BufSize; i++) + if (buffer[i] != readBuffer[i]) { + PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]); + return false; + } + + // Check for exceeding limit + for (i=0; i<4; i++) { + if (readBuffer[BufSize + i]) { + PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]); + } + } + + delete rdStream; + + PSP_INFO_PRINT("writing...\n"); + + wrStream = file.createWriteStream(); + if (!wrStream) { + PSP_ERROR("%s couldn't be created.\n", path); + return false; + } + + const char *phrase = "Jello is really fabulous"; + uint32 phraseLen = strlen(phrase); + + int ret; + if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) { + PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen); + return false; + } + + PSP_INFO_PRINT("reading...\n"); + + delete wrStream; + rdStream = file.createReadStream(); + if (!rdStream) { + PSP_ERROR("%s couldn't be created.\n", path); + return false; + } + + char *readPhrase = new char[phraseLen + 2]; + memset(readPhrase, 0, phraseLen + 2); + + if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) { + PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen); + return false; + } + + for (i=0; i<(int)phraseLen; i++) { + if (readPhrase[i] != phrase[i]) { + PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]); + return false; + } + } + + // check for exceeding + if (readPhrase[i] != 0) { + PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i); + return false; + } + + PSP_INFO_PRINT("trying to read end...\n"); + + // seek to end + if (!rdStream->seek(0, SEEK_END)) { + PSP_ERROR("couldn't seek to end for append\n"); + return false; + }; + + // try to read + if (rdStream->read(readPhrase, 2) || !rdStream->eos()) { + PSP_ERROR("was able to read at end of file\n"); + return false; + } + + PSP_INFO_PRINT("ok\n"); + return true; } void psp_tests() { PSP_INFO_PRINT("in tests\n"); - + #ifdef PSP_ENABLE_SPEED_TESTS // Speed tests PspSpeedTests speedTests; @@ -549,17 +718,18 @@ void psp_tests() { speedTests.seekSpeed(); speedTests.msReadSpeed(); speedTests.threadFunctionsSpeed(); - speedTests.semaphoreSpeed(); + speedTests.semaphoreSpeed(); speedTests.semaphoreManyThreadSpeed(); speedTests.fastCopySpeed(); -#endif - +#endif + #ifdef PSP_ENABLE_UNIT_TESTS // Unit tests PspUnitTests unitTests; - - unitTests.testFastCopy(); -#endif -} -#endif /* (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) */
\ No newline at end of file + //unitTests.testFastCopy(); + unitTests.testFileSystem(); +#endif +} + +#endif /* (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) */ diff --git a/backends/platform/psp/tests.h b/backends/platform/psp/tests.h index 1518acfb4c..9af7ba8d7d 100644 --- a/backends/platform/psp/tests.h +++ b/backends/platform/psp/tests.h @@ -23,14 +23,14 @@ * */ -#ifndef _PSP_TESTS_H_ +#ifndef _PSP_TESTS_H_ #define _PSP_TESTS_H_ //#define PSP_ENABLE_UNIT_TESTS // run unit tests //#define PSP_ENABLE_SPEED_TESTS // run speed tests -#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) +#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) void psp_tests(); #endif -#endif /* _PSP_TESTS_H_ */
\ No newline at end of file +#endif /* _PSP_TESTS_H_ */ diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp index 916b1e553b..f9e497a342 100644 --- a/backends/platform/psp/thread.cpp +++ b/backends/platform/psp/thread.cpp @@ -23,12 +23,12 @@ * */ -#include <pspthreadman.h> +#include <pspthreadman.h> #include "backends/platform/psp/thread.h" #include "backends/platform/psp/trace.h" - -// Class PspThreadable -------------------------------------------------- + +// Class PspThreadable -------------------------------------------------- // Inherit this to create C++ threads easily bool PspThreadable::threadCreateAndStart(const char *threadName, int priority, int stackSize, bool useVfpu /*= false*/) { @@ -38,41 +38,41 @@ bool PspThreadable::threadCreateAndStart(const char *threadName, int priority, i PSP_ERROR("thread already created!\n"); return false; } - + _threadId = sceKernelCreateThread(threadName, __threadCallback, priority, stackSize, THREAD_ATTR_USER, 0); // add VFPU support if (_threadId < 0) { PSP_ERROR("failed to create %s thread. Error code %d\n", threadName, _threadId); return false; } - + // We want to pass the pointer to this, but we'll have to take address of this so use a little trick PspThreadable *_this = this; - + if (sceKernelStartThread(_threadId, sizeof(uint32 *), &_this) < 0) { PSP_ERROR("failed to start %s thread id[%d]\n", threadName, _threadId); return false; } - - PSP_DEBUG_PRINT("Started %s thread with id[%x]\n", threadName, _threadId); - + + PSP_DEBUG_PRINT("Started %s thread with id[%x]\n", threadName, _threadId); + return true; } // Callback function to be called by PSP kernel int PspThreadable::__threadCallback(SceSize, void *__this) { DEBUG_ENTER_FUNC(); - + PspThreadable *_this = *(PspThreadable **)__this; // Dereference the copied value which was 'this' - + _this->threadFunction(); // call the virtual function - + return 0; } // PspThread class // Utilities to access general thread functions - + void PspThread::delayMillis(uint32 ms) { sceKernelDelayThread(ms * 1000); } @@ -90,8 +90,8 @@ void PspThread::delayMicros(uint32 us) { PspSemaphore::PspSemaphore(int initialValue, int maxValue/*=255*/) { DEBUG_ENTER_FUNC(); _handle = 0; - _handle = (uint32)sceKernelCreateSema("ScummVM Sema", 0 /* attr */, - initialValue, maxValue, + _handle = (uint32)sceKernelCreateSema("ScummVM Sema", 0 /* attr */, + initialValue, maxValue, 0 /*option*/); if (!_handle) PSP_ERROR("failed to create semaphore.\n"); @@ -108,10 +108,10 @@ int PspSemaphore::numOfWaitingThreads() { DEBUG_ENTER_FUNC(); SceKernelSemaInfo info; info.numWaitThreads = 0; - + if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0) PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle); - + return info.numWaitThreads; } @@ -119,10 +119,10 @@ int PspSemaphore::getValue() { DEBUG_ENTER_FUNC(); SceKernelSemaInfo info; info.currentCount = 0; - + if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0) PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle); - + return info.currentCount; } @@ -130,18 +130,18 @@ bool PspSemaphore::pollForValue(int value) { DEBUG_ENTER_FUNC(); if (sceKernelPollSema((SceUID)_handle, value) < 0) return false; - + return true; } // false: timeout or error bool PspSemaphore::takeWithTimeOut(uint32 timeOut) { DEBUG_ENTER_FUNC(); - + uint32 *pTimeOut = 0; - if (timeOut) + if (timeOut) pTimeOut = &timeOut; - + if (sceKernelWaitSema(_handle, 1, pTimeOut) < 0) // we always wait for 1 return false; return true; @@ -149,9 +149,9 @@ bool PspSemaphore::takeWithTimeOut(uint32 timeOut) { bool PspSemaphore::give(int num /*=1*/) { DEBUG_ENTER_FUNC(); - + if (sceKernelSignalSema((SceUID)_handle, num) < 0) - return false; + return false; return true; } @@ -161,7 +161,7 @@ bool PspMutex::lock() { DEBUG_ENTER_FUNC(); int threadId = sceKernelGetThreadId(); bool ret = true; - + if (_ownerId == threadId) { _recursiveCount++; } else { @@ -176,19 +176,19 @@ bool PspMutex::unlock() { DEBUG_ENTER_FUNC(); int threadId = sceKernelGetThreadId(); bool ret = true; - + if (_ownerId != threadId) { PSP_ERROR("attempt to unlock mutex by thread[%x] as opposed to owner[%x]\n", threadId, _ownerId); return false; } - + if (_recursiveCount) { _recursiveCount--; } else { _ownerId = 0; ret = _semaphore.give(1); - } + } return ret; } @@ -200,7 +200,7 @@ void PspCondition::releaseAll() { if (_waitingThreads > _signaledThreads) { // we have signals to issue int numWaiting = _waitingThreads - _signaledThreads; // threads we haven't signaled _signaledThreads = _waitingThreads; - + _waitSem.give(numWaiting); _mutex.unlock(); for (int i=0; i<numWaiting; i++) // wait for threads to tell us they're awake diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index de1c10a2aa..bbad2a9ead 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -34,7 +34,7 @@ class PspThreadable { protected: int _threadId; virtual void threadFunction() = 0; // this function will be called when the thread starts -public: +public: PspThreadable() : _threadId(-1) {} // constructor virtual ~PspThreadable() {} // destructor static int __threadCallback(SceSize, void *__this); // used to get called by sceKernelStartThread() Don't override @@ -43,7 +43,7 @@ public: // class for thread utils class PspThread { -public: +public: // static functions static void delayMillis(uint32 ms); // delay the current thread static void delayMicros(uint32 us); @@ -106,7 +106,7 @@ enum StackSizes { STACK_DISPLAY_THREAD = 2 * 1024, STACK_POWER_THREAD = 4 * 1024 }; - + #endif /* PSP_THREADS_H */ |