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 diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d14deb2951..07ee9645f0 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,10 @@ struct InputBuffer { u32 fileoffset; }; +struct Atrac; +int __AtracSetContext(Atrac *atrac, u32 buffer, u32 bufferSize); +int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize); + struct AtracLoopInfo { int cuePointID; int type; @@ -67,54 +84,158 @@ 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); + + 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); + } + if (p.mode == p.MODE_READ && data_buf != NULL) { + __AtracSetContext(this, first.addr, atracBufSize); + } + 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,6 +243,10 @@ u8 nextAtracID; void __AtracInit() { nextAtracID = 0; +#ifdef USE_FFMPEG + avcodec_register_all(); + av_register_all(); +#endif // USE_FFMPEG } void __AtracDoState(PointerWrap &p) { @@ -148,6 +273,7 @@ Atrac *getAtrac(int atracID) { int createAtrac(Atrac *atrac) { int id = nextAtracID++; atracMap[id] = atrac; + atrac->atracID = id; return id; } @@ -158,8 +284,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 +296,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 +333,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 +408,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 +464,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 +562,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 +577,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 +604,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 +636,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 +648,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 +681,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 +697,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 +734,184 @@ 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 __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; + 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)); + + return __AtracSetContext(atrac, buffer, bufferSize); + } +#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 +926,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 +983,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 +1006,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 +1023,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 +1117,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 +1188,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"}, 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..a1c2de341b 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; } 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 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: "; diff --git a/GPU/GLES/TextureScaler.cpp b/GPU/GLES/TextureScaler.cpp index d20a557f82..3cc7dc9ed3 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 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}; 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; 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 diff --git a/UI/MenuScreens.cpp b/UI/MenuScreens.cpp index 8864a311d4..f41025e804 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 @@ -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; } 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 9e78f58acf..a701fd2c60 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 50 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,17 @@ 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); + } 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); @@ -751,7 +765,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]) @@ -1120,7 +1135,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; @@ -1144,9 +1159,9 @@ namespace MainWindow void _ViewFullScreen(HWND hWnd) { - ShowCursor(FALSE); - SetCursor(NULL); - ClipCursor(&g_normalRC); + 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 d6dadf022d..ae11d8f207 100644 Binary files a/Windows/resource.h and b/Windows/resource.h differ 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