diff options
| author | Yotam Barnoy | 2010-10-31 11:08:43 +0000 |
|---|---|---|
| committer | Yotam Barnoy | 2010-10-31 11:08:43 +0000 |
| commit | 94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1 (patch) | |
| tree | 3df2a4ae7967c56d464729669fc06ce4e93dff36 /backends/platform/psp | |
| parent | 8df4278ba8cfbf71228e1927f9db635a9a30a57f (diff) | |
| parent | dca3c8d8bfc6c4db38cf8e8291818dd472041d4e (diff) | |
| download | scummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.tar.gz scummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.tar.bz2 scummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.zip | |
Updated with latest from trunk
svn-id: r53976
Diffstat (limited to 'backends/platform/psp')
35 files changed, 2397 insertions, 1254 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index e564200897..9f6b5c8921 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -126,7 +126,7 @@ endif # PSP LIBS PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ - -lpspkernel + -lpspkernel -lpspnet_inet # Add in PSPSDK includes and libraries. @@ -148,7 +148,10 @@ OBJS := powerman.o \ thread.o \ rtc.o \ mp3.o \ - tests.o + png_loader.o \ + image_viewer.o \ + tests.o \ + dummy.o BACKEND := psp @@ -200,4 +203,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..b83f1cab6d 100644 --- a/backends/platform/psp/README.PSP +++ b/backends/platform/psp/README.PSP @@ -1,81 +1,130 @@ -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. + - Press Start to return to the launcher and play another game. 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) +Right trigger + Start - F5 (Main Menu in some games) +Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad). +Right trigger + Select - Show Image Viewer (see below) +Start - Global Menu. Allows you to 'Return To Launcher' to play another game + +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) + + +Image Viewer +============ +For your convenience, I've included a simple image viewer in the PSP port. +You can view anything you want while playing a game. +There are a few simple rules to follow: + +- Images must be of PNG format. If you have images in another format, many + graphics utilities will convert them for you. +- Images must be named psp_image1.png, psp_image2.png etc. This is to make + sure there's no possible conflict between image files and game files. +- Images must be placed in the game directories. When using the image viewer, + only the images of the particular game being played will be available for viewing. +- Don't place any images in the ScummVM directory, or you won't be able to see + the images in the game directories. +- There's no guarantee that you'll be able to view your image. This is because + big images take a lot of memory (more than the size of the image on disk). If there + isn't enough memory left to show the image, ScummVM will tell you so. Try to make the + image smaller by either shrinking it or reducing the colors to 256 color palette mode. + +Image Viewer Controls: +===================== +Left/Right - previous/next image (e.g. go from psp_image1.png to psp_image2.png) +Up/down - zoom in/out +Analog - move around the image +Triggers, Start: - exit image viewer + + +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 + Select - Image Viewer +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.) -- 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 +- 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 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 +132,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 +158,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 14691befee..b5a72dccd0 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 07f70cec7d..f5179028dc 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 6360772c96..4310b195dd 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,13 @@ 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 +370,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; @@ -378,45 +378,45 @@ void Buffer::copyToArray(byte *dst, int pitch) { } while (--h); } -/* We can size the buffer either by texture size (multiple of 2^n) or source size. The GU can - really handle both, but is supposed to get only 2^n size buffers */ void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("w[%u], h[%u], %s\n", width, height, textureOrSource ? "size by source" : "size by texture"); - + + // We can size the buffer either by texture size (multiple of 2^n) or source size. + // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used. + _sourceSize.width = width; _sourceSize.height = height; - _textureSize.width = scaleUpToPowerOfTwo(width); + _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512 _textureSize.height = scaleUpToPowerOfTwo(height); - + if (textureOrSource == kSizeByTextureSize) { _width = _textureSize.width; _height = _textureSize.height; - } else { /* kSizeBySourceSize */ - _width = _sourceSize.width; + } else { // sizeBySourceSize + _width = _sourceSize.width; _height = _sourceSize.height; + + // adjust allocated width to be divisible by 32. + // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes + // We don't necessarily know the depth of the pixels here. So just make it divisible by 32. + uint32 checkDiv = _width & 31; + if (checkDiv) + _width += 32 - checkDiv; } + + PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture"); } -/* Scale a dimension (width/height) up to power of 2 for the texture */ +// Scale a dimension (width/height) up to power of 2 for the texture +// Will only go up to 512 since that's the maximum PSP texture size uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) { - uint32 textureDimension = 0; - if (size <= 16) - textureDimension = 16; - else if (size <= 32) - textureDimension = 32; - else if (size <= 64) - textureDimension = 64; - else if (size <= 128) - textureDimension = 128; - else if (size <= 256) - textureDimension = 256; - else - textureDimension = 512; + uint32 textureDimension = 16; + while (size > textureDimension && textureDimension < 512) + textureDimension <<= 1; - PSP_DEBUG_PRINT("power of 2 = %u\n", textureDimension); + PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension); return textureDimension; } @@ -539,51 +539,41 @@ void GuRenderer::render() { DEBUG_ENTER_FUNC(); PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues()); - setMaxTextureOffsetByIndex(0, 0); - guProgramDrawBehavior(); if (_buffer->hasPalette()) guLoadPalette(); guProgramTextureFormat(); - guLoadTexture(); - - Vertex *vertices = guGetVertices(); - fillVertices(vertices); - guDrawVertices(vertices); - - if (_buffer->getSourceWidth() > 512) { - setMaxTextureOffsetByIndex(1, 0); - - guLoadTexture(); - - vertices = guGetVertices(); - fillVertices(vertices); - - guDrawVertices(vertices); + // Loop over patches of 512x512 pixel textures and draw them + for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) { + _textureLoadOffset.y = j; + + for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) { + _textureLoadOffset.x = i; + + guLoadTexture(); + Vertex *vertices = guGetVertices(); + fillVertices(vertices); + + guDrawVertices(vertices); + } } } -inline void GuRenderer::setMaxTextureOffsetByIndex(uint32 x, uint32 y) { - DEBUG_ENTER_FUNC(); - const uint32 maxTextureSizeShift = 9; /* corresponds to 512 = max texture size*/ - - _maxTextureOffset.x = x << maxTextureSizeShift; /* x times 512 */ - _maxTextureOffset.y = y << maxTextureSizeShift; /* y times 512 */ -} - inline void GuRenderer::guProgramDrawBehavior() { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", _blending ? "on" : "off", _colorTest ? "on" : "off", _alphaReverse ? "on" : "off", _keyColor); + PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", + _blending ? "on" : "off", _colorTest ? "on" : "off", + _alphaReverse ? "on" : "off", _keyColor); if (_blending) { sceGuEnable(GU_BLEND); - if (_alphaReverse) // Reverse the alpha value (0 is 1) + if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0); - else // Normal alpha values + else // Normal alpha values sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); } else @@ -591,7 +581,9 @@ inline void GuRenderer::guProgramDrawBehavior() { if (_colorTest) { sceGuEnable(GU_COLOR_TEST); - sceGuColorFunc(GU_NOTEQUAL, _keyColor, 0x00ffffff); + sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color + _keyColor, + 0x00ffffff); // match everything but alpha } else sceGuDisable(GU_COLOR_TEST); } @@ -612,7 +604,8 @@ inline void GuRenderer::guLoadPalette() { PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask); sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0); - sceGuClutLoad(_palette->getNumOfEntries() >> 3, _palette->getRawValues()); + sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason + _palette->getRawValues()); } inline void GuRenderer::guProgramTextureFormat() { @@ -658,7 +651,17 @@ inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) { inline void GuRenderer::guLoadTexture() { DEBUG_ENTER_FUNC(); - sceGuTexImage(0, _buffer->getTextureWidth(), _buffer->getTextureHeight(), _buffer->getWidth(), _buffer->getPixels() + _buffer->_pixelFormat.pixelsToBytes(_maxTextureOffset.x)); + byte *startPoint = _buffer->getPixels(); + if (_textureLoadOffset.x) + startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x); + if (_textureLoadOffset.y) + startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y; + + sceGuTexImage(0, + _buffer->getTextureWidth(), // texture width (must be power of 2) + _buffer->getTextureHeight(), // texture height (must be power of 2) + _buffer->getWidth(), // width of a line of the image (to get to the next line) + startPoint); // where to start reading } inline Vertex *GuRenderer::guGetVertices() { @@ -676,40 +679,40 @@ void GuRenderer::fillVertices(Vertex *vertices) { uint32 outputWidth = _displayManager->getOutputWidth(); uint32 outputHeight = _displayManager->getOutputHeight(); - float textureStartX, textureStartY, textureEndX, textureEndY; - // Texture adjustments for eliminating half-pixel artifacts from scaling // Not necessary if we don't scale - float textureAdjustment = 0.0f; + float textureFix = 0.0f; if (_useGlobalScaler && - (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleX() != 1.0f)) - textureAdjustment = 0.5f; - - textureStartX = textureAdjustment + _offsetInBuffer.x; //debug - textureStartY = textureAdjustment + _offsetInBuffer.y; - // We subtract maxTextureOffset because our shifted texture starts at 512 and will go to 640 - textureEndX = _offsetInBuffer.x + _drawSize.width - textureAdjustment - _maxTextureOffset.x; - textureEndY = _offsetInBuffer.y + _drawSize.height - textureAdjustment; - + (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f)) + textureFix = 0.5f; + + // These coordinates describe an area within the texture. ie. we already loaded a square of texture, + // now the coordinates within it are 0 to the edge of the area of the texture we want to draw + float textureStartX = textureFix + _offsetInBuffer.x; + float textureStartY = textureFix + _offsetInBuffer.y; + // even when we draw one of several textures, we use the whole drawsize of the image. The GU + // will draw what it can with the texture it has and scale it properly for us. + float textureEndX = -textureFix + _offsetInBuffer.x + _drawSize.width - _textureLoadOffset.x; + float textureEndY = -textureFix + _offsetInBuffer.y + _drawSize.height - _textureLoadOffset.y; // For scaling to the final image size, calculate the gaps on both sides uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0; uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0; // Save scaled offset on screen - float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x); - float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y); - - float imageStartX, imageStartY, imageEndX, imageEndY; + float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x); + float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y); - imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x)); - imageStartY = gapY + scaledOffsetOnScreenY; + float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x))); + float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y))); + float imageEndX, imageEndY; + 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); - imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height); + imageEndX = gapX + scaledOffsetOnScreenX + scaleSourceToOutput(true, stretch(true, _drawSize.width)); + imageEndY = gapY + scaledOffsetOnScreenY + scaleSourceToOutput(false, stretch(false, _drawSize.height)); } vertices[0].u = textureStartX; @@ -728,8 +731,8 @@ void GuRenderer::fillVertices(Vertex *vertices) { PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY); } -/* Scale the input X offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputX(float offset) { +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::scaleSourceToOutput(bool x, float offset) { float result; if (!_useGlobalScaler) @@ -737,28 +740,22 @@ inline float GuRenderer::scaleSourceToOutputX(float offset) { else if (!offset) result = 0.0f; else - result = offset * _displayManager->getScaleX(); + result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY(); return result; } -/* Scale the input Y offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputY(float offset) { - float result; - - if (!_useGlobalScaler) - result = offset; - else if (!offset) - result = 0.0f; - else - result = offset * _displayManager->getScaleY(); - - return result; +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::stretch(bool x, float size) { + if (!_stretch) + return size; + return (x ? size * _stretchX : size * _stretchY); } inline void GuRenderer::guDrawVertices(Vertex *vertices) { DEBUG_ENTER_FUNC(); + // This function shouldn't need changing. The '32' here refers to floating point vertices. sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices); } diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h index d05b0b046c..005fc76c7c 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 @@ -173,8 +174,13 @@ protected: class GuRenderer { public: // Constructors - GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} - GuRenderer(Buffer *buffer, Palette *palette) : _useGlobalScaler(false), _buffer(buffer), _palette(palette), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} + GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} + GuRenderer(Buffer *buffer, Palette *palette) : + _useGlobalScaler(false), _buffer(buffer), _palette(palette), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} static void setDisplayManager(DisplayManager *dm) { _displayManager = dm; } // Called by the Display Manager // Setters @@ -189,8 +195,7 @@ public: } void setBuffer(Buffer *buffer) { _buffer = buffer; } void setPalette(Palette *palette) { _palette = palette; } - void setMaxTextureOffsetByIndex(uint32 x, uint32 y); // For drawing multiple textures - void setOffsetOnScreen(uint32 x, uint32 y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } + void setOffsetOnScreen(int x, int y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } void setOffsetInBuffer(uint32 x, uint32 y) { _offsetInBuffer.x = x; _offsetInBuffer.y = y; } void setColorTest(bool value) { _colorTest = value; } void setKeyColor(uint32 value) { _keyColor = _buffer->_pixelFormat.convertTo32BitColor(value); } @@ -198,6 +203,8 @@ public: void setAlphaReverse(bool value) { _alphaReverse = value; } void setFullScreen(bool value) { _fullScreen = value; } // Shortcut for rendering void setUseGlobalScaler(bool value) { _useGlobalScaler = value; } // Scale to screen + void setStretch(bool active) { _stretch = active; } + void setStretchXY(float x, float y) { _stretchX = x; _stretchY = y; } static void cacheInvalidate(void *pointer, uint32 size); @@ -215,11 +222,11 @@ protected: void guDrawVertices(Vertex *vertices); uint32 convertToGuPixelFormat(PSPPixelFormat::Type format); - float scaleSourceToOutputX(float offset); - float scaleSourceToOutputY(float offset); + float scaleSourceToOutput(bool x, float offset); + float stretch(bool x, float size); friend class MasterGuRenderer; - Point _maxTextureOffset; ///> For rendering textures > 512 pixels + Point _textureLoadOffset; ///> For rendering textures > 512 pixels Point _offsetOnScreen; ///> Where on screen to draw Point _offsetInBuffer; ///> Where in the texture to draw bool _useGlobalScaler; ///> Scale to the output size on screen @@ -232,6 +239,8 @@ protected: bool _colorTest; uint32 _keyColor; ///> Color to test against for color test. in 32 bits. bool _fullScreen; ///> Speeds up for fullscreen rendering + bool _stretch; ///> Whether zooming is activated + float _stretchX, _stretchY; }; #endif /* PSP_SCREEN_H */ diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index e65d6f4fd0..7454211da6 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -34,6 +34,7 @@ #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #define USE_DISPLAY_CALLBACK // to use callback for finishing the render #include "backends/platform/psp/display_manager.h" @@ -59,28 +60,93 @@ const OSystem::GraphicsMode DisplayManager::_supportedModes[] = { {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 @@ -88,12 +154,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; } @@ -149,7 +215,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 */ @@ -178,7 +244,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(); @@ -188,7 +254,7 @@ inline void MasterGuRenderer::guPostRender() { sceDisplayWaitVblankStart(); sceGuSwapBuffers(); _renderFinished = true; -#endif /* !USE_DISPLAY_CALLBACK */ +#endif /* !USE_DISPLAY_CALLBACK */ } void MasterGuRenderer::guShutDown() { @@ -216,7 +282,7 @@ void DisplayManager::init() { #ifdef USE_DISPLAY_CALLBACK _masterGuRenderer.setupCallbackThread(); #endif - + } void DisplayManager::setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format) { @@ -286,10 +352,10 @@ void DisplayManager::calculateScaleParams() { break; 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; } @@ -301,7 +367,7 @@ void DisplayManager::calculateScaleParams() { default: PSP_ERROR("Unsupported graphics mode[%d].\n", _graphicsMode); } - + // 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; @@ -316,51 +382,54 @@ 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 + // Any one of these being dirty causes everything to draw if (!_screen->isDirty() && - (!_overlay->isDirty()) && - (!_cursor->isDirty()) && - (!_keyboard->isDirty())) { + !_overlay->isDirty() && + !_cursor->isDirty() && + !_keyboard->isDirty() && + !_imageViewer->isDirty()) { PSP_DEBUG_PRINT("Nothing dirty\n"); 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", + PSP_DEBUG_PRINT("dirty: screen[%s], overlay[%s], cursor[%s], keyboard[%s], imageViewer[%s]\n", _screen->isDirty() ? "true" : "false", _overlay->isDirty() ? "true" : "false", _cursor->isDirty() ? "true" : "false", - _keyboard->isDirty() ? "true" : "false" + _keyboard->isDirty() ? "true" : "false", + _imageViewer->isDirty() ? "true" : "false", ); _masterGuRenderer.guPreRender(); // Set up rendering _screen->render(); - _screen->setClean(); // clean out dirty bit + + if (_imageViewer->isVisible()) + _imageViewer->render(); + _imageViewer->setClean(); if (_overlay->isVisible()) - _overlay->render(); - + _overlay->render(); _overlay->setClean(); if (_cursor->isVisible()) _cursor->render(); - _cursor->setClean(); if (_keyboard->isVisible()) _keyboard->render(); - _keyboard->setClean(); - - _masterGuRenderer.guPostRender(); + _masterGuRenderer.guPostRender(); + return true; // rendered successfully } diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h index 626415696a..5c7d4c799a 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,13 +89,14 @@ 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; class Overlay; class Cursor; class PSPKeyboard; +class ImageViewer; /** * Class that manages all display clients @@ -65,7 +108,8 @@ public: KEEP_ASPECT_RATIO, STRETCHED_FULL_SCREEN }; - DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {} + DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), + _imageViewer(0), _lastUpdateTime(0), _graphicsMode(0) {} ~DisplayManager(); void init(); @@ -76,11 +120,13 @@ public: uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; } const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; } - // Setters + // Setters for pointers void setScreen(Screen *screen) { _screen = screen; } void setCursor(Cursor *cursor) { _cursor = cursor; } void setOverlay(Overlay *overlay) { _overlay = overlay; } void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } + void setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format); // Getters @@ -106,6 +152,7 @@ private: Cursor *_cursor; Overlay *_overlay; PSPKeyboard *_keyboard; + ImageViewer *_imageViewer; MasterGuRenderer _masterGuRenderer; uint32 _lastUpdateTime; // For limiting FPS diff --git a/backends/platform/psp/dummy.cpp b/backends/platform/psp/dummy.cpp new file mode 100644 index 0000000000..4236734d4b --- /dev/null +++ b/backends/platform/psp/dummy.cpp @@ -0,0 +1,59 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + + //#include "common/scummsys.h" + #include <time.h> + #include <stdlib.h> + #include <stdio.h> + #include <png.h> + #include <sys/socket.h> + +//void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) { +//} + +//void userFlushFn(png_structp png_ptr) { +//} + + // Dummy functions are pulled in so that we don't need to build the plugins with certain libs + + int dummyFunc() { + + // For Broken Sword 2.5 + volatile int i; + i = clock(); + rename("dummyA", "dummyB"); + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_set_write_fn(png_ptr, NULL, NULL, NULL); + png_infop info_ptr; + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); + + // For lua's usage of libc: very heavy usage so it pulls in sockets? + setsockopt(0, 0, 0, NULL, 0); + getsockopt(0, 0, 0, NULL, NULL); + + return i; +}
\ No newline at end of file diff --git a/backends/platform/psp/image_viewer.cpp b/backends/platform/psp/image_viewer.cpp new file mode 100644 index 0000000000..26b7f31c97 --- /dev/null +++ b/backends/platform/psp/image_viewer.cpp @@ -0,0 +1,327 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" +#include "common/str.h" +#include "common/stream.h" +#include "common/archive.h" +#include "common/events.h" +#include "common/ptr.h" +#include "gui/message.h" +#include "engines/engine.h" +#include "backends/platform/psp/input.h" +#include "backends/platform/psp/display_manager.h" +#include "backends/platform/psp/display_client.h" +#include "backends/platform/psp/image_viewer.h" +#include "backends/platform/psp/png_loader.h" +#include "backends/platform/psp/thread.h" + +static const char *imageName = "psp_image"; +#define PSP_SCREEN_HEIGHT 272 +#define PSP_SCREEN_WIDTH 480 + +bool ImageViewer::load(int imageNum) { + if (_init) + unload(); + + // build string + char number[8]; + sprintf(number, "%d", imageNum); + Common::String imageNameStr(imageName); + Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png"); + + // search for image file + if (!SearchMan.hasFile(specificImageName)) { + PSP_ERROR("file %s not found\n", specificImageName.c_str()); + return false; + } + + Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName)); + + _buffer = new Buffer(); + _palette = new Palette(); + _renderer = new GuRenderer(); + + assert(_buffer); + assert(_palette); + assert(_renderer); + + // Load a PNG into our buffer and palette. Size it by the actual size of the image + PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize); + + PngLoader::Status status = image.allocate(); // allocate the buffers for the file + + char error[100]; + if (status == PngLoader::BAD_FILE) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } else if (status == PngLoader::OUT_OF_MEMORY) { + sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + // try to load the image file + if (!image.load()) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + + setConstantRendererOptions(); + setFullScreenImageParams(); // prepare renderer for full screen view + + _imageNum = imageNum; // now we can say we displayed this image + _init = true; + + return true; +} + +void ImageViewer::setConstantRendererOptions() { + _renderer->setBuffer(_buffer); + _renderer->setPalette(_palette); + + _renderer->setAlphaBlending(false); + _renderer->setColorTest(false); + _renderer->setUseGlobalScaler(false); + _renderer->setStretch(true); + _renderer->setOffsetInBuffer(0, 0); + _renderer->setDrawWholeBuffer(); +} + +void ImageViewer::unload() { + _init = false; + delete _buffer; + delete _palette; + delete _renderer; + _buffer = 0; + _palette = 0; + _renderer = 0; +} + +void ImageViewer::resetOnEngineDone() { + _imageNum = 0; +} + +void ImageViewer::setVisible(bool visible) { + DEBUG_ENTER_FUNC(); + + if (_visible == visible) + return; + + // from here on, we're making the loader visible + if (visible && g_engine) { // we can only run the image viewer when there's an engine + g_engine->pauseEngine(true); + + load(_imageNum ? _imageNum : 1); // load the 1st image or the current + } + + if (visible && _init) { // we managed to load + _visible = true; + setViewerButtons(true); + + { // so dialog goes out of scope, destroying all allocations + GUI::TimedMessageDialog dialog("Image Viewer", 1000); + dialog.runModal(); + } + + runLoop(); // only listen to viewer events + } else { // we were asked to make invisible or failed to load + _visible = false; + unload(); + setViewerButtons(false); + + if (g_engine && g_engine->isPaused()) + g_engine->pauseEngine(false); + } + setDirty(); +} + +// This is the only way we can truly pause the games +// Sad but true. +void ImageViewer::runLoop() { + while (_visible) { + Common::Event event; + PspThread::delayMillis(30); + _inputHandler->getAllInputs(event); + _displayManager->renderAll(); + } +} + +void ImageViewer::setViewerButtons(bool active) { + _inputHandler->setImageViewerMode(active); +} + +void ImageViewer::loadNextImage() { + if (!load(_imageNum+1)) { // try to load the next image + if (!load(_imageNum)) // we failed, so reload the current image + setVisible(false); // just hide + } + setDirty(); +} + +void ImageViewer::loadLastImage() { + if (_imageNum - 1 > 0) { + if (!load(_imageNum-1)) + if (!load(_imageNum)) + setVisible(false); // we can't even show the old image so hide + } + setDirty(); +} + +void ImageViewer::setFullScreenImageParams() { + // we try to fit the image fullscreen at least in one dimension + uint32 width = _buffer->getSourceWidth(); + uint32 height = _buffer->getSourceHeight(); + + _centerX = PSP_SCREEN_WIDTH / 2.0f; + _centerY = PSP_SCREEN_HEIGHT / 2.0f; + + // see if we fit width wise + if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) { + setZoom(PSP_SCREEN_WIDTH / (float)width); + } else { + setZoom(PSP_SCREEN_HEIGHT / (float)height); + } +} + +void ImageViewer::render() { + if (_init) { + assert(_buffer); + assert(_renderer); + + // move the image slightly. Note that we count on the renderer's timing + switch (_movement) { + case EVENT_MOVE_LEFT: + moveImageX(-_visibleWidth / 100.0f); + break; + case EVENT_MOVE_UP: + moveImageY(-_visibleHeight / 100.0f); + break; + case EVENT_MOVE_RIGHT: + moveImageX(_visibleWidth / 100.0f); + break; + case EVENT_MOVE_DOWN: + moveImageY(_visibleHeight / 100.0f); + break; + default: + break; + } + _renderer->render(); + } +} + +void ImageViewer::modifyZoom(bool up) { + float factor = _zoomFactor; + if (up) + factor += 0.1f; + else // down + factor -= 0.1f; + + setZoom(factor); +} + +void ImageViewer::setZoom(float value) { + if (value <= 0.0f) // don't want 0 or negative zoom + return; + + _zoomFactor = value; + _renderer->setStretchXY(value, value); + setOffsetParams(); +} + +void ImageViewer::moveImageX(float val) { + float newVal = _centerX + val; + + if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4) + return; + _centerX = newVal; + setOffsetParams(); +} + +void ImageViewer::moveImageY(float val) { + float newVal = _centerY + val; + + if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4) + return; + _centerY = newVal; + setOffsetParams(); +} + +// Set the renderer with the proper offset on the screen +// +void ImageViewer::setOffsetParams() { + _visibleWidth = _zoomFactor * _buffer->getSourceWidth(); + _visibleHeight = _zoomFactor * _buffer->getSourceHeight(); + + int offsetX = _centerX - (int)(_visibleWidth * 0.5f); + int offsetY = _centerY - (int)(_visibleHeight * 0.5f); + + _renderer->setOffsetOnScreen(offsetX, offsetY); + setDirty(); +} + +// Handler events coming in from the inputHandler +// +void ImageViewer::handleEvent(uint32 event) { + DEBUG_ENTER_FUNC(); + + switch (event) { + case EVENT_HIDE: + setVisible(false); + break; + case EVENT_SHOW: + setVisible(true); + break; + case EVENT_ZOOM_IN: + modifyZoom(true); + break; + case EVENT_ZOOM_OUT: + modifyZoom(false); + break; + case EVENT_MOVE_LEFT: + case EVENT_MOVE_UP: + case EVENT_MOVE_RIGHT: + case EVENT_MOVE_DOWN: + case EVENT_MOVE_STOP: + _movement = (Event)event; + break; + case EVENT_NEXT_IMAGE: + loadNextImage(); + break; + case EVENT_LAST_IMAGE: + loadLastImage(); + break; + default: + PSP_ERROR("Unknown event %d\n", event); + break; + } +}
\ No newline at end of file diff --git a/backends/platform/psp/image_viewer.h b/backends/platform/psp/image_viewer.h new file mode 100644 index 0000000000..ef8b196dbe --- /dev/null +++ b/backends/platform/psp/image_viewer.h @@ -0,0 +1,105 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +#ifndef PSP_IMAGE_VIEWER_H +#define PSP_IMAGE_VIEWER_H + +class InputHandler; + +class ImageViewer : public DisplayClient { +public: + enum Event { + EVENT_NONE = -1, + EVENT_HIDE = 0, + EVENT_SHOW = 1, + EVENT_ZOOM_IN, + EVENT_ZOOM_OUT, + EVENT_MOVE_LEFT, + EVENT_MOVE_UP, + EVENT_MOVE_RIGHT, + EVENT_MOVE_DOWN, + EVENT_MOVE_STOP, + EVENT_NEXT_IMAGE, + EVENT_LAST_IMAGE, + }; + +private: + Buffer *_buffer; + Palette *_palette; + GuRenderer *_renderer; + bool _visible; + bool _dirty; + bool _init; + uint32 _imageNum; // current image number + float _zoomFactor; // how much we're zooming in/out on the image + float _visibleHeight, _visibleWidth; + float _centerX, _centerY; + Event _movement; + + InputHandler *_inputHandler; + DisplayManager *_displayManager; + + void setFullScreenImageParams(); + void loadNextImage(); + void loadLastImage(); + void setViewerButtons(bool active); + void setConstantRendererOptions(); + void moveImageX(float val); + void moveImageY(float val); + bool load(int imageNum); + void unload(); + void runLoop(); // to get total pausing we have to do our own loop + + void setZoom(float value); + void setOffsetParams(); + void modifyZoom(bool up); // up or down + void setVisible(bool visible); + +public: + + ImageViewer() : _buffer(0), _palette(0), _visible(false), + _dirty(false), _init(false), _imageNum(0), + _zoomFactor(0.0f), _visibleHeight(0.0f), _visibleWidth(0.0f), + _centerX(0.0f), _centerY(0.0f), _movement(EVENT_MOVE_STOP), + _inputHandler(0), _displayManager(0) {} + ~ImageViewer() { unload(); } // deallocate images + bool load(); + void render(); + bool isVisible() { return _visible; } + bool isDirty() { return _dirty; } + void setDirty() { _dirty = true; } + void setClean() { if (!_visible) // otherwise we want to keep rendering + _dirty = false; + } + void resetOnEngineDone(); + + void handleEvent(uint32 event); + + // pointer setters + void setInputHandler(InputHandler *inputHandler) { _inputHandler = inputHandler; } + void setDisplayManager(DisplayManager *displayManager) { _displayManager = displayManager; } +}; + +#endif /* PSP_IMAGE_VIEWER_H */
\ No newline at end of file diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp index 2a91ce455a..665f41504f 100644 --- a/backends/platform/psp/input.cpp +++ b/backends/platform/psp/input.cpp @@ -23,238 +23,274 @@ * */ -// 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), _combosEnabled(true) { + 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); + _button[BTN_SELECT][SHIFTED].setPspEvent(PSP_EVENT_IMAGE_VIEWER, 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; + if (_combosEnabled) + 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 +317,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 +354,220 @@ 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(); + _nub.init(); +} + +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;*/ + case PSP_EVENT_IMAGE_VIEWER: + _imageViewer->handleEvent(pspEvent.data); + break; + case PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS: + setImageViewerMode(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(); +}*/ + +void InputHandler::setImageViewerMode(bool active) { + if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet + PSP_DEBUG_PRINT("postponing image viewer on event\n"); + _pendingPspEvent.type = PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS; // queue it to be done later + _pendingPspEvent.data = active; + } else if (active) { + _nub.setDpadMode(true); + _buttonPad.enableCombos(false); // disable combos + setButtonsForImageViewer(); + } else { // deactivate + _nub.setDpadMode(false); + _nub.init(); + _buttonPad.enableCombos(true); // re-enable combos + _buttonPad.initButtons(); + } +} + +void InputHandler::setButtonsForImageViewer() { + DEBUG_ENTER_FUNC(); + + // Dpad + _buttonPad.clearButtons(); + _buttonPad.getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_IN, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_OUT, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_LAST_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_NEXT_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_START, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_SELECT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + + //Nub + _nub.getPad().clearButtons(); + _nub.getPad().getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_UP, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_DOWN, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_LEFT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_RIGHT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); +} + + diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h index cd686d9e02..9a1ab6faab 100644 --- a/backends/platform/psp/input.h +++ b/backends/platform/psp/input.h @@ -28,36 +28,175 @@ #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 "backends/platform/psp/image_viewer.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_IMAGE_VIEWER, + PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS, + 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 + bool _combosEnabled; // can we do combos + static const uint32 _buttonMap[]; // maps the buttons to their values + + void initButtonsNormalMode(); + void initButtonsLolMode(); + void modifyButtonsForCombos(SceCtrlData &pad); + +public: + ButtonPad(); + void initButtons(); // set the buttons to the mode that's selected + void clearButtons(); // empty the buttons of all events + + 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 enableCombos(bool value) { _combosEnabled = value; } + Button &getButton(ButtonType type, ShiftMode mode) { return _button[type][mode]; } +}; + +class Nub { +private: + Cursor *_cursor; // to enable changing/getting cursor position + + ShiftMode _shifted; + bool _dpadMode; + + ButtonPad _buttonPad; // private buttonpad for dpad mode + + int32 modifyNubAxisMotion(int32 input); + void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data +public: + Nub() : _shifted(UNSHIFTED), _dpadMode(false) { } + void init() { _buttonPad.initButtons(); } + + void setCursor(Cursor *cursor) { _cursor = cursor; } + + // setters + void setDpadMode(bool active) { _dpadMode = active; } + void setShifted(ShiftMode shifted) { _shifted = shifted; } + + // getters + bool isButtonDown(); + bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); + ButtonPad &getPad() { return _buttonPad; } +}; + class InputHandler { public: - InputHandler() : _cursor(0), _keyboard(0), _prevButtons(0), _lastPadCheckTime(0), _buttonsChanged(0), _dpadX(0), _dpadY(0) {} + InputHandler() : _keyboard(0), _cursor(0), _imageViewer(0), _padMode(PAD_MODE_NORMAL), + _lastPadCheckTime(0) {} + // pointer setters + void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } + void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } void init(); bool getAllInputs(Common::Event &event); - void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } - void setCursor(Cursor *cursor) { _cursor = cursor; } + void setImageViewerMode(bool active); private: - Cursor *_cursor; + Nub _nub; + ButtonPad _buttonPad; + + // Pointers to relevant other classes PSPKeyboard *_keyboard; - uint32 _prevButtons; + Cursor *_cursor; + ImageViewer *_imageViewer; + + 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(); + void setButtonsForImageViewer(); }; #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 a854ec1252..e3eac153dd 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -16,7 +16,10 @@ MODULE_OBJS := powerman.o \ thread.o \ rtc.o \ mp3.o \ - tests.o + png_loader.o \ + image_viewer.o \ + tests.o \ + dummy.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp index 98e8a0404b..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 */ @@ -77,7 +77,7 @@ enum { bool Mp3PspStream::initDecoder() { DEBUG_ENTER_FUNC(); - + if (_decoderInit) { PSP_ERROR("Already initialized!"); return true; @@ -97,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; @@ -114,10 +114,10 @@ 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){ // TODO: how do we unload? /* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) || @@ -130,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; } @@ -176,26 +176,27 @@ 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 - + _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); - + deinitStream(); _state = MP3_STATE_INIT; @@ -221,7 +222,7 @@ int Mp3PspStream::initStream() { // Read the first few sample bytes into the buffer readMP3DataIntoBuffer(); - + return true; } @@ -229,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); @@ -244,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 @@ -276,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(); @@ -295,17 +296,17 @@ void Mp3PspStream::decodeMP3Data() { if (_state == MP3_STATE_EOS) return; - + findValidHeader(); // seach for next valid header 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; - - updatePcmLength(); // Retrieve the number of PCM samples. + + 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 @@ -315,7 +316,7 @@ void Mp3PspStream::decodeMP3Data() { _codecParams[8] = (unsigned long)_pcmSamples; _codecParams[7] = frame_size; _codecParams[9] = _pcmLength * 2; // x2 for stereo, though this one's not so important - + // debug #ifdef PRINT_BUFFERS PSP_DEBUG_PRINT("mp3 frame:\n"); @@ -415,10 +416,13 @@ 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(); } // Skip ahead @@ -469,38 +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 } - + 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
\ No newline at end of file +} // End of namespace Audio diff --git a/backends/platform/psp/mp3.h b/backends/platform/psp/mp3.h index 983f4cb7f4..1d2fe5ec2f 100644 --- a/backends/platform/psp/mp3.h +++ b/backends/platform/psp/mp3.h @@ -53,29 +53,30 @@ protected: Common::SeekableReadStream *_inStream; DisposeAfterUse::Flag _disposeAfterUse; - + 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(); @@ -84,19 +85,19 @@ protected: 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 @@ -104,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..40c074ae00 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 @@ -76,12 +76,18 @@ void OSystem_PSP::initBackend() { _displayManager.setScreen(&_screen); _displayManager.setOverlay(&_overlay); _displayManager.setKeyboard(&_keyboard); + _displayManager.setImageViewer(&_imageViewer); _displayManager.init(); // Set pointers for input handler _inputHandler.setCursor(&_cursor); _inputHandler.setKeyboard(&_keyboard); + _inputHandler.setImageViewer(&_imageViewer); _inputHandler.init(); + + // Set pointers for image viewer + _imageViewer.setInputHandler(&_inputHandler); + _imageViewer.setDisplayManager(&_displayManager); _savefile = new PSPSaveFileManager; @@ -97,6 +103,12 @@ void OSystem_PSP::initBackend() { OSystem::initBackend(); } +// Let's us know an engine +void OSystem_PSP::engineDone() { + // for now, all we need is to reset the image number on the viewer + _imageViewer.resetOnEngineDone(); +} + bool OSystem_PSP::hasFeature(Feature f) { return (f == kFeatureOverlaySupportsAlpha || f == kFeatureCursorHasPalette); } @@ -148,7 +160,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 +179,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 +187,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 +195,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 +231,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 +239,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 +247,7 @@ void OSystem_PSP::hideOverlay() { void OSystem_PSP::clearOverlay() { DEBUG_ENTER_FUNC(); - _pendingUpdate = false; + _pendingUpdate = false; _overlay.clearBuffer(); } @@ -246,7 +258,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 +278,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 +288,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 +322,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/osys_psp.h b/backends/platform/psp/osys_psp.h index 5721296c94..52b8f4e887 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -32,10 +32,12 @@ #include "sound/mixer_intern.h" #include "backends/base-backend.h" #include "backends/fs/psp/psp-fs-factory.h" + #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #include "backends/platform/psp/display_manager.h" #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" @@ -60,6 +62,7 @@ private: InputHandler _inputHandler; PspAudio _audio; PspTimer _pspTimer; + ImageViewer _imageViewer; public: OSystem_PSP() : _savefile(0), _mixer(0), _timer(0), _pendingUpdate(false), _pendingUpdateCounter(0) {} @@ -146,6 +149,7 @@ public: Common::SaveFileManager *getSavefileManager() { return _savefile; } FilesystemFactory *getFilesystemFactory() { return &PSPFilesystemFactory::instance(); } void getTimeAndDate(TimeDate &t) const; + virtual void engineDone(); void quit(); diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp new file mode 100644 index 0000000000..08f370f36d --- /dev/null +++ b/backends/platform/psp/png_loader.cpp @@ -0,0 +1,210 @@ +/* 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$ + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#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" + +//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +//#define __PSP_DEBUG_PRINT__ /* For debug printouts */ + +#include "backends/platform/psp/trace.h" + +PngLoader::Status PngLoader::allocate() { + DEBUG_ENTER_FUNC(); + + if (!findImageDimensions()) { + PSP_ERROR("failed to get image dimensions\n"); + return BAD_FILE; + } + + _buffer->setSize(_width, _height, _sizeBy); + + uint32 bitsPerPixel = _bitDepth * _channels; + + if (_paletteSize) { // 8 or 4-bit image + if (bitsPerPixel == 4) { + _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit); + _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); + _paletteSize = 16; // round up + } else if (bitsPerPixel == 8) { // 8-bit image + _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit); + _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); + _paletteSize = 256; // round up + } else { + PSP_ERROR("too many bits per pixel[%d] for a palette\n", bitsPerPixel); + 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 (_buffer->hasPalette() && !_palette->allocate()) { + PSP_ERROR("failed to allocate palette\n"); + return OUT_OF_MEMORY; + } + return OK; +} + +bool PngLoader::load() { + DEBUG_ENTER_FUNC(); + // 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() { + DEBUG_ENTER_FUNC(); + _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); + _channels = png_get_channels(_pngPtr, _infoPtr); + + 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(); + + bool status = basicImageLoad(); + + PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d], channels[%d], rowBytes[%d]\n", _width, _height, _paletteSize, _bitDepth, _channels, _infoPtr->rowbytes); + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); + return status; +} + +// +// Load a texture from a png image +// +bool PngLoader::loadImageIntoBuffer() { + DEBUG_ENTER_FUNC(); + + if (!basicImageLoad()) { + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); + return false; + } + png_set_strip_16(_pngPtr); // Strip off 16 bit channels in case they occur + + if (_paletteSize) { + // Copy the palette + png_colorp srcPal = _infoPtr->palette; + for (int i = 0; i < _infoPtr->num_palette; 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_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha if none exists + } + + uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr); + + // there seems to be a bug in libpng where it doesn't increase the rowbytes or the + // channel even after we add the alpha channel + if (_channels == 3 && (rowBytes / _width) == 3) { + _channels = 4; + rowBytes = _width * _channels; + } + + PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels); + + unsigned char *line = (unsigned char*) malloc(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, 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..4119bfef2b --- /dev/null +++ b/backends/platform/psp/png_loader.h @@ -0,0 +1,74 @@ +/* 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; + Buffer::HowToSize _sizeBy; + + // PNG lib values + int _bitDepth; + png_structp _pngPtr; + png_infop _infoPtr; + int _colorType; + uint32 _channels; + +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), _channels(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.spec b/backends/platform/psp/psp.spec index ac325b7fd6..7177413373 100644 --- a/backends/platform/psp/psp.spec +++ b/backends/platform/psp/psp.spec @@ -1,3 +1,3 @@ %rename lib old_lib *lib: -%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel +%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel -lpspnet_inet diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index 41cf451323..019f6c12d1 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -103,7 +103,7 @@ int exit_callback(void) { #ifdef ENABLE_PROFILING gprof_cleanup(); -#endif +#endif sceKernelExitGame(); return 0; @@ -170,12 +170,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..f210726692 100644 --- a/backends/platform/psp/pspkeyboard.cpp +++ b/backends/platform/psp/pspkeyboard.cpp @@ -23,19 +23,23 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + //#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" @@ -77,9 +81,9 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = { }, { //numbers { K('1'), K('2'), K('3'), K('4'), K(0), K(0) }, - { C(F5), C(F8), C(F7), C(F6), C(F9), C(F10) }, + { C(F5), C(F6), C(F7), C(F8), C(F9), C(F10) }, { K('5'), K('6'), K('7'), K('8'), K(0), K(0) }, - { C(F1), C(F4), C(F3), C(F2), K(0), K(0) }, + { C(F1), C(F2), C(F3), C(F4), K(0), K(0) }, { K('\b'), K('0'), K(' '), K('9'), K(0), K(0) } }, { //symbols @@ -91,16 +95,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 +275,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 +301,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); - } + PngLoader image(file, _buffers[i], _palettes[i]); - _buffers[i].allocate(); - _palettes[i].allocate(); - - // 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 +337,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 +351,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 +374,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 +388,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 +408,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 +424,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 f65c13ae83..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> @@ -49,16 +49,16 @@ #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: @@ -67,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 @@ -95,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); @@ -119,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); } @@ -128,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); } /* @@ -158,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); @@ -170,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); } @@ -246,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; } @@ -257,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); } @@ -266,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); } @@ -280,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(); @@ -334,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); } @@ -346,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); } @@ -397,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); @@ -415,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); @@ -429,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); @@ -437,7 +437,7 @@ void PspSpeedTests::fastCopySpeed() { fastCopyDifferentSizes(bufferDst, bufferSrc+1); fastCopyDifferentSizes(bufferDst+1, bufferSrc); - + free(bufferSrc32); free(bufferDst32); } @@ -453,11 +453,11 @@ 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"); @@ -465,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); @@ -491,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); @@ -509,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); @@ -529,16 +529,16 @@ 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 @@ -549,23 +549,23 @@ bool PspUnitTests::testFileSystem() { 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); @@ -576,9 +576,9 @@ bool PspUnitTests::testFileSystem() { 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); @@ -595,22 +595,22 @@ bool PspUnitTests::testFileSystem() { 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]; @@ -619,96 +619,96 @@ bool PspUnitTests::testFileSystem() { while (rdStream->read(index, 100) == 100) { index += 100; } - + if (!rdStream->eos()) { PSP_ERROR("didn't find EOS at end of stream\n"); - return false; + 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; @@ -718,18 +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(); unitTests.testFileSystem(); -#endif -} +#endif +} -#endif /* (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) */
\ No newline at end of file +#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 e757c2f575..3e1303a4e6 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 44394af40a..1ca6ef5c42 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 */ |
