From 279158a0103601908cb2329dc42f31938959dbd8 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sat, 4 May 2013 00:32:25 +1000 Subject: [PATCH 01/16] Buildfix (Harmattan and Blackberry): stdlib is required for abs(int). --- GPU/GLES/TextureScaler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/GPU/GLES/TextureScaler.cpp b/GPU/GLES/TextureScaler.cpp index 13e6b0174e..dcdd414e96 100644 --- a/GPU/GLES/TextureScaler.cpp +++ b/GPU/GLES/TextureScaler.cpp @@ -23,6 +23,7 @@ #include "Common/CommonFuncs.h" #include "Common/ThreadPools.h" #include "ext/xbrz/xbrz.h" +#include #ifdef __SYMBIAN32__ #define p From ba71ac43cbbaeb5afa3c030156effe0bbccbe795 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 3 May 2013 18:22:48 +0200 Subject: [PATCH 02/16] Restore BOM in UI/MenuScreens.cpp Conflicts: UI/MenuScreens.cpp --- UI/MenuScreens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MenuScreens.cpp b/UI/MenuScreens.cpp index 8864a311d4..26dc206aea 100644 --- a/UI/MenuScreens.cpp +++ b/UI/MenuScreens.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012- PPSSPP Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by From e23b22678945790534b0f4e4f27c8ff287357f0e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 3 May 2013 18:32:02 +0200 Subject: [PATCH 03/16] Update README.md to have the right build instructions for Android. --- README.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4d471b543e..527dc0b390 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,39 @@ in order to get the "native" library. Now, the actual building: +Building for Windows +--------------------- + +Use Visual Studio 2010+, Visual C++ Express is fine. Open the solution and just build, +it'll work. You may just need to set up a path or two to the Windows SDK (which includes the DX SDK) +nowadays. + + +Building for Android +-------------------- + +Install the Android SDK and NDK. + +To build the native C/C++ part, from a shell or command prompt, run: + + ./ab.sh + +or, on Windows: + + ab.cmd + +in android/. You may need to tweak the paths in the ab file. + +Then just open the project in Eclipse and run on your device. When you make changes to +the native code, you may have to refresh or add a few spaces to PPSSPPActivity.java for +Eclipse to rebuild the APK when you run it on your device the next time. + +There's an alternate method of building for Android using CMake below. + + +Other platforms +--------------- + PPSSPP currently uses CMake for its build system. In order to build for most systems, create a `build` directory and run: @@ -75,10 +108,10 @@ on homebrew. Just follow the basic build instructions afterwards. Currently the user interface is identical to Android's, operated with the mouse. A Qt-based interface is planned. -Building for Android --------------------- +Building for Android using CMake (not recommended, see above) +------------------------------------------------------------- -To build for android, first you must set the ANDROID\_NDK environment +To build for Android using CMake, first you must set the ANDROID\_NDK environment variable to point to the path of your NDK install. This is done on windows cmd with `set ANDROID_NDK=X:\...`, on bourne shells with `export ANDROID_NDK=/path/to/ndk`, and on C shells with From 25ab317e9d1b4019f2e580b89b4db7a64ae2d25e Mon Sep 17 00:00:00 2001 From: raven02 Date: Sat, 4 May 2013 02:36:16 +0800 Subject: [PATCH 04/16] Add Deposterize option to Android/iOS build --- UI/MenuScreens.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/UI/MenuScreens.cpp b/UI/MenuScreens.cpp index 26dc206aea..f41025e804 100644 --- a/UI/MenuScreens.cpp +++ b/UI/MenuScreens.cpp @@ -740,8 +740,8 @@ void GraphicsScreenP2::render() { if (g_Config.iAnisotropyLevel == 0) g_Config.iAnisotropyLevel = 2; - ui_draw2d.DrawText(UBUNTU24, gs->T("Level :"), x + 60, y += stride - 5, 0xFFFFFFFF, ALIGN_LEFT); - HLinear hlinear1(x + 160 , y + 5, 20); + ui_draw2d.DrawText(UBUNTU24, gs->T("Level :"), x + 60, y += stride, 0xFFFFFFFF, ALIGN_LEFT); + HLinear hlinear1(x + 160 , y, 20); if (UIButton(GEN_ID, hlinear1, 45, 0, "2x", ALIGN_LEFT)) g_Config.iAnisotropyLevel = 2; if (UIButton(GEN_ID, hlinear1, 45, 0, "4x", ALIGN_LEFT)) @@ -755,23 +755,20 @@ void GraphicsScreenP2::render() { } bool TexScaling = g_Config.iTexScalingLevel > 1; - UICheckBox(GEN_ID, x, y += stride + 20, gs->T("xBRZ Texture Scaling"), ALIGN_TOPLEFT, &TexScaling); + UICheckBox(GEN_ID, x, y += stride + 15, gs->T("xBRZ Texture Scaling"), ALIGN_TOPLEFT, &TexScaling); if (TexScaling) { if (g_Config.iTexScalingLevel <= 1) g_Config.iTexScalingLevel = 2; - - ui_draw2d.DrawText(UBUNTU24, gs->T("Level :"), x + 60, y += stride + 5, 0xFFFFFFFF, ALIGN_LEFT); - HLinear hlinear1(x + 160 , y - 5, 20); + UICheckBox(GEN_ID, x + 60, y += stride, gs->T("Deposterize"), ALIGN_LEFT, &g_Config.bTexDeposterize); + bool tst = g_Config.iTexScalingType == 1; + UICheckBox(GEN_ID, x + 60, y += stride, gs->T("Hybrid"), ALIGN_LEFT, &tst); + g_Config.iTexScalingType = tst ? 1 : 0; + ui_draw2d.DrawText(UBUNTU24, gs->T("Level :"), x + 60, y += stride, 0xFFFFFFFF, ALIGN_LEFT); + HLinear hlinear1(x + 160 , y, 20); if (UIButton(GEN_ID, hlinear1, 45, 0, "2x", ALIGN_LEFT)) g_Config.iTexScalingLevel = 2; if (UIButton(GEN_ID, hlinear1, 45, 0, "3x", ALIGN_LEFT)) g_Config.iTexScalingLevel = 3; - HLinear hlinear2(x + 160 , y + 60, 20); - ui_draw2d.DrawText(UBUNTU24, gs->T("Type :"), x + 60, y += stride + 20, 0xFFFFFFFF, ALIGN_LEFT); - if (UIButton(GEN_ID, hlinear2, 90, 0, "xBRZ", ALIGN_LEFT)) - g_Config.iTexScalingType = 0; - if (UIButton(GEN_ID, hlinear2, 100, 0, "Hybrid", ALIGN_LEFT)) - g_Config.iTexScalingType = 1; } else { g_Config.iTexScalingLevel = 1; } From 4373c1170db59b2b095f5f9f41ac03207cb0d54f Mon Sep 17 00:00:00 2001 From: raven02 Date: Sat, 4 May 2013 16:00:00 +0800 Subject: [PATCH 05/16] Basic Atrac3 Support in sceAtrac using ffmpeg --- Core/HLE/sceAtrac.cpp | 824 ++++++++++++++++++++++++++++++++---------- 1 file changed, 624 insertions(+), 200 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d14deb2951..36af9dbb14 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -31,22 +31,35 @@ #define ATRAC_ERROR_ALL_DATA_DECODED 0x80630024 #define ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED 0x80630022 #define ATRAC_ERROR_INCORRECT_READ_SIZE 0x80630013 - -#define FMT_CHUNK_MAGIC 0x20746D66 -#define DATA_CHUNK_MAGIC 0x61746164 -#define SMPL_CHUNK_MAGIC 0x6C706D73 -#define FACT_CHUNK_MAGIC 0x74636166 +#define ATRAC_ERROR_UNSET_PARAM 0x80630021 +#define ATRAC_ERROR_NO_ATRACID 0x80630003 +#define ATRAC_ERROR_BAD_CODECTYPE 0x80630004 +#define ATRAC_ERROR_ADD_DATA_IS_TOO_BIG 0x80630018 #define AT3_MAGIC 0x0270 #define AT3_PLUS_MAGIC 0xFFFE -#define RIFF_MAGIC 0x46464952 -#define WAVE_MAGIC 0x45564157 - #define PSP_MODE_AT_3_PLUS 0x00001000 #define PSP_MODE_AT_3 0x00001001 +const int FMT_CHUNK_MAGIC = 0x20746D66; +const int DATA_CHUNK_MAGIC = 0x61746164; +const int SMPL_CHUNK_MAGIC = 0x6C706D73; +const int FACT_CHUNK_MAGIC = 0x74636166; + +const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1; +const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2; +const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3; + const u32 ATRAC_MAX_SAMPLES = 1024; +#ifdef USE_FFMPEG +extern "C" { +#include +#include +#include +} +#endif // USE_FFMPEG + struct InputBuffer { u32 addr; u32 size; @@ -57,6 +70,9 @@ struct InputBuffer { u32 fileoffset; }; +struct Atrac; +int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize); + struct AtracLoopInfo { int cuePointID; int type; @@ -67,54 +83,181 @@ struct AtracLoopInfo { }; struct Atrac { - Atrac() : decodePos(0), decodeEnd(0), loopNum(0), - atracChannels(2), atracBitrate(64), atracBytesPerFrame(0x0230), atracSampleRate(0xAC44), - currentSample(0), endSample(-1), loopinfoNum(0), firstSampleoffset(0), - loopStartSample(0), loopEndSample(-1) { + Atrac() : decodePos(0), decodeEnd(0), loopNum(0), atracChannels(2), + atracBitrate(64), atracBytesPerFrame(0), atracBufSize(0), currentSample(0), + endSample(-1), loopinfoNum(0), firstSampleoffset(0),data_buf(0), + atracOutputChannels(2), atracID(-1) { memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(second)); +#ifdef USE_FFMPEG + pFormatCtx = 0; + pAVIOCtx = 0; + pCodecCtx = 0; + pSwrCtx = 0; + pFrame = 0; +#endif // USE_FFMPEG } + + ~Atrac() { +#ifdef USE_FFMPEG + ReleaseFFMPEGContext(); +#endif // USE_FFMPEG + if (data_buf) delete [] data_buf; + } + void DoState(PointerWrap &p) { + p.Do(atracChannels); + p.Do(atracOutputChannels); + + if (atracID == -1) { + // loading state + p.Do(atracID); + p.Do(first); + p.Do(atracBufSize); + p.Do(codeType); + u32 data_buf_value; + p.Do(data_buf_value); + if (data_buf_value) { + data_buf = new u8[first.filesize]; + p.DoArray(data_buf, first.filesize); + } + InputBuffer temp = first; + if (first.addr) { + int size = std::min(first.size, atracBufSize); + first.size = size; + if (data_buf) + Memory::Memcpy(first.addr, data_buf, size); + u8* temp_buf = data_buf; + data_buf = 0; + _AtracSetData(this, first.addr, atracBufSize); + // restore the state + first = temp; + if (data_buf) + delete [] data_buf; + data_buf = temp_buf; + } + } + else { + // saving state + p.Do(atracID); + p.Do(first); + p.Do(atracBufSize); + p.Do(codeType); + u32 data_buf_value = (u32)data_buf; + p.Do(data_buf_value); + if (data_buf) + p.DoArray(data_buf, first.filesize); + } + p.Do(second); + p.Do(decodePos); p.Do(decodeEnd); - p.Do(atracChannels); + p.Do(atracBitrate); - p.Do(atracSampleRate); p.Do(atracBytesPerFrame); - p.Do(loopStartSample); - p.Do(loopEndSample); - p.Do(loopNum); - p.Do(loopinfoNum); + p.Do(currentSample); p.Do(endSample); p.Do(firstSampleoffset); - p.Do(first); - p.Do(second); + + p.Do(loopinfo); + p.Do(loopinfoNum); + + p.Do(loopStartSample); + p.Do(loopEndSample); + p.Do(loopNum); + p.DoMarker("Atrac"); } void Analyze(); + u32 getDecodePosBySample(int sample) { + return (u32)(firstSampleoffset + sample / ATRAC_MAX_SAMPLES * atracBytesPerFrame ); + } + int getRemainFrames() { + // many games request to add atrac data when remainFrames = 0 + // However, some other games request to add atrac data + // when remainFrames = PSP_ATRAC_ALLDATA_IS_ON_MEMORY . + // Still need to find out how getRemainFrames() should work. + + int remainFrame; + if (first.fileoffset >= first.filesize || currentSample >= endSample) + remainFrame = PSP_ATRAC_ALLDATA_IS_ON_MEMORY; + else if (decodePos >= first.fileoffset - atracBytesPerFrame ) { + // require more data + remainFrame = PSP_ATRAC_ALLDATA_IS_ON_MEMORY; + } else { + // This is the correct one + //remainFrame = (first.size - decodePos) / atracBytesPerFrame; + + // Try to load all file data immediately + remainFrame = 0; + } + return remainFrame; + } + + int atracID; + u8* data_buf; u32 decodePos; u32 decodeEnd; + u16 atracChannels; + u16 atracOutputChannels; u32 atracBitrate; u16 atracBytesPerFrame; - u32 atracSampleRate; - u32 codeType; + u32 atracBufSize; + + int currentSample; + int endSample; + // Offset of the first sample in the input buffer + int firstSampleoffset; + + std::vector loopinfo; + int loopinfoNum; int loopStartSample; int loopEndSample; int loopNum; - int loopinfoNum; - int currentSample; - int endSample; - int firstSampleoffset; - std::vector loopinfo; + u32 codeType; InputBuffer first; InputBuffer second; + +#ifdef USE_FFMPEG + AVFormatContext *pFormatCtx; + AVIOContext *pAVIOCtx; + AVCodecContext *pCodecCtx; + SwrContext *pSwrCtx; + AVFrame *pFrame; + int audio_stream_index; + void ReleaseFFMPEGContext() { + if (pFrame) + av_free(pFrame); + if (pAVIOCtx && pAVIOCtx->buffer) + av_free(pAVIOCtx->buffer); + if (pAVIOCtx) + av_free(pAVIOCtx); + if (pSwrCtx) + swr_free(&pSwrCtx); + if (pCodecCtx) + avcodec_close(pCodecCtx); + if (pFormatCtx) + avformat_close_input(&pFormatCtx); + pFormatCtx = 0; + pAVIOCtx = 0; + pCodecCtx = 0; + pSwrCtx = 0; + pFrame = 0; + } + + void SeekToSample(int sample) { + s64 seek_pos = (s64)sample; + av_seek_frame(pFormatCtx, audio_stream_index, seek_pos, 0); + } +#endif // USE_FFMPEG + }; std::map atracMap; @@ -122,9 +265,16 @@ u8 nextAtracID; void __AtracInit() { nextAtracID = 0; +#ifdef USE_FFMPEG + avcodec_register_all(); + av_register_all(); +#endif // USE_FFMPEG } void __AtracDoState(PointerWrap &p) { +#ifdef USE_FFMPEG + p.Do(Memory::lastestAccessFile); +#endif // _USE_FFMPEG p.Do(atracMap); p.Do(nextAtracID); @@ -148,6 +298,7 @@ Atrac *getAtrac(int atracID) { int createAtrac(Atrac *atrac) { int id = nextAtracID++; atracMap[id] = atrac; + atrac->atracID = id; return id; } @@ -158,8 +309,8 @@ void deleteAtrac(int atracID) { } } -int getCodecType(const u32 addr) { - int at3magic = Memory::Read_U16(addr + 20); +int getCodecType(int addr) { + int at3magic = Memory::Read_U16(addr+20); if (at3magic == AT3_MAGIC) { return PSP_MODE_AT_3; } else if (at3magic == AT3_PLUS_MAGIC) { @@ -170,31 +321,30 @@ int getCodecType(const u32 addr) { void Atrac::Analyze() { + // reset some values currentSample = 0; endSample = -1; loopNum = 0; loopinfoNum = 0; + loopinfo.clear(); loopStartSample = -1; loopEndSample = -1; decodePos = 0; - if (first.size < 0x100) { + if (first.size < 0x100) + { ERROR_LOG(HLE, "Atrac buffer very small: %d", first.size); return; } - - if (!Memory::IsValidAddress(first.addr)) { + if (!Memory::IsValidAddress(first.addr)) + { WARN_LOG(HLE, "Atrac buffer at invalid address: %08x-%08x", first.addr, first.size); return; } - int RIFFMagic = Memory::Read_U32(first.addr); - int WAVEMagic = Memory::Read_U32(first.addr + 8); - if (RIFFMagic != RIFF_MAGIC || WAVEMagic != WAVE_MAGIC) { - ERROR_LOG(HLE, "Not a RIFF or WAVE format: %08x-%08x", RIFFMagic, WAVEMagic); - return; - } + // TODO: Validate stuff. + // RIFF size excluding chunk header. first.filesize = Memory::Read_U32(first.addr + 4) + 8; u32 offset = 12; @@ -208,51 +358,62 @@ void Atrac::Analyze() offset += 8; if (chunkSize > first.filesize - offset) break; - switch (chunkMagic) { - case FMT_CHUNK_MAGIC: { - if (chunkSize >= 16) { - atracChannels = Memory::Read_U16(first.addr + offset + 2); - atracSampleRate = Memory::Read_U32(first.addr + offset + 4); - atracBitrate = Memory::Read_U32(first.addr + offset + 8); - atracBytesPerFrame = Memory::Read_U16(first.addr + offset + 12); - } + case FMT_CHUNK_MAGIC: + { + if (chunkSize >= 16) { + int codeMagic = Memory::Read_U16(first.addr + offset); + if (codeMagic == AT3_MAGIC) + codeType = PSP_MODE_AT_3; + else if (codeMagic == AT3_PLUS_MAGIC) + codeType = PSP_MODE_AT_3_PLUS; + else + codeType = 0; + atracChannels = Memory::Read_U16(first.addr + offset + 2); + // int atracSamplerate = Memory::Read_U32(first.addr + offset + 4); ;Should always be 44100Hz + int avgBytesPerSec = Memory::Read_U32(first.addr + offset + 8); + atracBitrate = avgBytesPerSec * 8; + atracBytesPerFrame = Memory::Read_U16(first.addr + offset + 12); } - break; - case FACT_CHUNK_MAGIC: { - if (chunkSize >= 8) { - endSample = Memory::Read_U32(first.addr + offset); - atracSampleoffset = Memory::Read_U32(first.addr + offset + 4); - } + } + break; + case FACT_CHUNK_MAGIC: + { + if (chunkSize >= 8) { + endSample = Memory::Read_U32(first.addr + offset); + atracSampleoffset = Memory::Read_U32(first.addr + offset + 4); } - break; - case SMPL_CHUNK_MAGIC: { - if (chunkSize >= 36) { - int checkNumLoops = Memory::Read_U32(first.addr + offset + 28); - if (chunkSize >= 36 + checkNumLoops * 24) { - loopinfoNum = checkNumLoops; - loopinfo.resize(loopinfoNum); - u32 loopinfoAddr = first.addr + offset + 36; - for (int i = 0; i < loopinfoNum; i++, loopinfoAddr += 24) { - loopinfo[i].cuePointID = Memory::Read_U32(loopinfoAddr); - loopinfo[i].type = Memory::Read_U32(loopinfoAddr + 4); - loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8) - atracSampleoffset; - loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12) - atracSampleoffset; - loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16); - loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20); + } + break; + case SMPL_CHUNK_MAGIC: + { + if (chunkSize < 36) + break; + int checkNumLoops = Memory::Read_U32(first.addr + offset + 28); + if (chunkSize >= 36 + checkNumLoops * 24) { + loopinfoNum = checkNumLoops; + loopinfo.resize(loopinfoNum); + u32 loopinfoAddr = first.addr + offset + 36; + for (int i = 0; i < loopinfoNum; i++, loopinfoAddr += 24) { + loopinfo[i].cuePointID = Memory::Read_U32(loopinfoAddr); + loopinfo[i].type = Memory::Read_U32(loopinfoAddr + 4); + loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8) - atracSampleoffset; + loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12) - atracSampleoffset; + loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16); + loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20); - if (loopinfo[i].endSample > endSample) - loopinfo[i].endSample = endSample; - } - } - } + if (loopinfo[i].endSample > endSample) + loopinfo[i].endSample = endSample; + } } - break; - case DATA_CHUNK_MAGIC: { - bfoundData = true; - firstSampleoffset = offset; - } - break; + } + break; + case DATA_CHUNK_MAGIC: + { + bfoundData = true; + firstSampleoffset = offset; + } + break; } offset += chunkSize; } @@ -272,30 +433,55 @@ void Atrac::Analyze() u32 sceAtracGetAtracID(int codecType) { - ERROR_LOG(HLE, "FAKE sceAtracGetAtracID(%i)", codecType); - return createAtrac(new Atrac); + INFO_LOG(HLE, "sceAtracGetAtracID(%i)", codecType); + if (codecType < 0x1000 || codecType > 0x1001) + return ATRAC_ERROR_BAD_CODECTYPE; + + int atracID = createAtrac(new Atrac); + Atrac *atrac = getAtrac(atracID); + if (!atrac) + return ATRAC_ERROR_NO_ATRACID; + atrac->codeType = codecType; + return atracID; } u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { - ERROR_LOG(HLE, "UNIMPL sceAtracAddStreamData(%i, %08x)", atracID, bytesToAdd); + INFO_LOG(HLE, "sceAtracAddStreamData(%i, %08x)", atracID, bytesToAdd); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; + return 0; } // TODO + if (bytesToAdd > atrac->first.writableBytes) + return ATRAC_ERROR_ADD_DATA_IS_TOO_BIG; + + if (atrac->data_buf && (bytesToAdd > 0)) { + int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset); + Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, atrac->first.addr, addbytes); +#ifdef _USE_DSHOW_ + if (atrac->first.fileoffset + addbytes >= atrac->first.filesize) + addAtrac3Audio(atrac->data_buf, atrac->first.filesize, atracID); +#endif + } + atrac->first.size += bytesToAdd; + if (atrac->first.size > atrac->first.filesize) + atrac->first.size = atrac->first.filesize; + atrac->first.fileoffset = atrac->first.size; + atrac->first.writableBytes = std::min(atrac->first.filesize - atrac->first.size, atrac->atracBufSize); return 0; } u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) { - DEBUG_LOG(HLE, "FAKE sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr); + DEBUG_LOG(HLE, "sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr); Atrac *atrac = getAtrac(atracID); u32 ret = 0; if (atrac != NULL) { // We already passed the end - return an error (many games check for this.) - if (atrac->decodePos >= atrac->decodeEnd && atrac->loopNum == 0) { + if (atrac->currentSample >= atrac->endSample && atrac->loopNum == 0) { Memory::Write_U32(0, numSamplesAddr); Memory::Write_U32(1, finishFlagAddr); Memory::Write_U32(0, remainAddr); @@ -303,32 +489,75 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF ret = ATRAC_ERROR_ALL_DATA_DECODED; } else { // TODO: This isn't at all right, but at least it makes the music "last" some time. - u32 numSamples = (atrac->decodeEnd - atrac->decodePos) / (sizeof(s16) * 2); - if (atrac->decodePos >= atrac->decodeEnd) { - numSamples = 0; - } else if (numSamples > ATRAC_MAX_SAMPLES) { - numSamples = ATRAC_MAX_SAMPLES; + u32 numSamples = 0; +#ifdef USE_FFMPEG + if (atrac->codeType == PSP_MODE_AT_3 && atrac->pCodecCtx) { + int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; + atrac->SeekToSample(forceseekSample); + atrac->SeekToSample(atrac->currentSample); + AVPacket packet; + int got_frame, ret; + while (av_read_frame(atrac->pFormatCtx, &packet) >= 0) { + if (packet.stream_index == atrac->audio_stream_index) { + got_frame = 0; + ret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, &packet); + if (ret < 0) { + ERROR_LOG(HLE, "avcodec_decode_audio4: Error decoding audio %d", ret); + av_free_packet(&packet); + break; + } + + if (got_frame) { + // got a frame + int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, + atrac->pFrame->nb_samples, (AVSampleFormat)atrac->pFrame->format, 1); + u8* out = Memory::GetPointer(outAddr); + numSamples = atrac->pFrame->nb_samples; + ret = swr_convert(atrac->pSwrCtx, &out, atrac->pFrame->nb_samples, + (const u8**)atrac->pFrame->extended_data, atrac->pFrame->nb_samples); + if (ret < 0) { + ERROR_LOG(HLE, "swr_convert: Error while converting %d", ret); + } + + } + av_free_packet(&packet); + if (got_frame) + break; + } + } + + } else +#endif // USE_FFMPEG + { + numSamples = atrac->endSample - atrac->currentSample; + if (atrac->currentSample >= atrac->endSample) { + numSamples = 0; + } else if (numSamples > ATRAC_MAX_SAMPLES) { + numSamples = ATRAC_MAX_SAMPLES; + } + + if (numSamples == 0 && (atrac->loopNum != 0)) { + numSamples = ATRAC_MAX_SAMPLES; + } + Memory::Memset(outAddr, 0, numSamples * sizeof(s16) * atrac->atracOutputChannels); } - // Should we loop? - if (numSamples == 0 && atrac->loopNum != 0) { - // Restart. - atrac->decodePos = 0; - if (atrac->loopNum > 0) - atrac->loopNum--; - numSamples = ATRAC_MAX_SAMPLES; - } - - Memory::Memset(outAddr, 0, numSamples * sizeof(s16) * 2); Memory::Write_U32(numSamples, numSamplesAddr); - atrac->decodePos += ATRAC_MAX_SAMPLES; + // update current sample and decodePos + atrac->currentSample += numSamples; + atrac->decodePos = atrac->getDecodePosBySample(atrac->currentSample); + + int finishFlag = 0; + if (atrac->loopNum != 0 && (atrac->currentSample >= atrac->loopEndSample || numSamples == 0)) { + atrac->currentSample = atrac->loopStartSample; + if (atrac->loopNum > 0) + atrac->loopNum --; + } else if (atrac->currentSample >= atrac->endSample || numSamples == 0) + finishFlag = 1; - if (numSamples < ATRAC_MAX_SAMPLES) { - Memory::Write_U32(1, finishFlagAddr); - } else { - Memory::Write_U32(0, finishFlagAddr); - } - Memory::Write_U32(-1, remainAddr); + Memory::Write_U32(finishFlag, finishFlagAddr); + int remains = atrac->getRemainFrames(); + Memory::Write_U32(remains, remainAddr); } // TODO: Can probably remove this after we validate no wrong ids? } else { @@ -358,11 +587,11 @@ u32 sceAtracGetBufferInfoForReseting(int atracID, int sample, u32 bufferInfoAddr Memory::Memset(bufferInfoAddr, 0, 32); //return -1; } else { - int sampleOffset = (u32)(atrac->firstSampleoffset + sample / ATRAC_MAX_SAMPLES * atrac->atracBytesPerFrame); + int Sampleoffset = atrac->getDecodePosBySample(sample); Memory::Write_U32(atrac->first.addr, bufferInfoAddr); Memory::Write_U32(atrac->first.writableBytes, bufferInfoAddr + 4); Memory::Write_U32(atrac->first.neededBytes, bufferInfoAddr + 8); - Memory::Write_U32(sampleOffset, bufferInfoAddr + 12); + Memory::Write_U32(Sampleoffset, bufferInfoAddr + 12); Memory::Write_U32(atrac->second.addr, bufferInfoAddr + 16); Memory::Write_U32(atrac->second.writableBytes, bufferInfoAddr + 20); Memory::Write_U32(atrac->second.neededBytes, bufferInfoAddr + 24); @@ -373,30 +602,24 @@ u32 sceAtracGetBufferInfoForReseting(int atracID, int sample, u32 bufferInfoAddr u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetBitrate(%i, %08x)", atracID, outBitrateAddr); + DEBUG_LOG(HLE, "sceAtracGetBitrate(%i, %08x)", atracID, outBitrateAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { - //return -1; + return -1; } - atrac->atracBitrate = ( atrac->atracBytesPerFrame * 352800 ) / 1000; - if (atrac->codeType == PSP_MODE_AT_3_PLUS) - atrac->atracBitrate = ((atrac->atracBitrate >> 11) + 8) & 0xFFFFFFF0; - else - atrac->atracBitrate = (atrac->atracBitrate + 511) >> 10; - + // I wonder which result should be returned. Such as a 64kbps bitrate audio, + // should we return 64 or 64 * 1000 ? Here returns the second one. if (Memory::IsValidAddress(outBitrateAddr)) Memory::Write_U32(atrac->atracBitrate, outBitrateAddr); - return 0; } u32 sceAtracGetChannel(int atracID, u32 channelAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetChannel(%i, %08x)", atracID, channelAddr); + DEBUG_LOG(HLE, "sceAtracGetChannel(%i, %08x)", atracID, channelAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { -//Fix Sengoku Musou 3 Z Special [JPN] crash return -1; } if (Memory::IsValidAddress(channelAddr)) @@ -406,14 +629,14 @@ u32 sceAtracGetChannel(int atracID, u32 channelAddr) u32 sceAtracGetLoopStatus(int atracID, u32 loopNumAddr, u32 statusAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetLoopStatus(%i, %08x, %08x)", atracID, loopNumAddr, statusAddr); + DEBUG_LOG(HLE, "sceAtracGetLoopStatus(%i, %08x, %08x)", atracID, loopNumAddr, statusAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; } else { if (Memory::IsValidAddress(loopNumAddr)) Memory::Write_U32(atrac->loopNum, loopNumAddr); - + // return audio's loopinfo in at3 file if (Memory::IsValidAddress(statusAddr)) { if (atrac->loopinfoNum > 0) Memory::Write_U32(1, statusAddr); @@ -438,7 +661,7 @@ u32 sceAtracGetInternalErrorInfo(int atracID, u32 errorAddr) u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr); + DEBUG_LOG(HLE, "sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; @@ -450,20 +673,20 @@ u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr) u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr); + DEBUG_LOG(HLE, "sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { - //return -1; + return -1; } - if (atrac->first.writableBytes - atrac->firstSampleoffset < atrac->atracBytesPerFrame || atrac->endSample < atrac->decodePos) + if (atrac->currentSample >= atrac->endSample) return ATRAC_ERROR_ALL_DATA_DECODED; - Memory::Write_U32(atrac->decodePos - atrac->currentSample, outposAddr); // outpos - return 0; + Memory::Write_U32(atrac->currentSample, outposAddr); // outpos + return 0; } u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { - ERROR_LOG(HLE, "FAKE sceAtracGetNextSample(%i, %08x)", atracID, outNAddr); + DEBUG_LOG(HLE, "sceAtracGetNextSample(%i, %08x)", atracID, outNAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; @@ -483,14 +706,13 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr) u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) { - ERROR_LOG(HLE, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr); + DEBUG_LOG(HLE, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; Memory::Write_U32(12, remainAddr); // outpos } else { - // TODO: Seems like this is the number of bytes remaining to read from the file (or -1 if none)? - Memory::Write_U32(-1, remainAddr); + Memory::Write_U32(atrac->getRemainFrames(), remainAddr); } return 0; } @@ -500,50 +722,30 @@ u32 sceAtracGetSecondBufferInfo(int atracID, u32 outposAddr, u32 outBytesAddr) ERROR_LOG(HLE, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { - Memory::Write_U32(0, outposAddr); - Memory::Write_U32(0, outBytesAddr); - return ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED; + //return -1; } - - // TODO: When sceAtracIsSecondBufferNeeded() says yes, change this function. Maybe it's wrong anyway. -#if 0 - u32 pos = (((atrac->loopEndSample >> (0x100B - atrac->codeType)) + 1) * atrac->atracBytesPerFrame + atrac->second.fileoffset - 1 ) + 1; - Memory::Write_U32(pos, outposAddr); - Memory::Write_U32(atrac->second.writableBytes - pos, outBytesAddr); - return 0; -#else Memory::Write_U32(0, outposAddr); - Memory::Write_U32(0, outBytesAddr); + Memory::Write_U32(0x10000, outBytesAddr); + // TODO: Maybe don't write the above? return ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED; -#endif } u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSampleAddr, u32 outLoopEndSampleAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr); + DEBUG_LOG(HLE, "sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; } - if (Memory::IsValidAddress(outEndSampleAddr)) - Memory::Write_U32(atrac->endSample - atrac->currentSample, outEndSampleAddr); - if (atrac->loopEndSample != 0) { - if (Memory::IsValidAddress(outLoopStartSampleAddr)) - Memory::Write_U32(atrac->loopStartSample - atrac->currentSample, outLoopStartSampleAddr); - if (Memory::IsValidAddress(outLoopEndSampleAddr)) - Memory::Write_U32(atrac->loopEndSample - atrac->currentSample, outLoopEndSampleAddr); - } else { - if (Memory::IsValidAddress(outLoopStartSampleAddr)) - Memory::Write_U32(-1, outLoopStartSampleAddr); - if (Memory::IsValidAddress(outLoopEndSampleAddr)) - Memory::Write_U32(-1, outLoopEndSampleAddr); - } + Memory::Write_U32(atrac->endSample, outEndSampleAddr); // outEndSample + Memory::Write_U32(atrac->loopStartSample, outLoopStartSampleAddr); // outLoopStartSample + Memory::Write_U32(atrac->loopEndSample, outLoopEndSampleAddr); // outLoopEndSample return 0; } u32 sceAtracGetStreamDataInfo(int atracID, u32 writeAddr, u32 writableBytesAddr, u32 readOffsetAddr) { - ERROR_LOG(HLE, "FAKE sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writeAddr, writableBytesAddr, readOffsetAddr); + DEBUG_LOG(HLE, "sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writeAddr, writableBytesAddr, readOffsetAddr); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; @@ -557,37 +759,176 @@ u32 sceAtracGetStreamDataInfo(int atracID, u32 writeAddr, u32 writableBytesAddr, u32 sceAtracReleaseAtracID(int atracID) { - ERROR_LOG(HLE, "UNIMPL sceAtracReleaseAtracID(%i)", atracID); + INFO_LOG(HLE, "sceAtracReleaseAtracID(%i)", atracID); deleteAtrac(atracID); return 0; } u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { - ERROR_LOG(HLE, "UNIMPL sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf); + INFO_LOG(HLE, "sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf); Atrac *atrac = getAtrac(atracID); if (!atrac) { //return -1; } else { - // TODO: Not sure what this means? - atrac->decodePos = sample; + atrac->currentSample = sample; +#ifdef USE_FFMPEG + if (atrac->codeType == PSP_MODE_AT_3 && atrac->pCodecCtx) { + atrac->SeekToSample(sample); + } else +#endif // USE_FFMPEG + { + atrac->decodePos = atrac->getDecodePosBySample(sample); + } } return 0; } +#ifdef USE_FFMPEG +int _AtracReadbuffer(void *opaque, uint8_t *buf, int buf_size) +{ + Atrac *atrac = (Atrac*)opaque; + int size = std::min((int)atrac->atracBufSize, buf_size); + size = std::max(std::min(((int)atrac->first.size - (int)atrac->decodePos), size), 0); + if (size > 0) + memcpy(buf, atrac->data_buf + atrac->decodePos, size); + atrac->decodePos += size; + return size; +} + +int64_t _AtracSeekbuffer(void *opaque, int64_t offset, int whence) +{ + Atrac *atrac = (Atrac*)opaque; + switch (whence) { + case SEEK_SET: + atrac->decodePos = offset; + break; + case SEEK_CUR: + atrac->decodePos += offset; + break; + case SEEK_END: + atrac->decodePos = atrac->first.filesize - offset; + break; + } + return offset; +} + +#endif // USE_FFMPEG + +int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) +{ + atrac->atracBufSize = bufferSize; + if (atrac->first.size > atrac->first.filesize) + atrac->first.size = atrac->first.filesize; + atrac->first.fileoffset = atrac->first.size; + atrac->first.writableBytes = std::min(atrac->first.filesize - atrac->first.size, atrac->atracBufSize); + +#ifdef USE_FFMPEG + if (atrac->codeType == PSP_MODE_AT_3) { + INFO_LOG(HLE, "This is an atrac3 audio"); + + // some games may reuse an atracID for playing sound + atrac->ReleaseFFMPEGContext(); + + if (atrac->data_buf) + delete [] atrac->data_buf; + + atrac->data_buf = new u8[atrac->first.filesize]; + Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); + u8* tempbuf = (u8*)av_malloc(atrac->atracBufSize); + + atrac->pFormatCtx = avformat_alloc_context(); + atrac->pAVIOCtx = avio_alloc_context(tempbuf, atrac->atracBufSize, 0, (void*)atrac, _AtracReadbuffer, NULL, _AtracSeekbuffer); + atrac->pFormatCtx->pb = atrac->pAVIOCtx; + + int ret; + // Load audio buffer + if((ret = avformat_open_input((AVFormatContext**)&atrac->pFormatCtx, NULL, NULL, NULL)) != 0) { + ERROR_LOG(HLE, "avformat_open_input: Cannot open input %d", ret); + return -1; + } + + if((ret = avformat_find_stream_info(atrac->pFormatCtx, NULL)) < 0) { + ERROR_LOG(HLE, "avformat_find_stream_info: Cannot find stream information %d", ret); + return -1; + } + + AVCodec *pCodec; + // select the audio stream + ret = av_find_best_stream(atrac->pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0); + if (ret < 0) { + ERROR_LOG(HLE, "av_find_best_stream: Cannot find a audio stream in the input file %d", ret); + return -1; + } + atrac->audio_stream_index = ret; + atrac->pCodecCtx= atrac->pFormatCtx->streams[atrac->audio_stream_index]->codec; + + // open codec + if ((ret = avcodec_open2(atrac->pCodecCtx, pCodec, NULL)) < 0) { + ERROR_LOG(HLE, "avcodec_open2: Cannot open audio decoder %d", ret); + return -1; + } + + int wanted_channels = atrac->atracOutputChannels; + int wanted_channel_layout = av_get_default_channel_layout(wanted_channels); + int dec_channel_layout = av_get_default_channel_layout(atrac->atracChannels); + + atrac->pSwrCtx = + swr_alloc_set_opts + ( + NULL, + wanted_channel_layout, + AV_SAMPLE_FMT_S16, + atrac->pCodecCtx->sample_rate, + dec_channel_layout, + atrac->pCodecCtx->sample_fmt, + atrac->pCodecCtx->sample_rate, + 0, + NULL + ); + if (!atrac->pSwrCtx) { + ERROR_LOG(HLE, "swr_alloc_set_opts: Could not allocate resampler context %d", ret); + return -1; + } + if ((ret = swr_init(atrac->pSwrCtx)) < 0) { + ERROR_LOG(HLE, "swr_init: Failed to initialize the resampling context %d", ret); + return -1; + } + + // alloc audio frame + atrac->pFrame = avcodec_alloc_frame(); + + return 0; + } +#endif // _USE_FFMPEG + + return 0; +} + +int _AtracSetData(int atracID, u32 buffer, u32 bufferSize) +{ + Atrac *atrac = getAtrac(atracID); + if (!atrac) + return -1; + return _AtracSetData(atrac, buffer, bufferSize); +} + u32 sceAtracSetHalfwayBuffer(int atracID, u32 halfBuffer, u32 readSize, u32 halfBufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetHalfwayBuffer(%i, %08x, %8x, %8x)", atracID, halfBuffer, readSize, halfBufferSize); + INFO_LOG(HLE, "sceAtracSetHalfwayBuffer(%i, %08x, %8x, %8x)", atracID, halfBuffer, readSize, halfBufferSize); if (readSize > halfBufferSize) return ATRAC_ERROR_INCORRECT_READ_SIZE; Atrac *atrac = getAtrac(atracID); - if (atrac) { + int ret = 0; + if (atrac != NULL) { atrac->first.addr = halfBuffer; - atrac->first.size = halfBufferSize; + atrac->first.size = readSize; atrac->Analyze(); + atrac->atracOutputChannels = 2; + ret = _AtracSetData(atracID, halfBuffer, halfBufferSize); } - return 0; + return ret; } u32 sceAtracSetSecondBuffer(int atracID, u32 secondBuffer, u32 secondBufferSize) @@ -602,43 +943,53 @@ u32 sceAtracSetSecondBuffer(int atracID, u32 secondBuffer, u32 secondBufferSize) u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetData(%i, %08x, %08x)", atracID, buffer, bufferSize); + INFO_LOG(HLE, "sceAtracSetData(%i, %08x, %08x)", atracID, buffer, bufferSize); Atrac *atrac = getAtrac(atracID); + int ret = 0; if (atrac != NULL) { atrac->first.addr = buffer; atrac->first.size = bufferSize; atrac->Analyze(); + atrac->atracOutputChannels = 2; + ret = _AtracSetData(atracID, buffer, bufferSize); } - return 0; + return ret; } int sceAtracSetDataAndGetID(u32 buffer, u32 bufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetDataAndGetID(%08x, %08x)", buffer, bufferSize); + INFO_LOG(HLE, "sceAtracSetDataAndGetID(%08x, %08x)", buffer, bufferSize); int codecType = getCodecType(buffer); Atrac *atrac = new Atrac(); atrac->first.addr = buffer; atrac->first.size = bufferSize; atrac->Analyze(); - return createAtrac(atrac); + atrac->atracOutputChannels = 2; + int atracID = createAtrac(atrac); + int ret = _AtracSetData(atracID, buffer, bufferSize); + if (ret < 0) + return ret; + return atracID; } int sceAtracSetHalfwayBufferAndGetID(u32 halfBuffer, u32 readSize, u32 halfBufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetHalfwayBufferAndGetID(%08x, %08x, %08x)", halfBuffer, readSize, halfBufferSize); + INFO_LOG(HLE, "sceAtracSetHalfwayBufferAndGetID(%08x, %08x, %08x)", halfBuffer, readSize, halfBufferSize); if (readSize > halfBufferSize) return ATRAC_ERROR_INCORRECT_READ_SIZE; - - if (readSize < 0 || halfBufferSize < 0) - return -1; - int codecType = getCodecType(halfBuffer); + Atrac *atrac = new Atrac(); atrac->first.addr = halfBuffer; - atrac->first.size = halfBufferSize; + atrac->first.size = readSize; atrac->Analyze(); - return createAtrac(atrac); + atrac->atracOutputChannels = 2; + int atracID = createAtrac(atrac); + int ret = _AtracSetData(atracID, halfBuffer, halfBufferSize); + if (ret < 0) + return ret; + return atracID; } u32 sceAtracStartEntry() @@ -649,11 +1000,14 @@ u32 sceAtracStartEntry() u32 sceAtracSetLoopNum(int atracID, int loopNum) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetLoopNum(%i, %i)", atracID, loopNum); + INFO_LOG(HLE, "sceAtracSetLoopNum(%i, %i)", atracID, loopNum); Atrac *atrac = getAtrac(atracID); if (atrac) { + if (atrac->loopinfoNum == 0) + return ATRAC_ERROR_UNSET_PARAM; atrac->loopNum = loopNum; if (loopNum != 0 && atrac->loopinfoNum == 0) { + // Just loop the whole audio atrac->loopStartSample = 0; atrac->loopEndSample = atrac->endSample; } @@ -669,10 +1023,10 @@ int sceAtracReinit() int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr) { - ERROR_LOG(HLE, "UNIMPL sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr); + DEBUG_LOG(HLE, "sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr); Atrac *atrac = getAtrac(atracID); if (Memory::IsValidAddress(outputChanPtr)) - Memory::Write_U32(atrac->atracChannels, outputChanPtr); + Memory::Write_U32(atrac ? atrac->atracOutputChannels : 2, outputChanPtr); return 0; } @@ -686,33 +1040,73 @@ int sceAtracIsSecondBufferNeeded(int atracID) return 0; } -int sceAtracSetMOutHalfwayBuffer(int atracID, u32 MOutHalfBuffer, int readSize, int MOutHalfBufferSize) +int sceAtracSetMOutHalfwayBuffer(int atracID, u32 MOutHalfBuffer, u32 readSize, u32 MOutHalfBufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetMOutHalfwayBuffer(%i, %08x, %i, %i)", atracID, MOutHalfBuffer, readSize, MOutHalfBufferSize); + INFO_LOG(HLE, "sceAtracSetMOutHalfwayBuffer(%i, %08x, %08x, %08x)", atracID, MOutHalfBuffer, readSize, MOutHalfBufferSize); if (readSize > MOutHalfBufferSize) return ATRAC_ERROR_INCORRECT_READ_SIZE; + Atrac *atrac = getAtrac(atracID); - if (!atrac) { - //return -1; + int ret = 0; + if (atrac != NULL) { + atrac->first.addr = MOutHalfBuffer; + atrac->first.size = readSize; + atrac->Analyze(); + atrac->atracOutputChannels = 1; + ret = _AtracSetData(atracID, MOutHalfBuffer, MOutHalfBufferSize); } - return 0; + return ret; } -int sceAtracSetAA3HalfwayBufferAndGetID(u32 halfBuffer, u32 readSize, u32 halfBufferSize) +u32 sceAtracSetMOutData(int atracID, u32 buffer, u32 bufferSize) { - ERROR_LOG(HLE, "UNIMPL sceAtracSetAA3HalfwayBufferAndGetID(%08x, %08x, %08x)", halfBuffer, readSize, halfBufferSize); + INFO_LOG(HLE, "sceAtracSetMOutData(%i, %08x, %08x)", atracID, buffer, bufferSize); + Atrac *atrac = getAtrac(atracID); + int ret = 0; + if (atrac != NULL) { + atrac->first.addr = buffer; + atrac->first.size = bufferSize; + atrac->Analyze(); + atrac->atracOutputChannels = 1; + ret = _AtracSetData(atracID, buffer, bufferSize); + } + return ret; +} + +int sceAtracSetMOutDataAndGetID(u32 buffer, u32 bufferSize) +{ + INFO_LOG(HLE, "sceAtracSetMOutDataAndGetID(%08x, %08x)", buffer, bufferSize); + int codecType = getCodecType(buffer); + + Atrac *atrac = new Atrac(); + atrac->first.addr = buffer; + atrac->first.size = bufferSize; + atrac->Analyze(); + atrac->atracOutputChannels = 1; + int atracID = createAtrac(atrac); + int ret = _AtracSetData(atracID, buffer, bufferSize); + if (ret < 0) + return ret; + return atracID; +} + +int sceAtracSetMOutHalfwayBufferAndGetID(u32 halfBuffer, u32 readSize, u32 halfBufferSize) +{ + INFO_LOG(HLE, "sceAtracSetMOutHalfwayBufferAndGetID(%08x, %08x, %08x)", halfBuffer, readSize, halfBufferSize); if (readSize > halfBufferSize) return ATRAC_ERROR_INCORRECT_READ_SIZE; - - if (readSize < 0 || halfBufferSize < 0) - return -1; - int codecType = getCodecType(halfBuffer); + Atrac *atrac = new Atrac(); atrac->first.addr = halfBuffer; - atrac->first.size = halfBufferSize; + atrac->first.size = readSize; atrac->Analyze(); - return createAtrac(atrac); + atrac->atracOutputChannels = 1; + int atracID = createAtrac(atrac); + int ret = _AtracSetData(atracID, halfBuffer, halfBufferSize); + if (ret < 0) + return ret; + return atracID; } int sceAtracSetAA3DataAndGetID(u32 buffer, int bufferSize, int fileSize, u32 metadataSizeAddr) @@ -740,17 +1134,47 @@ int _sceAtracGetContextAddress(int atracID) int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelInitDecoder(%i, %08x)", atracID, paramsAddr); + Atrac *atrac = getAtrac(atracID); + if (atrac && Memory::IsValidAddress(paramsAddr)) { + atrac->atracChannels = Memory::Read_U32(paramsAddr); + atrac->atracOutputChannels = Memory::Read_U32(paramsAddr + 4); + atrac->atracBufSize = Memory::Read_U32(paramsAddr + 8); + } return 0; } int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelDecode(%i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); - if (Memory::IsValidAddress(sampleBytesAddr)) - Memory::Write_U32(0, sampleBytesAddr); + DEBUG_LOG(HLE, "UNIMPL sceAtracLowLevelDecode(%i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); + Atrac *atrac = getAtrac(atracID); + /*if (Memory::IsValidAddress(sourceBytesConsumedAddr)) + Memory::Write_U32(0, sourceBytesConsumedAddr); + if (Memory::IsValidAddress(samplesAddr) && Memory::IsValidAddress(sampleBytesAddr)) { + Memory::Write_U32(ATRAC_MAX_SAMPLES, sampleBytesAddr); + int outputChannels = atrac ? atrac->atracOutputChannels : 2; + Memory::Memset(samplesAddr, 0, ATRAC_MAX_SAMPLES * sizeof(s16) * outputChannels); + }*/ + Memory::Write_U32(0, sampleBytesAddr); return 0; } +int sceAtracSetAA3HalfwayBufferAndGetID(u32 halfBuffer, u32 readSize, u32 halfBufferSize) +{ + ERROR_LOG(HLE, "UNIMPL sceAtracSetAA3HalfwayBufferAndGetID(%08x, %08x, %08x)", halfBuffer, readSize, halfBufferSize); + if (readSize > halfBufferSize) + return ATRAC_ERROR_INCORRECT_READ_SIZE; + + if (readSize < 0 || halfBufferSize < 0) + return -1; + + int codecType = getCodecType(halfBuffer); + Atrac *atrac = new Atrac(); + atrac->first.addr = halfBuffer; + atrac->first.size = halfBufferSize; + atrac->Analyze(); + return createAtrac(atrac); +} + const HLEFunction sceAtrac3plus[] = { {0x7db31251,WrapU_IU,"sceAtracAddStreamData"}, @@ -781,11 +1205,11 @@ const HLEFunction sceAtrac3plus[] = {0xeca32a99,WrapI_I,"sceAtracIsSecondBufferNeeded"}, {0x0fae370e,WrapI_UUU,"sceAtracSetHalfwayBufferAndGetID"}, {0x2DD3E298,WrapU_IIU,"sceAtracGetBufferInfoForResetting"}, - {0x5CF9D852,WrapI_IUII,"sceAtracSetMOutHalfwayBuffer"}, + {0x5CF9D852,WrapI_IUUU,"sceAtracSetMOutHalfwayBuffer"}, + {0xF6837A1A,WrapU_IUU,"sceAtracSetMOutData"}, + {0x472E3825,WrapI_UU,"sceAtracSetMOutDataAndGetID"}, + {0x9CD7DE03,WrapI_UUU,"sceAtracSetMOutHalfwayBufferAndGetID"}, {0xB3B5D042,WrapI_IU,"sceAtracGetOutputChannel"}, - {0xF6837A1A,0,"sceAtracSetMOutData"}, - {0x472E3825,0,"sceAtracSetMOutDataAndGetID"}, - {0x9CD7DE03,0,"sceAtracSetMOutHalfwayBufferAndGetID"}, {0x5622B7C1,WrapI_UIIU,"sceAtracSetAA3DataAndGetID"}, {0x5DD66588,WrapI_UUU,"sceAtracSetAA3HalfwayBufferAndGetID"}, {0x231FC6B7,WrapI_I<_sceAtracGetContextAddress>,"_sceAtracGetContextAddress"}, From 2181b76c42514c05323c16758d32a10f5b37b18d Mon Sep 17 00:00:00 2001 From: nachume Date: Sat, 4 May 2013 20:34:33 +0900 Subject: [PATCH 06/16] ISO that replaced EBOOT.BIN is playable. implement LoadExecForUer_362A956B() and sceKernelRegisterExitCallback. Add some ERROR define on kernel.h. I was referring to the jpcsp. --- Core/HLE/sceKernel.cpp | 9 +- Core/HLE/sceKernel.h | 475 ++++++++++++++++++++--------------- Core/HLE/sceKernelMemory.cpp | 32 ++- Core/HLE/sceKernelThread.cpp | 33 +++ Core/HLE/sceKernelThread.h | 1 + 5 files changed, 343 insertions(+), 207 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 4cc35e190f..b37fce7859 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -76,6 +76,7 @@ static bool kernelRunning = false; KernelObjectPool kernelObjects; KernelStats kernelStats; +u32 registeredExitCbId; void __KernelInit() { @@ -236,13 +237,15 @@ void sceKernelExitGameWithStatus() int LoadExecForUser_362A956B() { - ERROR_LOG(HLE,"UNIMPL LoadExecForUser_362A956B()"); - return 0; + return hleLoadExecForUser_362A956B(); } u32 sceKernelRegisterExitCallback(u32 cbId) { - DEBUG_LOG(HLE,"NOP sceKernelRegisterExitCallback(%i)", cbId); + DEBUG_LOG(HLE,"sceKernelRegisterExitCallback(%i)", cbId); + if (__KernelRegisterCallback(THREAD_CALLBACK_EXIT, cbId) == 0) { + registeredExitCbId = cbId; + } return 0; } diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index dfb2f5060c..f5e03e6dab 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -27,209 +27,285 @@ class PointerWrap; enum { SCE_KERNEL_ERROR_OK = 0, + SCE_KERNEL_ERROR_ALREADY = 0x80000020, + SCE_KERNEL_ERROR_BUSY = 0x80000021, SCE_KERNEL_ERROR_OUT_OF_MEMORY = 0x80000022, SCE_KERNEL_ERROR_INVALID_ID = 0x80000100, + SCE_KERNEL_ERROR_INVALID_NAME = 0x80000101, + SCE_KERNEL_ERROR_INVALID_INDEX = 0x80000102, + SCE_KERNEL_ERROR_INVALID_POINTER = 0x80000103, SCE_KERNEL_ERROR_INVALID_SIZE = 0x80000104, + SCE_KERNEL_ERROR_INVALID_FLAG = 0x80000105, + SCE_KERNEL_ERROR_INVALID_COMMAND = 0x80000106, SCE_KERNEL_ERROR_INVALID_MODE = 0x80000107, - SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001fe, - SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001ff, - SCE_KERNEL_ERROR_ERROR = 0x80020001, - SCE_KERNEL_ERROR_NOTIMP = 0x80020002, - SCE_KERNEL_ERROR_ILLEGAL_EXPCODE = 0x80020032, - SCE_KERNEL_ERROR_EXPHANDLER_NOUSE = 0x80020033, - SCE_KERNEL_ERROR_EXPHANDLER_USED = 0x80020034, - SCE_KERNEL_ERROR_SYCALLTABLE_NOUSED = 0x80020035, - SCE_KERNEL_ERROR_SYCALLTABLE_USED = 0x80020036, - SCE_KERNEL_ERROR_ILLEGAL_SYSCALLTABLE = 0x80020037, - SCE_KERNEL_ERROR_ILLEGAL_PRIMARY_SYSCALL_NUMBER = 0x80020038, - SCE_KERNEL_ERROR_PRIMARY_SYSCALL_NUMBER_INUSE = 0x80020039, - SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80020064, - SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80020065, - SCE_KERNEL_ERROR_CPUDI = 0x80020066, - SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80020067, - SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x80020068, - SCE_KERNEL_ERROR_ILLEGAL_INTRLEVEL = 0x80020069, - SCE_KERNEL_ERROR_ILLEGAL_ADDRESS = 0x8002006a, - SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x8002006b, - SCE_KERNEL_ERROR_ILLEGAL_STACK_ADDRESS = 0x8002006c, - SCE_KERNEL_ERROR_ALREADY_STACK_SET = 0x8002006d, - SCE_KERNEL_ERROR_NO_TIMER = 0x80020096, - SCE_KERNEL_ERROR_ILLEGAL_TIMERID = 0x80020097, - SCE_KERNEL_ERROR_ILLEGAL_SOURCE = 0x80020098, - SCE_KERNEL_ERROR_ILLEGAL_PRESCALE = 0x80020099, - SCE_KERNEL_ERROR_TIMER_BUSY = 0x8002009a, - SCE_KERNEL_ERROR_TIMER_NOT_SETUP = 0x8002009b, - SCE_KERNEL_ERROR_TIMER_NOT_INUSE = 0x8002009c, - SCE_KERNEL_ERROR_UNIT_USED = 0x800200a0, - SCE_KERNEL_ERROR_UNIT_NOUSE = 0x800200a1, - SCE_KERNEL_ERROR_NO_ROMDIR = 0x800200a2, - SCE_KERNEL_ERROR_IDTYPE_EXIST = 0x800200c8, - SCE_KERNEL_ERROR_IDTYPE_NOT_EXIST = 0x800200c9, - SCE_KERNEL_ERROR_IDTYPE_NOT_EMPTY = 0x800200ca, - SCE_KERNEL_ERROR_UNKNOWN_UID = 0x800200cb, - SCE_KERNEL_ERROR_UNMATCH_UID_TYPE = 0x800200cc, - SCE_KERNEL_ERROR_ID_NOT_EXIST = 0x800200cd, - SCE_KERNEL_ERROR_NOT_FOUND_UIDFUNC = 0x800200ce, - SCE_KERNEL_ERROR_UID_ALREADY_HOLDER = 0x800200cf, - SCE_KERNEL_ERROR_UID_NOT_HOLDER = 0x800200d0, - SCE_KERNEL_ERROR_ILLEGAL_PERM = 0x800200d1, - SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT = 0x800200d2, - SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x800200d3, - SCE_KERNEL_ERROR_OUT_OF_RANGE = 0x800200d4, - SCE_KERNEL_ERROR_MEM_RANGE_OVERLAP = 0x800200d5, - SCE_KERNEL_ERROR_ILLEGAL_PARTITION = 0x800200d6, - SCE_KERNEL_ERROR_PARTITION_INUSE = 0x800200d7, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE = 0x800200d8, - SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED = 0x800200d9, - SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_LOCKED = 0x800200da, - SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_FAILED = 0x800200db, - SCE_KERNEL_ERROR_HEAPBLOCK_ALLOC_FAILED = 0x800200dc, - SCE_KERNEL_ERROR_HEAP_ALLOC_FAILED = 0x800200dd, - SCE_KERNEL_ERROR_ILLEGAL_CHUNK_ID = 0x800200de, - SCE_KERNEL_ERROR_NOCHUNK = 0x800200df, - SCE_KERNEL_ERROR_NO_FREECHUNK = 0x800200e0, - SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE = 0x800200e4, - SCE_KERNEL_ERROR_LINKERR = 0x8002012c, - SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d, - SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e, - SCE_KERNEL_ERROR_NOFILE = 0x8002012f, - SCE_KERNEL_ERROR_FILEERR = 0x80020130, - SCE_KERNEL_ERROR_MEMINUSE = 0x80020131, - SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132, - SCE_KERNEL_ERROR_ALREADY_STARTED = 0x80020133, - SCE_KERNEL_ERROR_NOT_STARTED = 0x80020134, - SCE_KERNEL_ERROR_ALREADY_STOPPED = 0x80020135, - SCE_KERNEL_ERROR_CAN_NOT_STOP = 0x80020136, - SCE_KERNEL_ERROR_NOT_STOPPED = 0x80020137, - SCE_KERNEL_ERROR_NOT_REMOVABLE = 0x80020138, - SCE_KERNEL_ERROR_EXCLUSIVE_LOAD = 0x80020139, - SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED = 0x8002013a, - SCE_KERNEL_ERROR_LIBRARY_FOUND = 0x8002013b, - SCE_KERNEL_ERROR_LIBRARY_NOTFOUND = 0x8002013c, - SCE_KERNEL_ERROR_ILLEGAL_LIBRARY = 0x8002013d, - SCE_KERNEL_ERROR_LIBRARY_INUSE = 0x8002013e, - SCE_KERNEL_ERROR_ALREADY_STOPPING = 0x8002013f, - SCE_KERNEL_ERROR_ILLEGAL_OFFSET = 0x80020140, - SCE_KERNEL_ERROR_ILLEGAL_POSITION = 0x80020141, - SCE_KERNEL_ERROR_ILLEGAL_ACCESS = 0x80020142, - SCE_KERNEL_ERROR_MODULE_MGR_BUSY = 0x80020143, - SCE_KERNEL_ERROR_ILLEGAL_FLAG = 0x80020144, - SCE_KERNEL_ERROR_CANNOT_GET_MODULELIST = 0x80020145, - SCE_KERNEL_ERROR_PROHIBIT_LOADMODULE_DEVICE = 0x80020146, - SCE_KERNEL_ERROR_PROHIBIT_LOADEXEC_DEVICE = 0x80020147, - SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE = 0x80020148, - SCE_KERNEL_ERROR_ILLEGAL_PERM_CALL = 0x80020149, - SCE_KERNEL_ERROR_CANNOT_GET_MODULE_INFORMATION = 0x8002014a, - SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_BUFFER = 0x8002014b, - SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_FILENAME = 0x8002014c, - SCE_KERNEL_ERROR_NO_EXIT_CALLBACK = 0x8002014d, - SCE_KERNEL_ERROR_NO_MEMORY = 0x80020190, - SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x80020191, - SCE_KERNEL_ERROR_ILLEGAL_ENTRY = 0x80020192, - SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80020193, - SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80020194, - SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020195, - SCE_KERNEL_ERROR_ILLEGAL_MASK = 0x80020196, - SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80020197, - SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80020198, - SCE_KERNEL_ERROR_UNKNOWN_SEMID = 0x80020199, - SCE_KERNEL_ERROR_UNKNOWN_EVFID = 0x8002019a, - SCE_KERNEL_ERROR_UNKNOWN_MBXID = 0x8002019b, - SCE_KERNEL_ERROR_UNKNOWN_VPLID = 0x8002019c, - SCE_KERNEL_ERROR_UNKNOWN_FPLID = 0x8002019d, - SCE_KERNEL_ERROR_UNKNOWN_MPPID = 0x8002019e, - SCE_KERNEL_ERROR_UNKNOWN_ALMID = 0x8002019f, - SCE_KERNEL_ERROR_UNKNOWN_TEID = 0x800201a0, - SCE_KERNEL_ERROR_UNKNOWN_CBID = 0x800201a1, - SCE_KERNEL_ERROR_DORMANT = 0x800201a2, - SCE_KERNEL_ERROR_SUSPEND = 0x800201a3, - SCE_KERNEL_ERROR_NOT_DORMANT = 0x800201a4, - SCE_KERNEL_ERROR_NOT_SUSPEND = 0x800201a5, - SCE_KERNEL_ERROR_NOT_WAIT = 0x800201a6, - SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x800201a7, - SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x800201a8, - SCE_KERNEL_ERROR_WAIT_CANCEL = 0x800201a9, - SCE_KERNEL_ERROR_RELEASE_WAIT = 0x800201aa, - SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x800201ab, - SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x800201ac, - SCE_KERNEL_ERROR_SEMA_ZERO = 0x800201ad, - SCE_KERNEL_ERROR_SEMA_OVF = 0x800201ae, - SCE_KERNEL_ERROR_EVF_COND = 0x800201af, - SCE_KERNEL_ERROR_EVF_MULTI = 0x800201b0, - SCE_KERNEL_ERROR_EVF_ILPAT = 0x800201b1, - SCE_KERNEL_ERROR_MBOX_NOMSG = 0x800201b2, - SCE_KERNEL_ERROR_MPP_FULL = 0x800201b3, - SCE_KERNEL_ERROR_MPP_EMPTY = 0x800201b4, - SCE_KERNEL_ERROR_WAIT_DELETE = 0x800201b5, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK = 0x800201b6, - SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE = 0x800201b7, - SCE_KERNEL_ERROR_ILLEGAL_SPADADDR = 0x800201b8, - SCE_KERNEL_ERROR_SPAD_INUSE = 0x800201b9, - SCE_KERNEL_ERROR_SPAD_NOT_INUSE = 0x800201ba, - SCE_KERNEL_ERROR_ILLEGAL_TYPE = 0x800201bb, - SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x800201bc, - SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x800201bd, - SCE_KERNEL_ERROR_UNKNOWN_VTID = 0x800201be, - SCE_KERNEL_ERROR_ILLEGAL_VTID = 0x800201bf, - SCE_KERNEL_ERROR_ILLEGAL_KTLSID = 0x800201c0, - SCE_KERNEL_ERROR_KTLS_FULL = 0x800201c1, - SCE_KERNEL_ERROR_KTLS_BUSY = 0x800201c2, - SCE_KERNEL_ERROR_PM_INVALID_PRIORITY = 0x80020258, - SCE_KERNEL_ERROR_PM_INVALID_DEVNAME = 0x80020259, - SCE_KERNEL_ERROR_PM_UNKNOWN_DEVNAME = 0x8002025a, - SCE_KERNEL_ERROR_PM_PMINFO_REGISTERED = 0x8002025b, - SCE_KERNEL_ERROR_PM_PMINFO_UNREGISTERED = 0x8002025c, - SCE_KERNEL_ERROR_PM_INVALID_MAJOR_STATE = 0x8002025d, - SCE_KERNEL_ERROR_PM_INVALID_REQUEST = 0x8002025e, - SCE_KERNEL_ERROR_PM_UNKNOWN_REQUEST = 0x8002025f, - SCE_KERNEL_ERROR_PM_INVALID_UNIT = 0x80020260, - SCE_KERNEL_ERROR_PM_CANNOT_CANCEL = 0x80020261, - SCE_KERNEL_ERROR_PM_INVALID_PMINFO = 0x80020262, - SCE_KERNEL_ERROR_PM_INVALID_ARGUMENT = 0x80020263, - SCE_KERNEL_ERROR_PM_ALREADY_TARGET_PWRSTATE = 0x80020264, - SCE_KERNEL_ERROR_PM_CHANGE_PWRSTATE_FAILED = 0x80020265, - SCE_KERNEL_ERROR_PM_CANNOT_CHANGE_DEVPWR_STATE = 0x80020266, - SCE_KERNEL_ERROR_PM_NO_SUPPORT_DEVPWR_STATE = 0x80020267, - SCE_KERNEL_ERROR_DMAC_REQUEST_FAILED = 0x800202bc, - SCE_KERNEL_ERROR_DMAC_REQUEST_DENIED = 0x800202bd, - SCE_KERNEL_ERROR_DMAC_OP_QUEUED = 0x800202be, - SCE_KERNEL_ERROR_DMAC_OP_NOT_QUEUED = 0x800202bf, - SCE_KERNEL_ERROR_DMAC_OP_RUNNING = 0x800202c0, - SCE_KERNEL_ERROR_DMAC_OP_NOT_ASSIGNED = 0x800202c1, - SCE_KERNEL_ERROR_DMAC_OP_TIMEOUT = 0x800202c2, - SCE_KERNEL_ERROR_DMAC_OP_FREED = 0x800202c3, - SCE_KERNEL_ERROR_DMAC_OP_USED = 0x800202c4, - SCE_KERNEL_ERROR_DMAC_OP_EMPTY = 0x800202c5, - SCE_KERNEL_ERROR_DMAC_OP_ABORTED = 0x800202c6, - SCE_KERNEL_ERROR_DMAC_OP_ERROR = 0x800202c7, - SCE_KERNEL_ERROR_DMAC_CHANNEL_RESERVED = 0x800202c8, - SCE_KERNEL_ERROR_DMAC_CHANNEL_EXCLUDED = 0x800202c9, - SCE_KERNEL_ERROR_DMAC_PRIVILEGE_ADDRESS = 0x800202ca, - SCE_KERNEL_ERROR_DMAC_NO_ENOUGHSPACE = 0x800202cb, - SCE_KERNEL_ERROR_DMAC_CHANNEL_NOT_ASSIGNED = 0x800202cc, - SCE_KERNEL_ERROR_DMAC_CHILD_OPERATION = 0x800202cd, - SCE_KERNEL_ERROR_DMAC_TOO_MUCH_SIZE = 0x800202ce, - SCE_KERNEL_ERROR_DMAC_INVALID_ARGUMENT = 0x800202cf, - SCE_KERNEL_ERROR_MFILE = 0x80020320, - SCE_KERNEL_ERROR_NODEV = 0x80020321, - SCE_KERNEL_ERROR_XDEV = 0x80020322, - SCE_KERNEL_ERROR_BADF = 0x80020323, - SCE_KERNEL_ERROR_INVAL = 0x80020324, - SCE_KERNEL_ERROR_UNSUP = 0x80020325, - SCE_KERNEL_ERROR_ALIAS_USED = 0x80020326, - SCE_KERNEL_ERROR_CANNOT_MOUNT = 0x80020327, - SCE_KERNEL_ERROR_DRIVER_DELETED = 0x80020328, - SCE_KERNEL_ERROR_ASYNC_BUSY = 0x80020329, - SCE_KERNEL_ERROR_NOASYNC = 0x8002032a, - SCE_KERNEL_ERROR_REGDEV = 0x8002032b, - SCE_KERNEL_ERROR_NOCWD = 0x8002032c, - SCE_KERNEL_ERROR_NAMETOOLONG = 0x8002032d, - SCE_KERNEL_ERROR_NXIO = 0x800203e8, - SCE_KERNEL_ERROR_IO = 0x800203e9, - SCE_KERNEL_ERROR_NOMEM = 0x800203ea, - SCE_KERNEL_ERROR_STDIO_NOT_OPENED = 0x800203eb, - SCE_KERNEL_ERROR_CACHE_ALIGNMENT = 0x8002044c, - SCE_KERNEL_ERROR_ERRORMAX = 0x8002044d, + SCE_KERNEL_ERROR_INVALID_FORMAT = 0x80000108, + SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001FE, + SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001FF, + SCE_KERNEL_ERROR_BAD_FILE = 0x80000209, + SCE_KERNEL_ERROR_ACCESS_ERROR = 0x8000020D, + + SCE_KERNEL_ERROR_ERRNO_ARG_LIST_TOO_LONG = 0x80010007, + SCE_KERNEL_ERROR_ERRNO_INVALID_FILE_DESCRIPTOR = 0x80010009, + SCE_KERNEL_ERROR_ERRNO_RESOURCE_UNAVAILABLE = 0x8001000B, + SCE_KERNEL_ERROR_ERRNO_NO_MEMORY = 0x8001000C, + SCE_KERNEL_ERROR_ERRNO_NO_PERM = 0x8001000D, + SCE_KERNEL_ERROR_ERRNO_FILE_INVALID_ADDR = 0x8001000E, + SCE_KERNEL_ERROR_ERRNO_DEVICE_BUSY = 0x80010010, + SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS = 0x80010011, + SCE_KERNEL_ERROR_ERRNO_CROSS_DEV_LINK = 0x80010012, + SCE_KERNEL_ERROR_ERRNO_DEVICE_NOT_FOUND = 0x80010013, + SCE_KERNEL_ERROR_ERRNO_NOT_A_DIRECTORY = 0x80010014, + SCE_KERNEL_ERROR_ERRNO_IS_DIRECTORY = 0x80010015, + SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT = 0x80010016, + SCE_KERNEL_ERROR_ERRNO_TOO_MANY_OPEN_SYSTEM_FILES = 0x80010018, + SCE_KERNEL_ERROR_ERRNO_FILE_IS_TOO_BIG = 0x8001001B, + SCE_KERNEL_ERROR_ERRNO_DEVICE_NO_FREE_SPACE = 0x8001001C, + SCE_KERNEL_ERROR_ERRNO_READ_ONLY = 0x8001001E, + SCE_KERNEL_ERROR_ERRNO_CLOSED = 0x80010020, + SCE_KERNEL_ERROR_ERRNO_FILE_PATH_TOO_LONG = 0x80010024, + SCE_KERNEL_ERROR_ERRNO_FILE_PROTOCOL = 0x80010047, + SCE_KERNEL_ERROR_ERRNO_DIRECTORY_IS_NOT_EMPTY = 0x8001005A, + SCE_KERNEL_ERROR_ERRNO_TOO_MANY_SYMBOLIC_LINKS = 0x8001005C, + SCE_KERNEL_ERROR_ERRNO_FILE_ADDR_IN_USE = 0x80010062, + SCE_KERNEL_ERROR_ERRNO_CONNECTION_ABORTED = 0x80010067, + SCE_KERNEL_ERROR_ERRNO_CONNECTION_RESET = 0x80010068, + SCE_KERNEL_ERROR_ERRNO_NO_FREE_BUF_SPACE = 0x80010069, + SCE_KERNEL_ERROR_ERRNO_FILE_TIMEOUT = 0x8001006E, + SCE_KERNEL_ERROR_ERRNO_IN_PROGRESS = 0x80010077, + SCE_KERNEL_ERROR_ERRNO_ALREADY = 0x80010078, + SCE_KERNEL_ERROR_ERRNO_NO_MEDIA = 0x8001007B, + SCE_KERNEL_ERROR_ERRNO_INVALID_MEDIUM = 0x8001007C, + SCE_KERNEL_ERROR_ERRNO_ADDRESS_NOT_AVAILABLE = 0x8001007D, + SCE_KERNEL_ERROR_ERRNO_IS_ALREADY_CONNECTED = 0x8001007F, + SCE_KERNEL_ERROR_ERRNO_NOT_CONNECTED = 0x80010080, + SCE_KERNEL_ERROR_ERRNO_FILE_QUOTA_EXCEEDED = 0x80010084, + SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED = 0x8001B000, + SCE_KERNEL_ERROR_ERRNO_ADDR_OUT_OF_MAIN_MEM = 0x8001B001, + SCE_KERNEL_ERROR_ERRNO_INVALID_UNIT_NUM = 0x8001B002, + SCE_KERNEL_ERROR_ERRNO_INVALID_FILE_SIZE = 0x8001B003, + SCE_KERNEL_ERROR_ERRNO_INVALID_FLAG = 0x8001B004, + + SCE_KERNEL_ERROR_ERROR = 0x80020001, + SCE_KERNEL_ERROR_NOTIMP = 0x80020002, + SCE_KERNEL_ERROR_ILLEGAL_EXPCODE = 0x80020032, + SCE_KERNEL_ERROR_EXPHANDLER_NOUSE = 0x80020033, + SCE_KERNEL_ERROR_EXPHANDLER_USED = 0x80020034, + SCE_KERNEL_ERROR_SYCALLTABLE_NOUSED = 0x80020035, + SCE_KERNEL_ERROR_SYCALLTABLE_USED = 0x80020036, + SCE_KERNEL_ERROR_ILLEGAL_SYSCALLTABLE = 0x80020037, + SCE_KERNEL_ERROR_ILLEGAL_PRIMARY_SYSCALL_NUMBER = 0x80020038, + SCE_KERNEL_ERROR_PRIMARY_SYSCALL_NUMBER_INUSE = 0x80020039, + SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80020064, + SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80020065, + SCE_KERNEL_ERROR_CPUDI = 0x80020066, + SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80020067, + SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x80020068, + SCE_KERNEL_ERROR_ILLEGAL_INTRLEVEL = 0x80020069, + SCE_KERNEL_ERROR_ILLEGAL_ADDRESS = 0x8002006a, + SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x8002006b, + SCE_KERNEL_ERROR_ILLEGAL_STACK_ADDRESS = 0x8002006c, + SCE_KERNEL_ERROR_ALREADY_STACK_SET = 0x8002006d, + SCE_KERNEL_ERROR_NO_TIMER = 0x80020096, + SCE_KERNEL_ERROR_ILLEGAL_TIMERID = 0x80020097, + SCE_KERNEL_ERROR_ILLEGAL_SOURCE = 0x80020098, + SCE_KERNEL_ERROR_ILLEGAL_PRESCALE = 0x80020099, + SCE_KERNEL_ERROR_TIMER_BUSY = 0x8002009a, + SCE_KERNEL_ERROR_TIMER_NOT_SETUP = 0x8002009b, + SCE_KERNEL_ERROR_TIMER_NOT_INUSE = 0x8002009c, + SCE_KERNEL_ERROR_UNIT_USED = 0x800200a0, + SCE_KERNEL_ERROR_UNIT_NOUSE = 0x800200a1, + SCE_KERNEL_ERROR_NO_ROMDIR = 0x800200a2, + SCE_KERNEL_ERROR_IDTYPE_EXIST = 0x800200c8, + SCE_KERNEL_ERROR_IDTYPE_NOT_EXIST = 0x800200c9, + SCE_KERNEL_ERROR_IDTYPE_NOT_EMPTY = 0x800200ca, + SCE_KERNEL_ERROR_UNKNOWN_UID = 0x800200cb, + SCE_KERNEL_ERROR_UNMATCH_UID_TYPE = 0x800200cc, + SCE_KERNEL_ERROR_ID_NOT_EXIST = 0x800200cd, + SCE_KERNEL_ERROR_NOT_FOUND_UIDFUNC = 0x800200ce, + SCE_KERNEL_ERROR_UID_ALREADY_HOLDER = 0x800200cf, + SCE_KERNEL_ERROR_UID_NOT_HOLDER = 0x800200d0, + SCE_KERNEL_ERROR_ILLEGAL_PERM = 0x800200d1, + SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT = 0x800200d2, + SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x800200d3, + SCE_KERNEL_ERROR_OUT_OF_RANGE = 0x800200d4, + SCE_KERNEL_ERROR_MEM_RANGE_OVERLAP = 0x800200d5, + SCE_KERNEL_ERROR_ILLEGAL_PARTITION = 0x800200d6, + SCE_KERNEL_ERROR_PARTITION_INUSE = 0x800200d7, + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE = 0x800200d8, + SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED = 0x800200d9, + SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_LOCKED = 0x800200da, + SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_FAILED = 0x800200db, + SCE_KERNEL_ERROR_HEAPBLOCK_ALLOC_FAILED = 0x800200dc, + SCE_KERNEL_ERROR_HEAP_ALLOC_FAILED = 0x800200dd, + SCE_KERNEL_ERROR_ILLEGAL_CHUNK_ID = 0x800200de, + SCE_KERNEL_ERROR_NOCHUNK = 0x800200df, + SCE_KERNEL_ERROR_NO_FREECHUNK = 0x800200e0, + SCE_KERNEL_ERROR_MEMBLOCK_FRAGMENTED = 0x800200e1, + SCE_KERNEL_ERROR_MEMBLOCK_CANNOT_JOINT = 0x800200e2, + SCE_KERNEL_ERROR_MEMBLOCK_CANNOT_SEPARATE = 0x800200e3, + SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE = 0x800200e4, + SCE_KERNEL_ERROR_ILLEGAL_DEVKIT_VER = 0x800200e5, + SCE_KERNEL_ERROR_LINKERR = 0x8002012c, + SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d, + SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e, + SCE_KERNEL_ERROR_NOFILE = 0x8002012f, + SCE_KERNEL_ERROR_FILEERR = 0x80020130, + SCE_KERNEL_ERROR_MEMINUSE = 0x80020131, + SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132, + SCE_KERNEL_ERROR_ALREADY_STARTED = 0x80020133, + SCE_KERNEL_ERROR_NOT_STARTED = 0x80020134, + SCE_KERNEL_ERROR_ALREADY_STOPPED = 0x80020135, + SCE_KERNEL_ERROR_CAN_NOT_STOP = 0x80020136, + SCE_KERNEL_ERROR_NOT_STOPPED = 0x80020137, + SCE_KERNEL_ERROR_NOT_REMOVABLE = 0x80020138, + SCE_KERNEL_ERROR_EXCLUSIVE_LOAD = 0x80020139, + SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED = 0x8002013a, + SCE_KERNEL_ERROR_LIBRARY_FOUND = 0x8002013b, + SCE_KERNEL_ERROR_LIBRARY_NOTFOUND = 0x8002013c, + SCE_KERNEL_ERROR_ILLEGAL_LIBRARY = 0x8002013d, + SCE_KERNEL_ERROR_LIBRARY_INUSE = 0x8002013e, + SCE_KERNEL_ERROR_ALREADY_STOPPING = 0x8002013f, + SCE_KERNEL_ERROR_ILLEGAL_OFFSET = 0x80020140, + SCE_KERNEL_ERROR_ILLEGAL_POSITION = 0x80020141, + SCE_KERNEL_ERROR_ILLEGAL_ACCESS = 0x80020142, + SCE_KERNEL_ERROR_MODULE_MGR_BUSY = 0x80020143, + SCE_KERNEL_ERROR_ILLEGAL_FLAG = 0x80020144, + SCE_KERNEL_ERROR_CANNOT_GET_MODULELIST = 0x80020145, + SCE_KERNEL_ERROR_PROHIBIT_LOADMODULE_DEVICE = 0x80020146, + SCE_KERNEL_ERROR_PROHIBIT_LOADEXEC_DEVICE = 0x80020147, + SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE = 0x80020148, + SCE_KERNEL_ERROR_ILLEGAL_PERM_CALL = 0x80020149, + SCE_KERNEL_ERROR_CANNOT_GET_MODULE_INFORMATION = 0x8002014a, + SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_BUFFER = 0x8002014b, + SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_FILENAME = 0x8002014c, + SCE_KERNEL_ERROR_NO_EXIT_CALLBACK = 0x8002014d, + SCE_KERNEL_ERROR_MEDIA_CHANGED = 0x8002014e, + SCE_KERNEL_ERROR_CANNOT_USE_BETA_VER_MODULE = 0x8002014f, + + SCE_KERNEL_ERROR_NO_MEMORY = 0x80020190, + SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x80020191, + SCE_KERNEL_ERROR_ILLEGAL_ENTRY = 0x80020192, + SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80020193, + SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80020194, + SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020195, + SCE_KERNEL_ERROR_ILLEGAL_MASK = 0x80020196, + SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80020197, + SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80020198, + SCE_KERNEL_ERROR_UNKNOWN_SEMID = 0x80020199, + SCE_KERNEL_ERROR_UNKNOWN_EVFID = 0x8002019a, + SCE_KERNEL_ERROR_UNKNOWN_MBXID = 0x8002019b, + SCE_KERNEL_ERROR_UNKNOWN_VPLID = 0x8002019c, + SCE_KERNEL_ERROR_UNKNOWN_FPLID = 0x8002019d, + SCE_KERNEL_ERROR_UNKNOWN_MPPID = 0x8002019e, + SCE_KERNEL_ERROR_UNKNOWN_ALMID = 0x8002019f, + SCE_KERNEL_ERROR_UNKNOWN_TEID = 0x800201a0, + SCE_KERNEL_ERROR_UNKNOWN_CBID = 0x800201a1, + SCE_KERNEL_ERROR_DORMANT = 0x800201a2, + SCE_KERNEL_ERROR_SUSPEND = 0x800201a3, + SCE_KERNEL_ERROR_NOT_DORMANT = 0x800201a4, + SCE_KERNEL_ERROR_NOT_SUSPEND = 0x800201a5, + SCE_KERNEL_ERROR_NOT_WAIT = 0x800201a6, + SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x800201a7, + SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x800201a8, + SCE_KERNEL_ERROR_WAIT_CANCEL = 0x800201a9, + SCE_KERNEL_ERROR_RELEASE_WAIT = 0x800201aa, + SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x800201ab, + SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x800201ac, + SCE_KERNEL_ERROR_SEMA_ZERO = 0x800201ad, + SCE_KERNEL_ERROR_SEMA_OVF = 0x800201ae, + SCE_KERNEL_ERROR_EVF_COND = 0x800201af, + SCE_KERNEL_ERROR_EVF_MULTI = 0x800201b0, + SCE_KERNEL_ERROR_EVF_ILPAT = 0x800201b1, + SCE_KERNEL_ERROR_MBOX_NOMSG = 0x800201b2, + SCE_KERNEL_ERROR_MPP_FULL = 0x800201b3, + SCE_KERNEL_ERROR_MPP_EMPTY = 0x800201b4, + SCE_KERNEL_ERROR_WAIT_DELETE = 0x800201b5, + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK = 0x800201b6, + SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE = 0x800201b7, + SCE_KERNEL_ERROR_ILLEGAL_SPADADDR = 0x800201b8, + SCE_KERNEL_ERROR_SPAD_INUSE = 0x800201b9, + SCE_KERNEL_ERROR_SPAD_NOT_INUSE = 0x800201ba, + SCE_KERNEL_ERROR_ILLEGAL_TYPE = 0x800201bb, + SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x800201bc, + SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x800201bd, + SCE_KERNEL_ERROR_UNKNOWN_VTID = 0x800201be, + SCE_KERNEL_ERROR_ILLEGAL_VTID = 0x800201bf, + SCE_KERNEL_ERROR_ILLEGAL_KTLSID = 0x800201c0, + SCE_KERNEL_ERROR_KTLS_FULL = 0x800201c1, + SCE_KERNEL_ERROR_KTLS_BUSY = 0x800201c2, + SCE_KERNEL_ERROR_MUTEX_NOT_FOUND = 0x800201c3, + SCE_KERNEL_ERROR_MUTEX_LOCKED = 0x800201c4, + SCE_KERNEL_ERROR_MUTEX_UNLOCKED = 0x800201c5, + SCE_KERNEL_ERROR_MUTEX_LOCK_OVERFLOW = 0x800201c6, + SCE_KERNEL_ERROR_MUTEX_UNLOCK_UNDERFLOW = 0x800201c7, + SCE_KERNEL_ERROR_MUTEX_RECURSIVE_NOT_ALLOWED = 0x800201c8, + SCE_KERNEL_ERROR_MESSAGEBOX_DUPLICATE_MESSAGE = 0x800201c9, + SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND = 0x800201ca, + SCE_KERNEL_ERROR_LWMUTEX_LOCKED = 0x800201cb, + SCE_KERNEL_ERROR_LWMUTEX_UNLOCKED = 0x800201cc, + SCE_KERNEL_ERROR_LWMUTEX_LOCK_OVERFLOW = 0x800201cd, + SCE_KERNEL_ERROR_LWMUTEX_UNLOCK_UNDERFLOW = 0x800201ce, + SCE_KERNEL_ERROR_LWMUTEX_RECURSIVE_NOT_ALLOWED = 0x800201cf, + + SCE_KERNEL_ERROR_PM_INVALID_PRIORITY = 0x80020258, + SCE_KERNEL_ERROR_PM_INVALID_DEVNAME = 0x80020259, + SCE_KERNEL_ERROR_PM_UNKNOWN_DEVNAME = 0x8002025a, + SCE_KERNEL_ERROR_PM_PMINFO_REGISTERED = 0x8002025b, + SCE_KERNEL_ERROR_PM_PMINFO_UNREGISTERED = 0x8002025c, + SCE_KERNEL_ERROR_PM_INVALID_MAJOR_STATE = 0x8002025d, + SCE_KERNEL_ERROR_PM_INVALID_REQUEST = 0x8002025e, + SCE_KERNEL_ERROR_PM_UNKNOWN_REQUEST = 0x8002025f, + SCE_KERNEL_ERROR_PM_INVALID_UNIT = 0x80020260, + SCE_KERNEL_ERROR_PM_CANNOT_CANCEL = 0x80020261, + SCE_KERNEL_ERROR_PM_INVALID_PMINFO = 0x80020262, + SCE_KERNEL_ERROR_PM_INVALID_ARGUMENT = 0x80020263, + SCE_KERNEL_ERROR_PM_ALREADY_TARGET_PWRSTATE = 0x80020264, + SCE_KERNEL_ERROR_PM_CHANGE_PWRSTATE_FAILED = 0x80020265, + SCE_KERNEL_ERROR_PM_CANNOT_CHANGE_DEVPWR_STATE = 0x80020266, + SCE_KERNEL_ERROR_PM_NO_SUPPORT_DEVPWR_STATE = 0x80020267, + + SCE_KERNEL_ERROR_DMAC_REQUEST_FAILED = 0x800202bc, + SCE_KERNEL_ERROR_DMAC_REQUEST_DENIED = 0x800202bd, + SCE_KERNEL_ERROR_DMAC_OP_QUEUED = 0x800202be, + SCE_KERNEL_ERROR_DMAC_OP_NOT_QUEUED = 0x800202bf, + SCE_KERNEL_ERROR_DMAC_OP_RUNNING = 0x800202c0, + SCE_KERNEL_ERROR_DMAC_OP_NOT_ASSIGNED = 0x800202c1, + SCE_KERNEL_ERROR_DMAC_OP_TIMEOUT = 0x800202c2, + SCE_KERNEL_ERROR_DMAC_OP_FREED = 0x800202c3, + SCE_KERNEL_ERROR_DMAC_OP_USED = 0x800202c4, + SCE_KERNEL_ERROR_DMAC_OP_EMPTY = 0x800202c5, + SCE_KERNEL_ERROR_DMAC_OP_ABORTED = 0x800202c6, + SCE_KERNEL_ERROR_DMAC_OP_ERROR = 0x800202c7, + SCE_KERNEL_ERROR_DMAC_CHANNEL_RESERVED = 0x800202c8, + SCE_KERNEL_ERROR_DMAC_CHANNEL_EXCLUDED = 0x800202c9, + SCE_KERNEL_ERROR_DMAC_PRIVILEGE_ADDRESS = 0x800202ca, + SCE_KERNEL_ERROR_DMAC_NO_ENOUGHSPACE = 0x800202cb, + SCE_KERNEL_ERROR_DMAC_CHANNEL_NOT_ASSIGNED = 0x800202cc, + SCE_KERNEL_ERROR_DMAC_CHILD_OPERATION = 0x800202cd, + SCE_KERNEL_ERROR_DMAC_TOO_MUCH_SIZE = 0x800202ce, + SCE_KERNEL_ERROR_DMAC_INVALID_ARGUMENT = 0x800202cf, + + SCE_KERNEL_ERROR_MFILE = 0x80020320, + SCE_KERNEL_ERROR_NODEV = 0x80020321, + SCE_KERNEL_ERROR_XDEV = 0x80020322, + SCE_KERNEL_ERROR_BADF = 0x80020323, + SCE_KERNEL_ERROR_INVAL = 0x80020324, + SCE_KERNEL_ERROR_UNSUP = 0x80020325, + SCE_KERNEL_ERROR_ALIAS_USED = 0x80020326, + SCE_KERNEL_ERROR_CANNOT_MOUNT = 0x80020327, + SCE_KERNEL_ERROR_DRIVER_DELETED = 0x80020328, + SCE_KERNEL_ERROR_ASYNC_BUSY = 0x80020329, + SCE_KERNEL_ERROR_NOASYNC = 0x8002032a, + SCE_KERNEL_ERROR_REGDEV = 0x8002032b, + SCE_KERNEL_ERROR_NOCWD = 0x8002032c, + SCE_KERNEL_ERROR_NAMETOOLONG = 0x8002032d, + SCE_KERNEL_ERROR_NXIO = 0x800203e8, + SCE_KERNEL_ERROR_IO = 0x800203e9, + SCE_KERNEL_ERROR_NOMEM = 0x800203ea, + SCE_KERNEL_ERROR_STDIO_NOT_OPENED = 0x800203eb, + + SCE_KERNEL_ERROR_CACHE_ALIGNMENT = 0x8002044c, + SCE_KERNEL_ERROR_ERRORMAX = 0x8002044d, }; // If you add to this, make sure to check KernelObjectPool::CreateByIDType(). @@ -467,6 +543,7 @@ struct KernelStats { }; extern KernelStats kernelStats; +extern u32 registeredExitCbId; void Register_ThreadManForUser(); void Register_LoadExecForUser(); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index cf3c6ce7b2..c369ac8b24 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -512,8 +512,8 @@ int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 // Alignment is only allowed for powers of 2. if ((type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) && ((addr & (addr - 1)) != 0 || addr == 0)) { - WARN_LOG_REPORT(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid alignment %x", SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE, addr); - return SCE_ERROR_KERNEL_ILLEGAL_ALIGNMENT_SIZE; + WARN_LOG_REPORT(HLE, "%08x=sceKernelAllocPartitionMemory(): invalid alignment %x", SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, addr); + return SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE; } PartitionMemoryBlock *block = new PartitionMemoryBlock(&userMemory, name, size, (MemblockType)type, addr); @@ -1161,11 +1161,25 @@ int sceKernelReferVplStatus(SceUID uid, u32 infoPtr) // TODO: Make proper kernel objects for these instead of using the UID as a pointer. + + u32 AllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAddr) { // Just support allocating a block in the user region. + if (paramsAddr) { + u32 length = Memory::Read_U32(paramsAddr); + if (length != 4) { + WARN_LOG(HLE, "AllockMemoryBlock(SysMemUserForUser_FE707FDF) : unknown parameters with length %d", length); + } + } + if (type < 0 || type > 1) { + return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE; + } u32 blockPtr = userMemory.Alloc(size, type == 1, pname); + if (!blockPtr) { + return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; + } INFO_LOG(HLE,"%08x=AllocMemoryBlock(SysMemUserForUser_FE707FDF)(%s, %i, %08x, %08x)", blockPtr, pname, type, size, paramsAddr); // Create a UID object??? Nah, let's just us the UID itself (hack!) @@ -1175,13 +1189,21 @@ u32 AllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAddr) { u32 FreeMemoryBlock(u32 uid) { INFO_LOG(HLE, "FreeMemoryBlock(%08x)", uid); - userMemory.Free(uid); + u32 blockPtr = userMemory.GetBlockStartFromAddress(uid); + if (!blockPtr) { + return SCE_KERNEL_ERROR_UNKNOWN_UID; + } + userMemory.Free(blockPtr); return 0; } u32 GetMemoryBlockPtr(u32 uid, u32 addr) { INFO_LOG(HLE, "GetMemoryBlockPtr(%08x, %08x)", uid, addr); - Memory::Write_U32(uid, addr); + u32 blockPtr = userMemory.GetBlockStartFromAddress(uid); + if (!blockPtr) { + return SCE_KERNEL_ERROR_UNKNOWN_UID; + } + Memory::Write_U32(blockPtr, addr); return 0; } @@ -1475,7 +1497,7 @@ const HLEFunction SysMemUserForUser[] = { // Obscure raw block API {0xDB83A952,WrapU_UU,"SysMemUserForUser_DB83A952"}, // GetMemoryBlockAddr {0x50F61D8A,WrapU_U,"SysMemUserForUser_50F61D8A"}, // FreeMemoryBlock - {0xFE707FDF,WrapU_CUUU,"SysMemUserForUser_FE707FDF"}, // AllocMemoryBlock + {0xFE707FDF,WrapU_CUUU,"SCE_KERNEL_ERROR_INVAL"}, // AllocMemoryBlock {0xD8DE5C1E,WrapU_V,"SysMemUserForUser_D8DE5C1E"} }; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index e6eecdde5f..41cbf5a5ac 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -3241,3 +3241,36 @@ void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) __KernelChangeThreadState(t, newStatus); } +int hleLoadExecForUser_362A956B() +{ + u32 error; + Callback *cb = kernelObjects.Get(registeredExitCbId, error); + if (!cb) { + WARN_LOG(HLE, "LoadExecForUser_362A956B() : registeredExitCbId not found 0x%x", registeredExitCbId); + return SCE_KERNEL_ERROR_UNKNOWN_CBID; + } + int cbArg = cb->nc.commonArgument; + if (!Memory::IsValidAddress(cbArg)) { + WARN_LOG(HLE, "LoadExecForUser_362A956B() : invalid address for cbArg (0x%08X)", cbArg); + return SCE_KERNEL_ERROR_ILLEGAL_ADDR; + } + int unknown1 = Memory::Read_U32(cbArg - 8); + if (unknown1 < 0 || unknown1 >= 4) { + WARN_LOG(HLE, "LoadExecForUser_362A956B() : invalid value unknown1 (0x%08X)", unknown1); + return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; + } + int parameterArea = Memory::Read_U32(cbArg - 4); + if (!Memory::IsValidAddress(parameterArea)) { + WARN_LOG(HLE, "LoadExecForUser_362A956B() : invalid address for parameterArea on userMemory (0x%08X)", parameterArea); + return SCE_KERNEL_ERROR_ILLEGAL_ADDR; + } + + int size = Memory::Read_U32(parameterArea); + if (size < 12) { + WARN_LOG(HLE, "LoadExecForUser_362A956B() : invalid parameterArea size %d", size); + return SCE_KERNEL_ERROR_ILLEGAL_SIZE; + } + Memory::Write_U32(0, parameterArea + 4); + Memory::Write_U32(-1, parameterArea + 8); + return 0; +} diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 063919344f..18b72d6675 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -307,3 +307,4 @@ struct DebugThreadInfo std::vector GetThreadsInfo(); void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus); +int hleLoadExecForUser_362A956B(); \ No newline at end of file From dd2fbd3401feb250dfdac6b41764df6a4631a386 Mon Sep 17 00:00:00 2001 From: nachume Date: Sat, 4 May 2013 20:46:41 +0900 Subject: [PATCH 07/16] typo SysMemUserForUser_FE707FDF. --- Core/HLE/sceKernelMemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index c369ac8b24..a1c2de341b 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -1497,7 +1497,7 @@ const HLEFunction SysMemUserForUser[] = { // Obscure raw block API {0xDB83A952,WrapU_UU,"SysMemUserForUser_DB83A952"}, // GetMemoryBlockAddr {0x50F61D8A,WrapU_U,"SysMemUserForUser_50F61D8A"}, // FreeMemoryBlock - {0xFE707FDF,WrapU_CUUU,"SCE_KERNEL_ERROR_INVAL"}, // AllocMemoryBlock + {0xFE707FDF,WrapU_CUUU,"SysMemUserForUser_FE707FDF"}, // AllocMemoryBlock {0xD8DE5C1E,WrapU_V,"SysMemUserForUser_D8DE5C1E"} }; From 34b1c24dafda09f015e5c20048e8a71c0680cdc1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 4 May 2013 17:46:44 +0200 Subject: [PATCH 08/16] Buildfix for some new compiler --- Core/HLE/sceAtrac.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 36af9dbb14..13753b28dd 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -143,7 +143,7 @@ struct Atrac { p.Do(first); p.Do(atracBufSize); p.Do(codeType); - u32 data_buf_value = (u32)data_buf; + u32 data_buf_value = (u32)(intptr_t)data_buf; p.Do(data_buf_value); if (data_buf) p.DoArray(data_buf, first.filesize); From 1d6c36585e612e354efe4be3a351b7589acca9ec Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 4 May 2013 17:56:32 +0200 Subject: [PATCH 09/16] Update native and lang --- lang | 2 +- native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lang b/lang index 2a6b957902..a8d260acb3 160000 --- a/lang +++ b/lang @@ -1 +1 @@ -Subproject commit 2a6b9579029002d347aa11bc89cb5e44e1c68dbe +Subproject commit a8d260acb367e922c7f4792ab134c8a02052c854 diff --git a/native b/native index 203e3c9903..3edf239571 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 203e3c9903c7bece68ef42ea05261edeb5d1b7eb +Subproject commit 3edf239571e8132eed1fa6baaf7b8e269d889103 From 0613e4b20d24152821f5b6ffff318a1c9594ad5c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 4 May 2013 09:28:11 -0700 Subject: [PATCH 10/16] Correct savestate logic in atrac. Not 100% sure it works though, it doesn't crash and games run. USE_FFMPEG builds with this change. --- Core/HLE/sceAtrac.cpp | 189 +++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 103 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 13753b28dd..07ee9645f0 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -71,6 +71,7 @@ struct InputBuffer { }; struct Atrac; +int __AtracSetContext(Atrac *atrac, u32 buffer, u32 bufferSize); int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize); struct AtracLoopInfo { @@ -85,7 +86,7 @@ struct AtracLoopInfo { struct Atrac { Atrac() : decodePos(0), decodeEnd(0), loopNum(0), atracChannels(2), atracBitrate(64), atracBytesPerFrame(0), atracBufSize(0), currentSample(0), - endSample(-1), loopinfoNum(0), firstSampleoffset(0),data_buf(0), + endSample(-1), loopinfoNum(0), firstSampleoffset(0), data_buf(0), atracOutputChannels(2), atracID(-1) { memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(second)); @@ -102,51 +103,28 @@ struct Atrac { #ifdef USE_FFMPEG ReleaseFFMPEGContext(); #endif // USE_FFMPEG - if (data_buf) delete [] data_buf; + if (data_buf) + delete [] data_buf; } void DoState(PointerWrap &p) { p.Do(atracChannels); p.Do(atracOutputChannels); - if (atracID == -1) { - // loading state - p.Do(atracID); - p.Do(first); - p.Do(atracBufSize); - p.Do(codeType); - u32 data_buf_value; - p.Do(data_buf_value); - if (data_buf_value) { + p.Do(atracID); + p.Do(first); + p.Do(atracBufSize); + p.Do(codeType); + u32 has_data_buf = data_buf != NULL; + p.Do(has_data_buf); + if (has_data_buf) { + if (p.mode == p.MODE_READ) { data_buf = new u8[first.filesize]; - p.DoArray(data_buf, first.filesize); - } - InputBuffer temp = first; - if (first.addr) { - int size = std::min(first.size, atracBufSize); - first.size = size; - if (data_buf) - Memory::Memcpy(first.addr, data_buf, size); - u8* temp_buf = data_buf; - data_buf = 0; - _AtracSetData(this, first.addr, atracBufSize); - // restore the state - first = temp; - if (data_buf) - delete [] data_buf; - data_buf = temp_buf; } + p.DoArray(data_buf, first.filesize); } - else { - // saving state - p.Do(atracID); - p.Do(first); - p.Do(atracBufSize); - p.Do(codeType); - u32 data_buf_value = (u32)(intptr_t)data_buf; - p.Do(data_buf_value); - if (data_buf) - p.DoArray(data_buf, first.filesize); + if (p.mode == p.MODE_READ && data_buf != NULL) { + __AtracSetContext(this, first.addr, atracBufSize); } p.Do(second); @@ -272,9 +250,6 @@ void __AtracInit() { } void __AtracDoState(PointerWrap &p) { -#ifdef USE_FFMPEG - p.Do(Memory::lastestAccessFile); -#endif // _USE_FFMPEG p.Do(atracMap); p.Do(nextAtracID); @@ -815,6 +790,76 @@ int64_t _AtracSeekbuffer(void *opaque, int64_t offset, int whence) #endif // USE_FFMPEG +int __AtracSetContext(Atrac *atrac, u32 buffer, u32 bufferSize) +{ +#ifdef USE_FFMPEG + u8* tempbuf = (u8*)av_malloc(atrac->atracBufSize); + + atrac->pFormatCtx = avformat_alloc_context(); + atrac->pAVIOCtx = avio_alloc_context(tempbuf, atrac->atracBufSize, 0, (void*)atrac, _AtracReadbuffer, NULL, _AtracSeekbuffer); + atrac->pFormatCtx->pb = atrac->pAVIOCtx; + + int ret; + // Load audio buffer + if((ret = avformat_open_input((AVFormatContext**)&atrac->pFormatCtx, NULL, NULL, NULL)) != 0) { + ERROR_LOG(HLE, "avformat_open_input: Cannot open input %d", ret); + return -1; + } + + if((ret = avformat_find_stream_info(atrac->pFormatCtx, NULL)) < 0) { + ERROR_LOG(HLE, "avformat_find_stream_info: Cannot find stream information %d", ret); + return -1; + } + + AVCodec *pCodec; + // select the audio stream + ret = av_find_best_stream(atrac->pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0); + if (ret < 0) { + ERROR_LOG(HLE, "av_find_best_stream: Cannot find a audio stream in the input file %d", ret); + return -1; + } + atrac->audio_stream_index = ret; + atrac->pCodecCtx = atrac->pFormatCtx->streams[atrac->audio_stream_index]->codec; + + // open codec + if ((ret = avcodec_open2(atrac->pCodecCtx, pCodec, NULL)) < 0) { + ERROR_LOG(HLE, "avcodec_open2: Cannot open audio decoder %d", ret); + return -1; + } + + int wanted_channels = atrac->atracOutputChannels; + int wanted_channel_layout = av_get_default_channel_layout(wanted_channels); + int dec_channel_layout = av_get_default_channel_layout(atrac->atracChannels); + + atrac->pSwrCtx = + swr_alloc_set_opts + ( + NULL, + wanted_channel_layout, + AV_SAMPLE_FMT_S16, + atrac->pCodecCtx->sample_rate, + dec_channel_layout, + atrac->pCodecCtx->sample_fmt, + atrac->pCodecCtx->sample_rate, + 0, + NULL + ); + if (!atrac->pSwrCtx) { + ERROR_LOG(HLE, "swr_alloc_set_opts: Could not allocate resampler context %d", ret); + return -1; + } + if ((ret = swr_init(atrac->pSwrCtx)) < 0) { + ERROR_LOG(HLE, "swr_init: Failed to initialize the resampling context %d", ret); + return -1; + } + + // alloc audio frame + atrac->pFrame = avcodec_alloc_frame(); +#endif + + return 0; +} + int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) { atrac->atracBufSize = bufferSize; @@ -835,70 +880,8 @@ int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) atrac->data_buf = new u8[atrac->first.filesize]; Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); - u8* tempbuf = (u8*)av_malloc(atrac->atracBufSize); - atrac->pFormatCtx = avformat_alloc_context(); - atrac->pAVIOCtx = avio_alloc_context(tempbuf, atrac->atracBufSize, 0, (void*)atrac, _AtracReadbuffer, NULL, _AtracSeekbuffer); - atrac->pFormatCtx->pb = atrac->pAVIOCtx; - - int ret; - // Load audio buffer - if((ret = avformat_open_input((AVFormatContext**)&atrac->pFormatCtx, NULL, NULL, NULL)) != 0) { - ERROR_LOG(HLE, "avformat_open_input: Cannot open input %d", ret); - return -1; - } - - if((ret = avformat_find_stream_info(atrac->pFormatCtx, NULL)) < 0) { - ERROR_LOG(HLE, "avformat_find_stream_info: Cannot find stream information %d", ret); - return -1; - } - - AVCodec *pCodec; - // select the audio stream - ret = av_find_best_stream(atrac->pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0); - if (ret < 0) { - ERROR_LOG(HLE, "av_find_best_stream: Cannot find a audio stream in the input file %d", ret); - return -1; - } - atrac->audio_stream_index = ret; - atrac->pCodecCtx= atrac->pFormatCtx->streams[atrac->audio_stream_index]->codec; - - // open codec - if ((ret = avcodec_open2(atrac->pCodecCtx, pCodec, NULL)) < 0) { - ERROR_LOG(HLE, "avcodec_open2: Cannot open audio decoder %d", ret); - return -1; - } - - int wanted_channels = atrac->atracOutputChannels; - int wanted_channel_layout = av_get_default_channel_layout(wanted_channels); - int dec_channel_layout = av_get_default_channel_layout(atrac->atracChannels); - - atrac->pSwrCtx = - swr_alloc_set_opts - ( - NULL, - wanted_channel_layout, - AV_SAMPLE_FMT_S16, - atrac->pCodecCtx->sample_rate, - dec_channel_layout, - atrac->pCodecCtx->sample_fmt, - atrac->pCodecCtx->sample_rate, - 0, - NULL - ); - if (!atrac->pSwrCtx) { - ERROR_LOG(HLE, "swr_alloc_set_opts: Could not allocate resampler context %d", ret); - return -1; - } - if ((ret = swr_init(atrac->pSwrCtx)) < 0) { - ERROR_LOG(HLE, "swr_init: Failed to initialize the resampling context %d", ret); - return -1; - } - - // alloc audio frame - atrac->pFrame = avcodec_alloc_frame(); - - return 0; + return __AtracSetContext(atrac, buffer, bufferSize); } #endif // _USE_FFMPEG From 368e5fe7d865ea62f9cb1646d697f32d11b76f5f Mon Sep 17 00:00:00 2001 From: raven02 Date: Sun, 5 May 2013 00:31:33 +0800 Subject: [PATCH 11/16] Add ffmpeg as submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitmodules b/.gitmodules index 45fe74f00a..a91aa56767 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "lang"] path = lang url = git://github.com/hrydgard/ppsspp-lang.git +[submodule "ffmpeg"] + path = ffmpeg + url = git://github.com/hrydgard/ppsspp-ffmpeg.git From a0e6917ee829233bff8afa4b5a17f37c6dd05213 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 4 May 2013 13:23:50 -0700 Subject: [PATCH 12/16] If unspecified, default normal to 0, 0, 1. Fixes Trails in the Sky buttons and improves Kingdom Hearts lighting. --- GPU/GLES/TransformPipeline.cpp | 2 +- GPU/GLES/VertexShaderGenerator.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index aa2a054219..881ccfeb67 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -518,7 +518,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( // We do software T&L for now float out[3], norm[3]; float pos[3], nrm[3]; - Vec3 normal(0, 0, 0); + Vec3 normal(0, 0, 1); reader.ReadPos(pos); if (reader.hasNormal()) reader.ReadNrm(nrm); diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index 6712c62a91..14997df488 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -165,8 +165,6 @@ void GenerateVertexShader(int prim, char *buffer) { int shadeLight0 = gstate.getUVGenMode() == 2 ? gstate.getUVLS0() : -1; int shadeLight1 = gstate.getUVGenMode() == 2 ? gstate.getUVLS1() : -1; for (int i = 0; i < 4; i++) { - if (!hasNormal) - continue; if (i == shadeLight0 || i == shadeLight1) doLight[i] = LIGHT_SHADE; if ((gstate.lightingEnable & 1) && (gstate.lightEnable[i] & 1)) @@ -293,10 +291,14 @@ void GenerateVertexShader(int prim, char *buffer) { WRITE(p, " vec3 worldpos = (u_world * vec4(a_position.xyz, 1.0)).xyz;\n"); if (hasNormal) WRITE(p, " vec3 worldnormal = (u_world * vec4(a_normal, 0.0)).xyz;\n"); + else + WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } else { WRITE(p, " vec3 worldpos = vec3(0.0);\n"); if (hasNormal) WRITE(p, " vec3 worldnormal = vec3(0.0);\n"); + else + WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); int numWeights = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f}; From d053d3c8b459decab71c29efd2aa024cd1b0f84a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 4 May 2013 23:21:06 +0200 Subject: [PATCH 13/16] Windows Cursor fixes: Show mouse cursor in menu in fullscreen. Remove ClipCursor calls, not necessary. --- Windows/WindowsHost.cpp | 2 ++ Windows/WndMainWindow.cpp | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index c414e440ac..73d4387cb5 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -18,6 +18,7 @@ #include "Core/Core.h" #include "Core/Config.h" #include "Core/CoreParameter.h" +#include "Core/System.h" #include "EmuThread.h" #include "DSoundStream.h" #include "WindowsHost.h" @@ -127,6 +128,7 @@ void WindowsHost::SetDebugMode(bool mode) disasmWindow[i]->SetDebugMode(mode); } +extern BOOL g_bFullScreen; void WindowsHost::PollControllers(InputState &input_state) { diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index e35320d38a..5a52b35c60 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -42,11 +42,12 @@ #define ENABLE_TOUCH 0 -static BOOL g_bFullScreen = FALSE; +BOOL g_bFullScreen = FALSE; static RECT g_normalRC = {0}; extern InputState input_state; - +#define TIMER_CURSORUPDATE 1 +#define CURSORUPDATE_INTERVAL_MS 500 extern unsigned short analog_ctrl_map[]; extern unsigned int key_pad_map[]; extern const char * getVirtualKeyName(unsigned char key); @@ -200,6 +201,7 @@ namespace MainWindow hwndMain = CreateWindowEx(0,szWindowClass, "", style, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL); + SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0); SetPlaying(0); if (!hwndMain) return FALSE; @@ -233,6 +235,7 @@ namespace MainWindow #endif SetFocus(hwndMain); + SetFocus(hwndDisplay); return TRUE; } @@ -388,6 +391,18 @@ namespace MainWindow ResizeDisplay(); break; + case WM_TIMER: + // Hack: Take the opportunity to also show/hide the mouse cursor in fullscreen mode. + if (g_bFullScreen && globalUIState == UISTATE_INGAME) { + ShowCursor(FALSE); + SetCursor(0); + } else { + ShowCursor(TRUE); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + SetTimer(hWnd, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0); + return 0; + case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); @@ -1112,7 +1127,7 @@ namespace MainWindow { ShowCursor(TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); - ClipCursor(NULL); + // put caption and border styles back DWORD dwOldStyle = ::GetWindowLong(hWnd, GWL_STYLE); DWORD dwNewStyle = dwOldStyle | WS_CAPTION | WS_THICKFRAME; @@ -1138,7 +1153,7 @@ namespace MainWindow { ShowCursor(FALSE); SetCursor(NULL); - ClipCursor(&g_normalRC); + // keep in mind normal window rectangle ::GetWindowRect(hWnd, &g_normalRC); From e254dbf6aad118807aef32bf80c4025371f44751 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 4 May 2013 23:54:22 +0200 Subject: [PATCH 14/16] Delete junk from Windows/resource.h . More cursor stuff. --- Windows/WndMainWindow.cpp | 10 +++++----- Windows/resource.h | Bin 164358 -> 21940 bytes 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 5a52b35c60..b2e1767195 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -47,7 +47,7 @@ static RECT g_normalRC = {0}; extern InputState input_state; #define TIMER_CURSORUPDATE 1 -#define CURSORUPDATE_INTERVAL_MS 500 +#define CURSORUPDATE_INTERVAL_MS 50 extern unsigned short analog_ctrl_map[]; extern unsigned int key_pad_map[]; extern const char * getVirtualKeyName(unsigned char key); @@ -395,7 +395,6 @@ namespace MainWindow // Hack: Take the opportunity to also show/hide the mouse cursor in fullscreen mode. if (g_bFullScreen && globalUIState == UISTATE_INGAME) { ShowCursor(FALSE); - SetCursor(0); } else { ShowCursor(TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); @@ -760,7 +759,8 @@ namespace MainWindow disasmWindow[0] = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); DialogManager::AddDlg(disasmWindow[0]); disasmWindow[0]->Show(g_Config.bShowDebuggerOnLoad); - if (g_Config.bFullScreen) _ViewFullScreen(hWnd); + if (g_Config.bFullScreen) + _ViewFullScreen(hWnd); memoryWindow[0] = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); DialogManager::AddDlg(memoryWindow[0]); if (disasmWindow[0]) @@ -1151,8 +1151,8 @@ namespace MainWindow void _ViewFullScreen(HWND hWnd) { - ShowCursor(FALSE); - SetCursor(NULL); + if (globalUIState == UISTATE_INGAME) + ShowCursor(FALSE); // keep in mind normal window rectangle ::GetWindowRect(hWnd, &g_normalRC); diff --git a/Windows/resource.h b/Windows/resource.h index d581544bcbb7826669859bd04857267a87438969..75222449aebf20b5edafcd47d4b68d2c07c2e22a 100644 GIT binary patch delta 899 zcmYL|O=uHQ5XYHkNY`aqLe;d^8e>{ZC`F12_7FWRH;)3ugym_-XuB%TU zgZNv&J+TL4EfB{3W|%2uY5{z*0j#^5LBYaC$TGBVlCU!@;iC_0E$p#b*VZP(JzFI7 zw?h_JGeW`4R-)P=I(F=^&~PLI2Hx6E=9O)b<+`JnLB*R<7;Ixo}fv2f=iQJSNMdT!nqA{68*YroGWBC*$xmz?(6Hzlk%$Mw(rPG}{Q!gPW=pS1i$p<;FM-Li>XJ;kSCjDU6N8H7&vI|fFEGvG!dIz@eUni2 zfp$y7 zak@!(zrzJZhPu{^B)%SiR_y8#-u^ky4Ut@jQ-)BTkSSJ#yZE}3KO&4yDxje?DiY4* IHIWzp01cKS?*IS* literal 164358 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 ?f{Cs1ZKin6hZtS$IwsSv-;k zLH5RL({G0B-rJSq>nj0!sJ6zNSpm&!`*8J8wQ3xV$;|knAd~CL$IriwQMJY!-wP|K z4m1Co@sY+a#?~5dlQ%Lh=F5$7`Gw0y4vHdpY$mraQEfFgJfOm~wnpfSQ-;c%CQHHi!CCdMZ0U;58Mhd@U5$Nnz{x%KSR!mSHh#wX zzEUyOT8+&LKGQ*a%Cajls;|Z->n?8wO=fmBL*%;=FUX6tn!@(dBT`YnfJSs=0b;66 zqv0K@YWl2<^@vvgK1Ri!l2?~T|Gu1|i@CC`mO4^>6r*Z2_NBTF>l)+RYHZCtJcF91 z@v)Dftv8PEqm_V!RoLVuxEJRSiYJ1XI&-%XzO9tT-l)EY z>~JqKa{c(lo@9)#$iwxm>0m?1KS%iON@=QXigXqL3H+RoDyDdupd=4K;;t8aIumgR> z_L~vDDn#s5xm{~G)^XfP__2&`S9()jud#^ni?H!)`dpymvhENF?KuFE7;piC;s^J67OIQu=HC$dMn`#n%AG~1&gmt7bBGe++WRU!Q-EB*zJgZEv@Ea<<7dPiMW4ne;9;WTZ zr8h@@J$-Mjw5(v;E=P6$W{cLItzd6^Eb*%8wxs7j$_cJuXZ?iCQB@S&2Ux>Kw!JS8 zSPS)kvW*b)V6HBCYpO1J_pAZt zbK)5)wAC5*d=%<$d#G0JyehMZimxJcR@}Q)sBzlk9_n^SYuhgyIU4T*8>6b)c|0pE znTfGg?Zoq0uLQsmm&X|2>XPgagXWV(cy`u+GnL60m8{3dPrEg}DxOX|HsiAx)#{Rr zm1vb`Pjo!S{Nfa&!eQ;TOr3gtKg}4G>Ynlq>c)IKMWH`MjLIz2dW&rZ&i^tyicz<9 zGRwJTNcDFys&>ug>9OIaui2Yrl$#ZHj7t5-E1NYHbH_2N>OaIP$7(<^s_jOqOhTTI zj;J5aUBl;nQ1rYa9s6h^Le{l0zH&kM26)hl+GezGjUV%7o14?F?94z`3RnaSLn`S(kP}`!){~Jk>9?CU9T&m8kYAt=Gf+KZY7&a7}*BU`@M-^ z#}XLD0}sou|6JZ?vzNF1l^C_{wZng2vy8Vpp0atL<{z#h_fXqjJM7I$zg>(f?~`2~ zF6p(4vE|1R4Qt-5`f@R<{5U*BAFDYJPEvu4#mHM{*^f#}<)FFG99`f}E5x1Ue(l^(5HX$jg2KkXjUI7HnszI;XeG^KNVe1t_ujy@M%)M>q zxqp`t{+ggg&m-$a!Ui7i)9TNDi(}AT_{@xf`gm#z`^O{RST7QBnDU!wR`fY@ zp^t0d%;KvTiM*k9?`6Njw?$vFjv%U+%;T$<=ki{gczn?W^hH=N3>Er%F9)Nu_c`K^ z^$JlXV82W%$@nX9rC*))yN&RzSBSbM@`W| z3dQ4Ky+W2RV3mhj$l2GozTP$`a5$KrMt!FF8+JokaGATsWGX>ve5+<$l}TO0N!jgimd5 zWz=zEzDX>XTiI!IEAc*lMl+u)Jn{SoxXj#mZy&>7!)|jFqa8PMY|ByXSLxDshi}e! zQZtgBXTJrbT0H4-+mN@iK7*SfTiwz;0{mFy8|yS)&uHV=_o3Q6h(GJ>(N|#}M7f1_ zebvg_E;WiVwklf|ug=oxzY{hb>EqXRoi%^^iw-LO`mu_RD357X{EOUPRdVXjIy#C` ziGO8~X;2U-xo-t>o5nMfZqlt?e)MJmz2Y*S%|*q-}L5`6qk`BJG)q!wPn5 zf0^6fsS?q?f?Zogdf)2v6$=@Uz?Mr}4Tz>ftM+p3D^IeuzT`n8?%1^z?AH3uTF5z` zY^^W88hj$!(CT!pQ$Ip?WPPJfxMSF@^(C@E_VJ+5i;Sz`@|p9SEVfp$;Tda1W&PLr z@z>LqW@QDaD2}mZX*}1g=rE_U{#Mvnnm)cP4Ks3mwNQ+TRI!V?zX`IYX?z@`%F^Iv zlb0ByY=04>Vrf2QLw=+Uikl`Xc7{mM5;~=!BzYrPvOOMut&) zGb}?)*J!A!nbY)v7vEzpC@ykMbu$t6Jxcv};>)tRoo5w4*zrRy7}+8px3u zB#O~|ef+)Vo6q^gsAxV`rykXOF{(5lZ=-r%@YmlF9;2f97$+Nt)z27Jnvc$MV#D>3 zi&0(k)qc!8#gc{?dppZp&Bv-`XImh_)rI0tdwCbyUGyJid zKAD$SpE|Hsq(}6}vST%Ua$pb7^%N|)<;=&G!4Yq~rms#q?t=fpeW@*vX6*>yYWidx zSqlKR)`5?Z=VagU*$h$hw?ptGOc30`C@IWw{^O?GvrTsz1pb3h)chw9fy{K1Y= zi8T$M^&dE@AC2&>rZ0OzzbT_i1(ThknFo#)9gXm<7Jkh3jrrf!!dG)xv-pev7It-4 zjxm1i%j3V%R}t~KcTN0{bwlpU<3Ex&=^-2KbJ%r+KA+R>`NVVg+{O=75qYLIYVhY< z;Z+?!um<2+nSoenw1>v5T|c;n-TLzMdeP6s-pbOhPBTY2HeNiEqZ&w-IciaL_HE+D zqZ{uf@)6dujni^@JMsD)W@j!OJud4P4_>}pjw}k>2&-) zz1=wPZ!&CgmpCS-+I31hL+tNIpV{c;I)&V^s;a$vtYEj)YxNS**uArdu-9EH*gn72 zfdcM$e#iXY@?@L6tk2s{7jbEg?pAjYp%IVJUl!$La_l+-FkY**9n%{{0{{8+Pp5w= z`)U7t`lYN1|6}?5qIia^{bKZv^i`X_L%#2Z_-K$d551+lN4Mz^C|B>{T27>gixyGu zI{t&+m(fy`pY?D}Gchw1rz;ye+t(o3fX}}T`Rsb6-E|_T*1r{gjJ=&RZJu%V{Xuis zTRo!qqVFrN&|S}M{GR%panW0m$o}G$m~79{-Ey6s9LPKN>h>dS=DI8mJFZ&paJKGy zqx+@>aPhiUSJOyNdboAP1D{4cyYoBSx@_MIWg8tbpV@Pnwxb^1(jg!ptIPIqm3h)E z$710r8Z9%QJzUoz@@=sKD>0_?`FA0oU55yNwN5Mi7(3S?-<`cG)rMmZtzd6;h@^+7 z;SOyqz};4`Yn_1(QJq%3DD=saeQo`QHT2eFK+{q;BCjjor{zwDZ98OOeZgt}a(pK2 z`=O-NGyX_jPuN(q7@rw`bkz}0cB8Y;w`M%quwy%W^l*JU)^#?ym=7Hqof?or0D(o zjl8u;`!kov7~kjrvDo28XFa^;zv|-n;aJcW{nf*@`7WRG&3SDG)!pl23s|Qy$}T%U zehT^R^OHNV$0Ki}-}AM1MffpxK0kS<8v2rae~i9@y`7)eC1a!aUGoM(EL_{qwt~H# zJL;uHe%9%Ze&ZY_Vz9wK8X z-{*B&JUbIVehzt&%OCZz-UteP1$!$aSWWHX8Lz#}uq7k-YshVHb{GftpDrU;AzzS@ zW4*1q*Nx6<3h6-V%=oIaYsH=Z9(X(>n+C6t}_jU2(myj2^j9}k+r%FFtvx2>q z5k?qnt)B88N#jU{tymi$gw?l}`zLC{|9o(cAJh*!e(%|hPRFk7Jf0zO>@hj)WvwLR z$Ga#@#(Vf%8DF*bJ)XQT{AH(QDhyhUvldN^=vK!Kp5-O`zkFHZlsGGE?<1npi!aVo zpw(wb*XSq0;$QDR(gozCwRSJpv?lTX+2g;!cUD-Cq z_qXI|ek!J#&Rxt~TxF zp!Zp67Yw4LJ~rQEylFdR>eXU%Uiyf3?~tL2hj&EBGc${h7W|qq?b&>?4i?a;T4|>m z|C}-}yW{&to2yxDMs|yJ`~c4-kkJUcQs>;U+DE9P)k;y#cqD z?d`G4O8mazt?#rNN#5wJFOg56ZrpbzhS<_II`84eJ^}sEe1o?p9|TPkN#TeeK6kb| z6pSd=_mY#C*W0 zM!UlFY8PAVt^8?sUEZre6ukFTGrA>zSYY)$`_s-H2|M0})a4K9_)umAHTSrN5Z%q? zFUCjy@SeXbsB^n#w|BWQ?D+EcX|;cupJhB5jU_cu#bcJwXz!I_o2|sRV#cG7+P}`v zgdOhzqp@ThkuWmcPm3>(SDs_qw?39JK4W=2i^1Eq<2c>tJdt|)z9FM6`^}K)4qYgfoK`Kq=bI)P&tBl_x8APjRcgnDB&NIvB zy<)$c^E+NS-tvWcGW)(R-9xm;*pl(@3gU}mAEKzk>5Ptq9k1$jx`{{dQ&^oczcWvU z4Hwh_h9$6^b3|c$?PjO$Bz~xCXw@!oC(#_QB(Qm@HBIl&o{m_f@>|K{n}c*b3c;)^nz%3se`SZco959LsN+3tX( z%;XI9&@DNS@trSdT=h_`%VO3$WYs6KV{6RBt2;yf2$VtnU|?H!>k z(6CB}EY;D=Hxk7?{(742~k2c5O7 zyHsbD-ZyQli>Ta;;<#HK-&Xvl&a|pk^c12w?ynHPRU=Tpg59Ubf%ZDslEWCk<~O+$ zy|Z-HkBj>ujNkO(AT9Fxd1D3{5W2%!TDNDnI{mTYw=zKRWczocb9mB=mBnvt8?zpc z=sn0IO#9yW-NW}?Hn5)f&iqG58Sh9O>-7=-zNcWWCN@jIdJ5W=mh1bze%a-}Dtp@H zft@jouG!BKf3`JwtjEfm3&!|flfNo*k4BiKo!^1qlO56Cu7g8Tc_-tHXF8(YYx0uJ z_eC2#JXZ_mo?wJ;b@SC4kllTZ&)#5EA(&NqKkG{6e1vaxZS}XmFZWUZ*y_#|{qYt3 zs+(K4$ox)^WBRvsbF{zKuFYtP5x&*6eSGox)Y)WXn0=1$t*)&sz4>P3Vj1zVt{CCF zEky5=_s*!@e+PbVY|R$RvnHR3MciZbuH5SMipv(F!Kl^N6}KKzdtEfgIXl@x{0(t@ z8zr$P-X+$VHnwGM!V!t-2)j$?>k|~H7@Z*JqlD4 z$bQpr*u&ahcfQ2<&KK!I`b&`bH93s2#TT-IYxCWnL41kpMdFLrw`ldP>cxyI+R-q2 zpU#&U-}z!W4aRqtD<r(fx?^n7J^%KyE%l;1&ev-^ zy;tA5+O`}XJ$Hm1*962DvqcYzul49`F=i{7&X*Y9`9d9??EOkc)8r+_7GLB+ zAL(2WUq*ESA}}KOwJg#cw)Re#w-OrL3|l;rFE`&s?=mCoxZWUHA!nj4TxOB&Rfnx} zl=uj2@<=xeNAvnFT7~S1`M8X6j9Fh5?QzXPd?6}AQs@_-L3DIs$9a44#rA?=_LC9x zza1SpUt)ZpLr5Y%z`S1J-l9FL3-Bf^q6$T&D?X{Pjn#6xsh&vVE5664o= z;jJ!MjuEfx??ro77r+Zb_Q(X(e>pxDcAU32c_H%Gs@xT>XgoEKVtnTdwUXDL_Vygp zY`+lgSzUmPl+kW~HTNm(IBze$FjL7G;d343ON{S)p}NK@d3te`>Crw_c?=`kAe=cn4uHzjwqC3vri|4ArAmzt-9^*S-h%3mnD@I@Qi{jdVXlH)v{R6A^4!$st zZk7KcdnA0tMwTg>lXCsa@#EY@O+V4yn@^HIdk@DS#p>jfS=+wW0|$Puep2)1GTP&q z*X8E>;!Cryz*_H-XpiGY$7XL!-r+RMaUa)Poi)dfZSM-8Zw1be{UgvtcN}|(=f2Lu zR$EzAGkOY_mr)FZ%##UxR5b8xX2)nBVdGDud3jgHoL}dBiQ@qAh2940vG_>G{ES<} zK4!9NT0uABb^X1@bQEWxA6eP9!WH9r?DM)T+P;!CRpVpP9s7-r&7RC_eFxlG*sy{&Z=`QCZ|42NKcSPv(N3@Up0OtJ<<-hfK_g2}pGPXzCwccyHCKz9CckEqMm%X{5 z8%Ox69MPSwddq5Uc7$(l6fnIwUWM9@@d*E3nVsly{5ovX`}1s_-w|kp&kjSNzV23k%njX zVyUbrB(tz1e5=di15*npW}RCpJx9Oct1fF*eXNPzj>2_pmugu1CmGYP*(G0$eE{*c z=XK8rzg^F)x(|Fuf^3JjJ=H$aBYd|fPfP5F=kZ}liooy5=GH$@MGVTFzU;_pkNtS3 zU0$~B^ps)N---4Sw)QrA`YHcY|9y5W>`{F1w(y#|)x5lLPhrRYd(HFbXDO!&c~wR= zqt?H3o{xNZ^2+&oZb$Va(LTb4C&-C<5d5$6BVot2AMvH`?bohp-UX>S)w_f9C5{nX z7Fji=H5=qMdU)IGqCLhQ)1LP~I_;wvfgOlgMSz|`Znjj$=b}Bv7VYp_d7l`ef7NM^ zV-V*%_U}oN^YwW3c4r;0Ve1C$tu8-!8l7$1w=Id*QXL>2rG~=lLi{3tu$hPHg65N-q`2S^+tmodLgxt$CEw z-csA1IqhQ~hWBKUubrivJBjufTeSP$TP!k;n4~R@y7W+^1*nDaUYU%-0{Ea^xui^wGJb@ zKmV>9r#<%ZobTp2^5(L6i5K5vAI!1Yd*emXVBoIl$FDm3;W#$B7gTiFd{tF+kNhLL z9f)#Qw7Thl*oSet{S6)SoqdKK`xvUd(VY#|TPYi#izg%hLOda}K~`qgQVTowFGM%{ zG+aV=Tz40?x{$M&zsDWXJ<82OH$A5K8N|L@iy5N}JN8{%PVk77N1}ETBkivWJN7Na z6M7tZTi*I!v%((LQ04!VSEeJLeHQjq?ym?t_FF_ZoL24RL9r)$g#Hz{tBh%IA!S);RB=%SKbgyLCjqcc=aJu!D@*{m^ zUzhHz$nW3NeQSXuMtAH>INk6XIiU|>%hmq5_#I>K>At;yY;=!&6te2bh<0|LrCoH# z*jmM7{uMjQJ}lWYbYh-kF)p!xVcgZgss{RA)JOKV%mMqGxlfR1WqWN;J@I4YQ<0Tt zjrO|#@O7tV4@b0Xul6!!edQc4^eZ?rJ8QmPLKa72PY|l_mvOu*x|{q5b`p=!sv)B% zfa=*fbLRlnaURa7wtZvawYoj$-tqv|y&3cLoSAS-_RRsRN8T%51G92I3&c2R9Aj+b z2oXJckKJ5HV^@CA+i?HL&tZ_uM#j@?Q>j`<=SMTk*#t|gis=ss5K~422CR0E0;}VtO$8WjXI~Pad zn9Mk0JK}0R!F=VKJ&9vKM;y^^8hT6mxFS$Lfv6s3si|ntPr(}!RC}Oj4j;D0+8zr# zjwFpE^buQSeT6%4B=gVYKXI3}6%eLJMlmXH1|$adHo-^R; zS5`+JHaYg(;78`4U6t>*BQ$po)pt7b=X!)#9qE|Ev|nY|;z;d75h1XmRlPCn*+m{n zHgs>5;YjBDT@`*A9c!PWI+MSva_2Qn`?av+k%S|>E1TYX*7Eade>d|9M=~$!s(76< zIQ!p->X_RuBY5x39PM;4YkxCrIKsTqo?pa{v;8i51~`&=Xjg?_`=_0`BC0bl{;J%0 z25J8rVaFqBGJ=i4&$juacUSDOwpZXt=8s$zU9kO|xpPq+bKB-Rdj(THXQo@6iU)+{ z$vkAJj(vDp$gA>9b5w4BC8}eebx$=KNwyJhkd=d5y!srCo!RxP@=W#b=Z{5oJdW>+ z-NtsY553kn;i=7I_o?=o{-KQCJfi(Fqk7M4dPnDHJ5=Wy8z0LkS@{&zvGnb!*4rNG zm?l;r*F`^U?|x7n+X9noB)|99*>zDpiXf?xQ6FQE7wYl+KSR}b!j2nV>t&~w8!{9 zH|eb)!^5ssGhC_1G>-UuOpo~w;!7Nt_4zWFBX+*T_?n^0Z9gm;5v@WNLNOXrWZ%WS zVur>x&AD>ShY(ld*i2lJjl3>2v$~`1!ij11tIm}e-=#(R3SVMo=Gz@adq4Igqf0db zjuX?6Gg;wyY>%De$2==h9mjs+xYkL|u0=C$@aY_n@txz$cXl$uPo_g*F2f<(mU{T>JP}MaH#H zBOYNpXKM+Gk4N~n9*7DF>uGFVP>i;}I>Pt$K=_UHg74RxWDI!|8zvMmdtjuM*o04=8S$Z z!ngH6S_!9}GWAxlm&Jb3E19n*8R5Ime_OahuM3@Mv($_KJ=t-ce=PEa_HQ~7lXO1y zSmofTOswQtoiA}jX78*c!)1Q_JXdPDjPafC#5Y>Yu!`T~jr>V67U*NG?7(;Ow?*gn zoY*3^v_7K8vH}{>IGXekB_n_*hK8SA$5eAX#;-?|l{&;_b2@B0Q)7G|QT8{b6P29C zyvLgH#`sRIW<^Tux5AEdqt16}F7(-x()l(!n|vn4_%+{&gyD*L-t_T|-h?*7cfJ#K zYX>o&WR~+8Z=CPPGaTP^`Y4?5blBj7Na}6OMxV}?IK%6F!5$Ie$nLH2CB{a>kn_eL z(7IY#&=Jk{JsKvK7U%f!+{`zf3WIYTKR|geqiE*SIUeV|o#U)Zds?(_u4lLRlqAO3 z`z)Si38ckrMr|?e9FE6h=^Q_vQTnEne{hbk?vE?Fo#SzS!#Pf+T>hLr@yw?<9%DOS zj%Sp<>2#WiFN)-CFG#(SVutG4*2P(fmM<@g6(yF}&O|dS>%^BBTeRE0zUwo|$26`D zIPLF?Zb8bgmTaDAA7R6V`3`9t6=BC2NX^i?3TXZoPk}DT-_U%c%+J_YtSu<{0j)8r z?WoZge>%tGOq(QKz3K3KzAHrc1OMC9V`OK4yt(yvoC`bVi%Sal^bo;gA|<*O*!_qe z&3+~&!xm52J4x#>i4%F71KnFQ@tv?^PqD?mDl4!*o_B0jj2Dk#eRUNZ3qh@(+{tK7 zu&^`RY&;R&WMzpMU!Lt27Rexw^1kJl57G)P1b@;Tu5{E$U zS6;oN3hL&gS+MB~$>MOWl4ZA#H9u4S!`%+H`)vL;3698c^<~1pVYZO%?%|8y@YVV( zhzhv_{2BMC!T=l4#{4>09uEh9oh1DYX$=YKfo7>K9 zJAx~jwISO{4oF#*`TV5GN{rp(%Iu!|&XpM7M)We;V{6u<{XrRDxb+qpv3>=HST@nhQQpkrkx`M7a^`Q46R(W8A`&ij4~ z@<$IB{?_&1HO-vmU_@iTCFTkldG3^rrM}aM#@Icstjl?f-=m#<2DN`iPQPf6d(vWT zyu){eGh`E#!|mNc*l}N%^QC=XS|QCu^tt z%6NqZ9FMJYMD?tkIMs3gQcLy2l2ajTGanm4b!sh_`z9EmwR-&mO^*%zD;bQJnv-@MoSYaXcihDBE!vS7Q8@ zE7&!BA@YT}w_;p_E3sYP%gVgvwDG*xiREfp!9Q7%Zo`(WWbsxzqGVY=lo2J+rw?d(9e=RkY~Z1FwDk7;*pqZ!a2 zZ_yrWT%-Mx47_NM@gv%`XVF~ET(rk}SF|%L(YNbW1m}B<-)aGi6yq_BuCh*PUK+)f zxw^Kv66@Xlh|=%CoSL(B&XpLy<;vr8bhyGBxDv~`D3`4xXF3iQPk$>}LOKDWaqC^vU-YfC?9pYE$8igk<7>&kAp88N*nl3L`|D61%edyJRaWNa zWQ{LLj3c6YJZ+Yet3w0N$f8SPjBi}QB3Xu*F_??x$e{Ns@GV!A*YCv-H8<>7T!~{X zamDz7?jqa${q$%$S7LmdpK%6#%pbTC&!3hnjO6pP4Yj8peTpk_6eq4|2C?=Bu8?;c zVcPf3l^B1|747v;7K?oe@b5C2ge&pfY`LPh_u>f|Wus4VC640i8FU#}Vtlw#??Sbr zQ+O`cw8n8u%N4zejSh!7|5>`6Zt}jim7UN#UXOLn_wZZVS9xNz$5CjDeQR1uOp1_} z`yHOQnuXaz6&McLU+14ThwgVOXu`*n(26c9QOwxcnAGv(_@b6}(~mjD?YE8}`xmAI zY~41!8@AsQdbqYDQKb=Sk9{KNJo8`On)7d@anI#`Cod9FPQLX~`Nud%Yj$hiKzXdw zMY%d+vCHI$>c1QvJI`bPLX?ZM##8(l?GH9WmxhV;t|&i3v+nAY$73qWw>1&@UXRKQ zpoWyao1Jd#ST~CDt0HggP;Sx7m>2d7r#u@|L#9@NrPk`pR}-V__%Y|j86Qm~ksK+t zu2;n`WgkAHHTu*qBF(-U+!36Kb&DvMAHZy+w}Ta3=y!IwM>EqD8xWMeosn)M0gF;7Ifq=lTQ-Z(n@uGCsuV%@u!79>LVt0|UVMt=5`$2_Td zei`Ml$5`W|Nmji((*O@Tex2~C(Z4RbcGXVToX<3*SqZy??$`1-K6CnGAE}lcMbWjz zjxp=2j-Tl>X>{z^X1Cbudr64y*j~5T>-#YX zJGQ830``Y9-)qay(K&k!#X6>?dVNK)sE+M)i+y(?SEuIz`(a1-!V#;Y)2G9Z0IW72 zal*cbBk|mCsm5yMUb!LKr>KtguCQ4>@v@Ajc`){u<4<8{BWc*gP-DFM7s8J9x#*@2 zjsJrU;_Xupi`A?V`p3e~DqTi59iqxa_tDyKgdLBiNy)onC6JQ#FUM!hn%MRmN7SP* zTO;y2it5-p7}ZFL_ZDyc635yeL3Jj7R<&?%VvEo_7u7R1;k&|ZBBLJC{<^T^ibXpo z@epENQd`QM-;}_p!=#5OWZ3mM{bh&=pAe^PIMJ)G-nULuhe`uPj(xPWcbea7{8^RUKDar8DjgLXpik?&G*Y_ zkMUdD)eklIwg^3gXpimkmUith*gku9=6sLwTiUHBU-4#!Yu}0X*zSvV>^-)BWyeCH zJMA&PXkXVaE$y*iQOi5=)m+}mkUjonr{KPhq_=2I@7f*2_t?9rW#%&4V|?+QD)A+> z$8l{t_VoQv!{;8lPwb0rpQDc$e`EKd-qGiiB1Nw>#8}Z) z;S+<$xnt2UeDuNl!lwwQcWsQXJt`lUanSCF?5^8G+g~5y`yP+v|Fx2Pre0@v8sTf7 zMB90o{_(ZF07v+&lVn}@DsD@^Nojwai4nMu;t*A;v||Jw+t};jIr`{UBjpavHg@UK z+YIL7*AbU&x5~@7)TiHetE3JFr^YKMjQ{!^(Qms|n%_;OgL}{=Gh+=#__mv*M?K2r zk!NZtjn8KBwOb|s#~L6@(yXKVj`6iyWxbYij`BJF+isQEVEI(FeZe+hncsDJHKM=P zqARP0Y&0A{jy#1gnrHeb4A(v#KaLKCPgRvl^ZI=pKaSvpPsPo$o@=(o@#83KkH0nw zjvq%tHU2txELuVT#L-HPe`FM#{y3r#K2=-%D?F<;DRTVSGZ((R2v)jaQ%v?|KIiaN zhf@uQCm?dcTUS+)?zi4fR*oNgx}x9k$uKYr=CFA_$B(_y7Jmg<+;jZQOEmh|$6*#9 z`C-Qb?NdDejuFFW2K2pL@r7If{GX8<`;Fsg`cwMn$Xy&i)1Sy6(cRkIs^y2>5c~Xj zT;|oW)lyD>rayV-@TK^f{#34a?Y$$d{IfSepFdlC-+{p7r1$Ck$@C|_8k$XgMLn$O zy5nd1v&GlW<8$kf96!!(NdF+4?D!%NsK07&{{)Vo=^w*iw=jlJcUFIVp{;gK znB!;q!7$e~wBu*`L2{{>i(TdCYZZ>4=?5gm-q?8*KhCOZeD#K2b|YIuujMDxKU6=p z9~ZrSuZk^uUEAreW_(DZfec|fc&#`Ct<5_5;-x-b8-g89%HVbX< zxv@RcTD1My2;Z{Mdbbu`b$aK@?2`!Jve5l;wmdFUWVIROX-{!{W%L}DXEn>hXz0yA zbJ@fZzU5gxL%ilo&*Cf3N}SC)XPyS%1&=*@C(w8v+gpM31{UH~Y$SVF#Qfe~9nmj4 ze{3gG?&bKIpWfon_~-T$DI)3Pm6zy z|8X}&gnx|xS)SPW|G4;#=;hhYPUnA?CwBbRT>2b7-6B|EvMDQBCfCn-9@q0U7SZF= z&Fs->^!L__X?(Gc3|Eofd-5tNXxJIw(&-6cQ>RC~% zJY}8r74EVoPP%riLtc>WUExsA!B#=kTC-g_#|epwyE zdZnaM$4}t++59#8xQg!jC(q;BJC4a>Y0bTJAU|^YGyCZJ!FM~Kv&D{|&0loR+ajH_ zyA$~{8UF25KU*DM5~Nvx6&UZ!WB9!{s7ihef6aH}DI7o3&xUW5V`1i2E;)WSzBT^7 zd&AyQ7GX4j|zl!{#22pXuk8ey!G>%ho%7 zHh-P|73`M&Z2rD4(#ZN{{5R_W9e3>4`1jKB_1!q$lse2xt;G2AW2&E9{FNBn@P9h} z68h&+o#6<6Z#6)#PKCc=GM;^ketwL3Djqt^vN9XuO{Ru0hYx8SN|LV$2 zdk&{Rp1&FYZ%&MW<7e}i{0tg@><=2<_Bn^YzLIB;pXrB7cgACUGy9HRq(hKSJH5|` zSZqdOoj;j<@`?PTXUL&0|YyX`7EWcgn zthkHL84;VOy-&x_^4o2n=?a$|Kg(}>9}_v6_eJ)ZWklN}o#*&jA7YC~50G;#&srLO zp5Jcq9eZ5KcKq1B$p6$TBze!hk&Lf9er{jrgJAx~DE+IBpXnd3-#C7z zfAqeB^)5lzKkQ1|&#$s?G5d>AZ}(NGnO?RhaQZX-v!7AKNY*)MSkb5BXY=<#nNzHI ziqJOvu5$L`Rnwn50U&T_TAQ+k&Pg0yuX*xpXbkouZ}NO-?zD3 zTLZOSpXd15{1ra&5nhVrLHYDO!?6Zr&)QLT{LH`V<74lMB<+1i^sv1z7DClB=8eyR z-tJw}LCUVeb9x5Zvl8EgF~%1nm(^14XZ8%Y$}jtK%=VOLradcMnvVkvzxUo`)1g{L zV)*k>nB!;k-z^k>zd-e#KfQM-i+yhqL)D#Tu+{LhHkh7A^Ab5-m8a=p*VjkSVQU+- zM-$Xro);hZ`*No|Lovd)wGCuPiF=`)IFD@C%zFG;d@$MVi}7VP6MGYFk~RHM?$lc= zHpbT~BIgF^4+{6^`aDMXKc0R){h^HJ?@xa@{k0s|V>fd=!vAwY{jbG~n8AvEGs4gG z+{|4aKhAxK{+TLRM18G?GW=Vgfj@ElB>HcE2K+dN68`#b{KhTkf9z)pe|<;(J$~#D z3V(f9{yl!|6AFKQ|NK3E>=z3E+s`n*v2Q4RJSC%O?bF9M_74qzX0AqecKqLlF_7UO zoxzU(yA=QE40ik2cl0o9?2yEBvF%nsn)cXk3IC{M z*7&jA68=%itnp*JCH%|nR<9l}{LAgu&5qp?{^fS-X2)&`|8m=MGnG%gy4u>!ADiyE zS#(T)?%r5@r;*>^@nhR!{5h%}96z=#rW;fPW!)=1Ax_`uh>`nx!26@x!D)}}meFqS zN`F?eh9i3G@1gxp`7aySqngKQk8R?X_SKF%(Vp28Jl*(+3HQ#eT!MfV%4bduZR_cx@m!EK_^F~?GepD0Gw8!K6OOeU{{#j%)=DqMghup+| zg781b*v9!&;eQVP$NAI0oTz{twX*g2#__H2KL`Kg{HgFi2mgD10{r z>9g=Z_7jBvIrtyja^Zgt{>S!K_@9ISu}!4r_v2^aKNaN2CJO&@{@*S%_VF+0|Lx)l z_wg_1|Lx8m=;F^&Z_V}3?J`Fr`pvG>J;B?f=t6isu;sPKg=3zGs_N>OYo#DP{k9`HB z{irr}+GAV3rF~T{$#(Sm*^Kt1n%-%T{RE?(H8}K`)Bj9Q(hSe}jcCto6rHrQXzlNu z_Sgq8-W;_ejvxCVhJRGkJAUqi9M$xO|5fUPP=RXsI(z2$`S>2y^p2nTAY}PxDQ!Q#dS{aTSQkrns37$II=}9;$Nr7sU#io->cszsf2rR2D)m8bUaT9w zN_~)<<>_)h_r7)h=i_^+Zs^r%jQ^MGhS=U3{^hzMwuy#+xo(KY`27e)a$A7W4k5%qnfS8k8O+ak7~9WKaOvOe^j&8_;K!3_(wHcjUUH| z!au6nYW&!?2%nfBpQpWVZT|M^e1?B?20MOiTMYl`40in3wiy1=8SMD6Z87|#GuZKS z+fw_T>^sZOCcQDOuVYzmb@E>_KCiPKltK8yBDFI-*+{kpTCo6&x+ z

-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 Hx99&K@@SOF From fd0c3680379ccabe20368c14b6ae0085f8275fbe Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 4 May 2013 15:11:10 -0700 Subject: [PATCH 15/16] Fix texfunc disasm missing color doubling. --- GPU/GeDisasm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index 0fb9d850e6..880b3bc2a1 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -808,10 +808,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { "unsupported2", "unsupported3", }; - if (data & ~0x107) - sprintf(buffer, "TexFunc %i %s (%s, extra %x)", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7], data); + if (data & ~0x10107) + sprintf(buffer, "TexFunc %i %s %s%s (extra %x)", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7], data & 0x10000 ? " color double" : "", data); else - sprintf(buffer, "TexFunc %i %s (%s)", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7]); + sprintf(buffer, "TexFunc %i %s %s%s", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7], data & 0x10000 ? " color double" : ""); } break; From 353528b63dd4c9ae86c6360e84ef1854572f25de Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 4 May 2013 15:28:57 -0700 Subject: [PATCH 16/16] When displaying an FBO, pick the most recent used. Fixes flicker in Jewel Summoner, and black screen in Shadow of Destiny. --- GPU/GLES/Framebuffer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 7436028cd3..9b8a7ca616 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -241,13 +241,20 @@ void FramebufferManager::DrawActiveTexture(float x, float y, float w, float h, b } VirtualFramebuffer *FramebufferManager::GetDisplayFBO() { + VirtualFramebuffer *match = NULL; for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { VirtualFramebuffer *v = *iter; if (MaskedEqual(v->fb_address, displayFramebufPtr_) && v->format == displayFormat_) { // Could check w too but whatever - return *iter; + if (match == NULL || match->last_frame_used < v->last_frame_used) { + match = v; + } } } + if (match != NULL) { + return match; + } + DEBUG_LOG(HLE, "Finding no FBO matching address %08x", displayFramebufPtr_); #if 0 // defined(_DEBUG) std::string debug = "FBOs: ";