diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aeefd3044..d1f080fdec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,15 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (NOT MOBILE_DEVICE) set(USE_FFMPEG ON) endif() + if (NOT ARM) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_M_X64") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_M_X64") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_M_IX86") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_M_IX86") + endif() + endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index c8a8ca27d0..79150ba370 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -450,6 +450,31 @@ void WriteReplaceInstruction(u32 address, u64 hash, int size) { } } +void RestoreReplacedInstruction(u32 address) { + const u32 curInstr = Memory::Read_U32(address); + if (MIPS_IS_REPLACEMENT(curInstr)) { + Memory::Write_U32(replacedInstructions[address], address); + } + INFO_LOG(HLE, "Restored replaced func at %08x", address); + replacedInstructions.erase(address); +} + +void RestoreReplacedInstructions(u32 startAddr, u32 endAddr) { + const auto start = replacedInstructions.lower_bound(startAddr); + const auto end = replacedInstructions.upper_bound(endAddr); + int restored = 0; + for (auto it = start; it != end; ++it) { + const u32 addr = it->first; + const u32 curInstr = Memory::Read_U32(addr); + if (MIPS_IS_REPLACEMENT(curInstr)) { + Memory::Write_U32(it->second, addr); + ++restored; + } + } + INFO_LOG(HLE, "Restored %d replaced funcs between %08x-%08x", restored, startAddr, endAddr); + replacedInstructions.erase(start, end); +} + bool GetReplacedOpAt(u32 address, u32 *op) { u32 instr = Memory::Read_Opcode_JIT(address).encoding; if (MIPS_IS_REPLACEMENT(instr)) { diff --git a/Core/HLE/ReplaceTables.h b/Core/HLE/ReplaceTables.h index 423dd8f0cd..23c38f5e57 100644 --- a/Core/HLE/ReplaceTables.h +++ b/Core/HLE/ReplaceTables.h @@ -58,4 +58,6 @@ int GetReplacementFuncIndex(u64 hash, int funcSize); const ReplacementTableEntry *GetReplacementFunc(int index); void WriteReplaceInstruction(u32 address, u64 hash, int size); +void RestoreReplacedInstruction(u32 address); +void RestoreReplacedInstructions(u32 startAddr, u32 endAddr); bool GetReplacedOpAt(u32 address, u32 *op); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 92b800e6f0..6331d5a924 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -959,10 +959,11 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro SectionID textSection = reader.GetSectionByName(".text"); if (textSection != -1) { - u32 textStart = reader.GetSectionAddr(textSection); + module->textStart = reader.GetSectionAddr(textSection); u32 textSize = reader.GetSectionSize(textSection); + module->textEnd = module->textStart + textSize; - module->nm.text_addr = textStart; + module->nm.text_addr = module->textStart; // TODO: This value appears to be wrong. In one example, the PSP has a value > 0x1000 bigger. module->nm.text_size = textSize; // TODO: It seems like the data size excludes the text size, which kinda makes sense? @@ -970,11 +971,11 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro #if !defined(MOBILE_DEVICE) bool gotSymbols = reader.LoadSymbols(); - MIPSAnalyst::ScanForFunctions(textStart, textStart + textSize, !gotSymbols); + MIPSAnalyst::ScanForFunctions(module->textStart, module->textEnd, !gotSymbols); #else if (g_Config.bFuncHashMap) { bool gotSymbols = reader.LoadSymbols(); - MIPSAnalyst::ScanForFunctions(textStart, textStart + textSize, !gotSymbols); + MIPSAnalyst::ScanForFunctions(module->textStart, module->textEnd, !gotSymbols); } #endif } @@ -1127,15 +1128,15 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro } if (textSection == -1) { - u32 textStart = reader.GetVaddr(); - u32 textEnd = firstImportStubAddr - 4; + module->textStart = reader.GetVaddr(); + module->textEnd = firstImportStubAddr - 4; #if !defined(MOBILE_DEVICE) bool gotSymbols = reader.LoadSymbols(); - MIPSAnalyst::ScanForFunctions(textStart, textEnd, !gotSymbols); + MIPSAnalyst::ScanForFunctions(module->textStart, module->textEnd, !gotSymbols); #else if (g_Config.bFuncHashMap) { bool gotSymbols = reader.LoadSymbols(); - MIPSAnalyst::ScanForFunctions(textStart, textEnd, !gotSymbols); + MIPSAnalyst::ScanForFunctions(module->textStart, module->textEnd, !gotSymbols); } #endif } diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index f91c439c5b..d44c1958da 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -26,6 +26,8 @@ #include "Core/MemMap.h" #include "Core/Reporting.h" +static const int ID3 = 0x49443300; + #ifdef USE_FFMPEG #ifndef PRId64 #define PRId64 "%llu" @@ -241,11 +243,8 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { fclose(file); } #endif - // 2 bytes per channel and we have frame.channels in mp3 source - // learn japanese v0.9 frame.channels = 0 - if (frame.channels == 0) - frame.channels = 2; - ctx->mp3SumDecodedSamples += bytesdecoded / (2 * frame.channels); + // 2 bytes per channel and we use ctx->mp3Channels here + ctx->mp3SumDecodedSamples += bytesdecoded / (2 * ctx->mp3Channels); return bytesdecoded; } @@ -340,9 +339,6 @@ u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { ctx->mp3DecodedBytes = 0; ctx->mp3SumDecodedSamples = 0; ctx->mp3LoopNum = -1; - ctx->mp3Channels = 2; - ctx->mp3Bitrate = 128; - ctx->mp3SamplingRate = 44100; if (mp3Map.find(mp3Addr) != mp3Map.end()) { delete mp3Map[mp3Addr]; @@ -427,6 +423,72 @@ int __Mp3InitContext(Mp3Context *ctx) { #endif } +int __CalculateMp3Channels(int bitval) { + if (bitval == 0 || bitval == 1 || bitval == 2) { // Stereo / Joint Stereo / Dual Channel. + return 2; + } else if (bitval == 3) { // Mono. + return 1; + } else { + return -1; + } +} + +int __CalculateMp3SampleRates(int bitval, int mp3version) { + if (mp3version == 3) { // MPEG Version 1 + int valuemapping[] = { 44100, 48000, 32000, -1 }; + return valuemapping[bitval]; + } else if (mp3version == 2) { // MPEG Version 2 + int valuemapping[] = { 22050, 24000, 16000, -1 }; + return valuemapping[bitval]; + } else if (mp3version == 0) { // MPEG Version 2.5 + int valuemapping[] = { 11025, 12000, 8000, -1 }; + return valuemapping[bitval]; + } else { + return -1; + } +} + +int __CalculateMp3Bitrates(int bitval, int mp3version, int mp3layer) { + if (mp3version == 3) { // MPEG Version 1 + if (mp3layer == 3) { // Layer I + int valuemapping[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }; + return valuemapping[bitval]; + } else if (mp3layer == 2) { // Layer II + int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }; + return valuemapping[bitval]; + } else if (mp3layer == 1) { // Layer III + int valuemapping[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }; + return valuemapping[bitval]; + } else { + return -1; + } + } else if (mp3version == 2 || mp3version == 0) { // MPEG Version 2 or 2.5 + if (mp3layer == 3) { // Layer I + int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }; + return valuemapping[bitval]; + } else if (mp3layer == 1 || mp3layer == 2) { // Layer II or III + int valuemapping[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }; + return valuemapping[bitval]; + } else { + return -1; + } + } else { + return -1; + } +} + +int __ParseMp3Header(Mp3Context *ctx) { + int header = bswap32(Memory::Read_U32(ctx->mp3Buf)); + // ID3 tag , can be seen in Hanayaka Nari Wa ga Ichizoku. + if ((header & 0xFFFFFF00) == ID3) { + int size = bswap32(Memory::Read_U32(ctx->mp3Buf + ctx->mp3StreamStart + 6)); + // Highest bit of each byte has to be ignored (format: 0x7F7F7F7F) + size = (size & 0x7F) | ((size & 0x7F00) >> 1) | ((size & 0x7F0000) >> 2) | ((size & 0x7F000000) >> 3); + header = bswap32(Memory::Read_U32(ctx->mp3Buf + ctx->mp3StreamStart + 10 + size)); + } + return header; +} + int sceMp3Init(u32 mp3) { DEBUG_LOG(ME, "sceMp3Init(%08x)", mp3); @@ -436,22 +498,20 @@ int sceMp3Init(u32 mp3) { return -1; } - // Read in the header and swap the endian - int header = bswap32(Memory::Read_U32(ctx->mp3Buf)); + // Parse the Mp3 header + int header = __ParseMp3Header(ctx); + int layer = (header >> 17) & 0x3; ctx->mp3Version = ((header >> 19) & 0x3); + ctx->mp3SamplingRate = __CalculateMp3SampleRates((header >> 10) & 0x3, ctx->mp3Version); + ctx->mp3Channels = __CalculateMp3Channels((header >> 6) & 0x3); + ctx->mp3Bitrate = __CalculateMp3Bitrates((header >> 12) & 0xF, ctx->mp3Version, layer); + + INFO_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%ikHz, bitrate=%ikbps", ctx->mp3Channels, ctx->mp3SamplingRate, ctx->mp3Bitrate); #ifdef USE_FFMPEG int ret = __Mp3InitContext(ctx); if (ret != 0) - return ret; - - // Let's just grab this info from FFMPEG, it seems more reliable than the code above. - - ctx->mp3SamplingRate = ctx->decoder_context->sample_rate; - ctx->mp3Channels = ctx->decoder_context->channels; - ctx->mp3Bitrate = ctx->decoder_context->bit_rate / 1000; - INFO_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%ikHz, bitrate=%ikbps", ctx->mp3Channels, ctx->mp3SamplingRate, ctx->mp3Bitrate); - + return ret; av_dump_format(ctx->avformat_context, 0, "mp3", 0); #endif diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 9fc5a4c292..fc65f70c94 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -559,6 +559,8 @@ skip: } } + RestoreReplacedInstructions(startAddr, endAddr); + // TODO: Also wipe them from hash->function map } diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index a53099e5a0..266e54ad35 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -1581,12 +1581,6 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) { #endif case GE_CMD_TEXLEVEL: -#ifndef MOBILE_DEVICE - if (data == 1) - WARN_LOG_REPORT_ONCE(texLevel1, G3D, "Unsupported texture level bias settings: %06x", data) - else if (data != 0) - WARN_LOG_REPORT_ONCE(texLevel2, G3D, "Unsupported texture level bias settings: %06x", data); -#endif if (diff) gstate_c.textureChanged = true; break; diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index ee954d58b6..b69193105a 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -489,8 +489,8 @@ void TextureCache::UpdateSamplingParams(TexCacheEntry &entry, bool force) { // Enforce no mip filtering, for safety. minFilt &= 1; // no mipmaps yet } else { - // TODO: Is this a signed value? Which direction? - float lodBias = 0.0; // -(float)((gstate.texlevel >> 16) & 0xFF) / 16.0f; + // Texture lod bias should be signed. + float lodBias = (float)(int)(s8)((gstate.texlevel >> 16) & 0xFF) / 16.0f; if (force || entry.lodBias != lodBias) { #ifndef USING_GLES2 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, lodBias); diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index 92a5faa249..343a1479d1 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -119,7 +119,7 @@ namespace WindowsRawInput { } if (g_Config.bEscapeExitsEmulator && raw->data.keyboard.VKey == VK_ESCAPE) { - DestroyWindow(MainWindow::GetHWND()); + PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0); return; } diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 03a87151b4..b209a71e08 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -1316,7 +1316,7 @@ namespace MainWindow break; case ID_FILE_EXIT: - DestroyWindow(hWnd); + PostMessage(hwndMain, WM_CLOSE, 0, 0); break; case ID_DEBUG_RUNONLOAD: