Compare commits

..

1 Commits

Author SHA1 Message Date
unexploredtest
f63b2c2fa3
Merge 6c98e7b538 into 19a3f25a71 2025-06-04 13:52:04 -05:00
357 changed files with 3398 additions and 3216 deletions

3
.gitmodules vendored
View File

@ -84,9 +84,6 @@
[submodule "Externals/Vulkan-Headers"] [submodule "Externals/Vulkan-Headers"]
path = Externals/Vulkan-Headers path = Externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git url = https://github.com/KhronosGroup/Vulkan-Headers.git
[submodule "Externals/watcher/watcher"]
path = Externals/watcher/watcher
url = https://github.com/e-dant/watcher.git
[submodule "Externals/SFML/SFML"] [submodule "Externals/SFML/SFML"]
path = Externals/SFML/SFML path = Externals/SFML/SFML
url = https://github.com/SFML/SFML.git url = https://github.com/SFML/SFML.git

View File

@ -691,8 +691,8 @@ dolphin_find_optional_system_library_pkgconfig(ZSTD libzstd>=1.4.0 zstd::zstd Ex
dolphin_find_optional_system_library_pkgconfig(ZLIB zlib>=1.3.1 ZLIB::ZLIB Externals/zlib-ng) dolphin_find_optional_system_library_pkgconfig(ZLIB zlib>=1.3.1 ZLIB::ZLIB Externals/zlib-ng)
dolphin_find_optional_system_library_pkgconfig(minizip-ng dolphin_find_optional_system_library_pkgconfig(MINIZIP
"minizip-ng>=4.0.4" minizip-ng::minizip-ng Externals/minizip-ng "minizip>=4.0.4" minizip::minizip Externals/minizip-ng
) )
dolphin_find_optional_system_library(LZO Externals/LZO) dolphin_find_optional_system_library(LZO Externals/LZO)
@ -784,8 +784,6 @@ if (USE_RETRO_ACHIEVEMENTS)
add_subdirectory(Externals/rcheevos) add_subdirectory(Externals/rcheevos)
endif() endif()
add_subdirectory(Externals/watcher)
######################################## ########################################
# Pre-build events: Define configuration variables and write SCM info header # Pre-build events: Define configuration variables and write SCM info header
# #

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
# GIHP78 - Scooby-Doo! Night of 100 Frights
[Video_Settings]
# Fixes video stuttering on FMVs encoded at 25 FPS
SafeTextureCacheColorSamples = 512

View File

@ -1,8 +0,0 @@
# SBLE5G - A Boy and His Blob
[OnFrame]
$Fix selecting right-most bean
0x800BD308:dword:0x4181000C
[OnFrame_Enabled]
$Fix selecting right-most bean

View File

@ -1,8 +0,0 @@
# SBLP5G - A Boy and His Blob
[OnFrame]
$Fix selecting right-most bean
0x800BE268:dword:0x4181000C
[OnFrame_Enabled]
$Fix selecting right-most bean

View File

@ -1,9 +0,0 @@
# SCYE4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019CB1C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SCYP4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019CB1C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SCYR4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019B4EC:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SCYX4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019CBBC:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SCYY4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019B55C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SCYZ4Q - Cars 2
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8019B55C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,4 +1,4 @@
# SQIE4Q, SQIP4Q, SQIY4Q - Disney Infinity # SQIE4Q, SQIP4Q - Disney Infinity
[Core] [Core]
# Values set here will override the main Dolphin settings. # Values set here will override the main Dolphin settings.

View File

@ -1,9 +0,0 @@
# SQIE4Q - Disney Infinity
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8008E60C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SQIP4Q - Disney Infinity
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8008E60C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# SQIY4Q - Disney Infinity
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x8008E60C:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSE4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA2E4:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSP4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA2E4:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSP4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA354:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSX4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA354:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSY4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA2E4:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSY4Q - Toy Story 3
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA354:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -1,9 +0,0 @@
# STSZ4Q - Toy Story 3 Toy Box Special Edition
[OnFrame]
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
$BAT Speedhack
0x801FA2E4:dword:0x48000180
[OnFrame_Enabled]
$BAT Speedhack

View File

@ -6,10 +6,10 @@ include(CheckIncludeFile)
add_library(minizip STATIC add_library(minizip STATIC
minizip-ng/mz.h minizip-ng/mz.h
# minizip-ng/compat/crypt.h # minizip-ng/compat/crypt.h
# minizip-ng/compat/ioapi.c minizip-ng/compat/ioapi.c
# minizip-ng/compat/ioapi.h minizip-ng/compat/ioapi.h
# minizip-ng/compat/unzip.c minizip-ng/compat/unzip.c
# minizip-ng/compat/unzip.h minizip-ng/compat/unzip.h
# minizip-ng/compat/zip.c # minizip-ng/compat/zip.c
# minizip-ng/compat/zip.h # minizip-ng/compat/zip.h
minizip-ng/mz_crypt.c minizip-ng/mz_crypt.c
@ -93,4 +93,4 @@ endif()
target_link_libraries(minizip PUBLIC ZLIB::ZLIB) target_link_libraries(minizip PUBLIC ZLIB::ZLIB)
add_library(minizip-ng::minizip-ng ALIAS minizip) add_library(minizip::minizip ALIAS minizip)

View File

@ -23,6 +23,8 @@
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="minizip-ng\compat\ioapi.c" />
<ClCompile Include="minizip-ng\compat\unzip.c" />
<ClCompile Include="minizip-ng\mz_crypt.c" /> <ClCompile Include="minizip-ng\mz_crypt.c" />
<ClCompile Include="minizip-ng\mz_os.c" /> <ClCompile Include="minizip-ng\mz_os.c" />
<ClCompile Include="minizip-ng\mz_os_win32.c" /> <ClCompile Include="minizip-ng\mz_os_win32.c" />
@ -37,6 +39,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="minizip-ng\mz.h" /> <ClInclude Include="minizip-ng\mz.h" />
<ClCompile Include="minizip-ng\compat\ioapi.h" />
<ClCompile Include="minizip-ng\compat\unzip.h" />
<ClInclude Include="minizip-ng\mz_crypt.h" /> <ClInclude Include="minizip-ng\mz_crypt.h" />
<ClInclude Include="minizip-ng\mz_os.h" /> <ClInclude Include="minizip-ng\mz_os.h" />
<ClInclude Include="minizip-ng\mz_strm.h" /> <ClInclude Include="minizip-ng\mz_strm.h" />

View File

@ -1,4 +0,0 @@
add_library(watcher INTERFACE IMPORTED GLOBAL)
set_target_properties(watcher PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/watcher/include
)

@ -1 +0,0 @@
Subproject commit b03bdcfc11549df595b77239cefe2643943a3e2f

View File

@ -13,9 +13,6 @@
<uses-feature <uses-feature
android:name="android.hardware.gamepad" android:name="android.hardware.gamepad"
android:required="false"/> android:required="false"/>
<uses-feature
android:name="android.hardware.microphone"
android:required="false"/>
<uses-feature <uses-feature
android:name="android.software.leanback" android:name="android.software.leanback"
android:required="false"/> android:required="false"/>
@ -28,8 +25,12 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission
<uses-permission android:name="android.permission.RECORD_AUDIO"/> android:name="android.permission.VIBRATE"
android:required="false"/>
<uses-permission
android:name="android.permission.RECORD_AUDIO"
android:required="false"/>
<application <application
android:name=".DolphinApplication" android:name=".DolphinApplication"

View File

@ -1,28 +0,0 @@
package org.dolphinemu.dolphinemu.utils
import android.content.Context
import android.media.AudioManager
import androidx.annotation.Keep
import org.dolphinemu.dolphinemu.DolphinApplication
object AudioUtils {
@JvmStatic @Keep
fun getSampleRate(): Int =
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE, 48000)
@JvmStatic @Keep
fun getFramesPerBuffer(): Int =
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER, 256)
private fun getAudioServiceProperty(property: String, fallback: Int): Int {
return try {
val context = DolphinApplication.getAppContext()
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
Integer.parseUnsignedInt(am.getProperty(property))
} catch (e: NullPointerException) {
fallback
} catch (e: NumberFormatException) {
fallback
}
}
}

View File

@ -122,10 +122,6 @@ static jmethodID s_permission_handler_request_record_audio_permission;
static jmethodID s_runnable_run; static jmethodID s_runnable_run;
static jclass s_audio_utils_class;
static jmethodID s_audio_utils_get_sample_rate;
static jmethodID s_audio_utils_get_frames_per_buffer;
namespace IDCache namespace IDCache
{ {
JNIEnv* GetEnvForThread() JNIEnv* GetEnvForThread()
@ -566,21 +562,6 @@ jmethodID GetRunnableRun()
return s_runnable_run; return s_runnable_run;
} }
jclass GetAudioUtilsClass()
{
return s_audio_utils_class;
}
jmethodID GetAudioUtilsGetSampleRate()
{
return s_audio_utils_get_sample_rate;
}
jmethodID GetAudioUtilsGetFramesPerBuffer()
{
return s_audio_utils_get_frames_per_buffer;
}
} // namespace IDCache } // namespace IDCache
extern "C" { extern "C" {
@ -817,13 +798,6 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V"); s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
env->DeleteLocalRef(runnable_class); env->DeleteLocalRef(runnable_class);
const jclass audio_utils_class = env->FindClass("org/dolphinemu/dolphinemu/utils/AudioUtils");
s_audio_utils_class = reinterpret_cast<jclass>(env->NewGlobalRef(audio_utils_class));
s_audio_utils_get_sample_rate = env->GetStaticMethodID(audio_utils_class, "getSampleRate", "()I");
s_audio_utils_get_frames_per_buffer =
env->GetStaticMethodID(audio_utils_class, "getFramesPerBuffer", "()I");
env->DeleteLocalRef(audio_utils_class);
return JNI_VERSION; return JNI_VERSION;
} }
@ -860,6 +834,5 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_core_device_control_class); env->DeleteGlobalRef(s_core_device_control_class);
env->DeleteGlobalRef(s_input_detector_class); env->DeleteGlobalRef(s_input_detector_class);
env->DeleteGlobalRef(s_permission_handler_class); env->DeleteGlobalRef(s_permission_handler_class);
env->DeleteGlobalRef(s_audio_utils_class);
} }
} }

View File

@ -121,8 +121,4 @@ jmethodID GetPermissionHandlerRequestRecordAudioPermission();
jmethodID GetRunnableRun(); jmethodID GetRunnableRun();
jclass GetAudioUtilsClass();
jmethodID GetAudioUtilsGetSampleRate();
jmethodID GetAudioUtilsGetFramesPerBuffer();
} // namespace IDCache } // namespace IDCache

View File

@ -55,14 +55,14 @@ JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getEnabled( Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getEnabled(
JNIEnv* env, jobject obj) JNIEnv* env, jobject obj)
{ {
return static_cast<jboolean>(GetPointer(env, obj)->enabled.GetValue()); return static_cast<jboolean>(GetPointer(env, obj)->enabled);
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_setEnabled( Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_setEnabled(
JNIEnv* env, jobject obj, jboolean value) JNIEnv* env, jobject obj, jboolean value)
{ {
GetPointer(env, obj)->enabled.SetValue(value); GetPointer(env, obj)->enabled = value;
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL

View File

@ -16,7 +16,6 @@
#include "AudioCommon/WASAPIStream.h" #include "AudioCommon/WASAPIStream.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/TimeUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/System.h" #include "Core/System.h"
@ -167,8 +166,7 @@ void UpdateSoundStream(Core::System& system)
if (sound_stream) if (sound_stream)
{ {
int const volume = int volume = Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
sound_stream->SetVolume(volume); sound_stream->SetVolume(volume);
} }
} }
@ -194,7 +192,7 @@ void SetSoundStreamRunning(Core::System& system, bool running)
void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples) void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples)
{ {
const SoundStream* const sound_stream = system.GetSoundStream(); SoundStream* sound_stream = system.GetSoundStream();
if (!sound_stream) if (!sound_stream)
return; return;
@ -214,17 +212,14 @@ void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_s
void StartAudioDump(Core::System& system) void StartAudioDump(Core::System& system)
{ {
const SoundStream* const sound_stream = system.GetSoundStream(); SoundStream* sound_stream = system.GetSoundStream();
std::time_t const start_time = std::time(nullptr); std::time_t start_time = std::time(nullptr);
std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID(); std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID();
const auto local_time = Common::LocalTime(start_time); std::string base_name =
if (!local_time) fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(start_time));
return;
std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name); const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name);
const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name); const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name);
@ -237,7 +232,7 @@ void StartAudioDump(Core::System& system)
void StopAudioDump(Core::System& system) void StopAudioDump(Core::System& system)
{ {
const SoundStream* const sound_stream = system.GetSoundStream(); SoundStream* sound_stream = system.GetSoundStream();
if (!sound_stream) if (!sound_stream)
return; return;
@ -270,7 +265,7 @@ void DecreaseVolume(Core::System& system, unsigned short offset)
void ToggleMuteVolume(Core::System& system) void ToggleMuteVolume(Core::System& system)
{ {
bool const isMuted = Config::Get(Config::MAIN_AUDIO_MUTED); bool isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted); Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
UpdateSoundStream(system); UpdateSoundStream(system);
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector> #include <vector>

View File

@ -10,6 +10,7 @@
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/Thread.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#ifdef _WIN32 #ifdef _WIN32
@ -22,7 +23,7 @@ constexpr u32 BUFFER_SAMPLES = 512;
long CubebStream::DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/, long CubebStream::DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/,
void* output_buffer, long num_frames) void* output_buffer, long num_frames)
{ {
const auto* const self = static_cast<CubebStream*>(user_data); auto* self = static_cast<CubebStream*>(user_data);
if (self->m_stereo) if (self->m_stereo)
self->m_mixer->Mix(static_cast<short*>(output_buffer), num_frames); self->m_mixer->Mix(static_cast<short*>(output_buffer), num_frames);
@ -43,7 +44,7 @@ CubebStream::CubebStream()
Common::Event sync_event; Common::Event sync_event;
m_work_queue.Push([this, &sync_event] { m_work_queue.Push([this, &sync_event] {
Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); });
auto const result = CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); auto result = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
m_coinit_success = result == S_OK; m_coinit_success = result == S_OK;
m_should_couninit = result == S_OK || result == S_FALSE; m_should_couninit = result == S_OK || result == S_FALSE;
}); });

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <cstddef>
#include <functional>
#include <memory> #include <memory>
#include <vector> #include <vector>

View File

@ -182,8 +182,7 @@ std::size_t Mixer::MixSurround(float* samples, std::size_t num_samples)
memset(samples, 0, num_samples * SURROUND_CHANNELS * sizeof(float)); memset(samples, 0, num_samples * SURROUND_CHANNELS * sizeof(float));
std::size_t const needed_frames = std::size_t needed_frames = m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples);
m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples);
constexpr std::size_t max_samples = 0x8000; constexpr std::size_t max_samples = 0x8000;
ASSERT_MSG(AUDIO, needed_frames <= max_samples, ASSERT_MSG(AUDIO, needed_frames <= max_samples,
@ -191,7 +190,7 @@ std::size_t Mixer::MixSurround(float* samples, std::size_t num_samples)
needed_frames, max_samples); needed_frames, max_samples);
std::array<s16, max_samples> buffer; std::array<s16, max_samples> buffer;
std::size_t const available_frames = Mix(buffer.data(), static_cast<std::size_t>(needed_frames)); std::size_t available_frames = Mix(buffer.data(), static_cast<std::size_t>(needed_frames));
if (available_frames != needed_frames) if (available_frames != needed_frames)
{ {
ERROR_LOG_FMT(AUDIO, ERROR_LOG_FMT(AUDIO,
@ -230,7 +229,7 @@ void Mixer::PushSamples(const s16* samples, std::size_t num_samples)
if (m_log_dsp_audio) if (m_log_dsp_audio)
{ {
const s32 sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor(); const s32 sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor();
auto const volume = m_dma_mixer.GetVolume(); auto volume = m_dma_mixer.GetVolume();
m_wave_writer_dsp.AddStereoSamplesBE(samples, static_cast<u32>(num_samples), m_wave_writer_dsp.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
sample_rate_divisor, volume.first, volume.second); sample_rate_divisor, volume.first, volume.second);
} }
@ -242,7 +241,7 @@ void Mixer::PushStreamingSamples(const s16* samples, std::size_t num_samples)
if (m_log_dtk_audio) if (m_log_dtk_audio)
{ {
const s32 sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor(); const s32 sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor();
auto const volume = m_streaming_mixer.GetVolume(); auto volume = m_streaming_mixer.GetVolume();
m_wave_writer_dtk.AddStereoSamplesBE(samples, static_cast<u32>(num_samples), m_wave_writer_dtk.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
sample_rate_divisor, volume.first, volume.second); sample_rate_divisor, volume.first, volume.second);
} }
@ -287,8 +286,7 @@ void Mixer::PushSkylanderPortalSamples(const u8* samples, std::size_t num_sample
{ {
for (std::size_t i = 0; i < num_samples; ++i) for (std::size_t i = 0; i < num_samples; ++i)
{ {
s16 const sample = s16 sample = static_cast<u16>(samples[i * 2 + 1]) << 8 | static_cast<u16>(samples[i * 2]);
static_cast<u16>(samples[i * 2 + 1]) << 8 | static_cast<u16>(samples[i * 2]);
samples_stereo[i * 2] = sample; samples_stereo[i * 2] = sample;
samples_stereo[i * 2 + 1] = sample; samples_stereo[i * 2 + 1] = sample;
} }
@ -337,8 +335,7 @@ void Mixer::StartLogDTKAudio(const std::string& filename)
{ {
if (!m_log_dtk_audio) if (!m_log_dtk_audio)
{ {
bool const success = bool success = m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor());
m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor());
if (success) if (success)
{ {
m_log_dtk_audio = true; m_log_dtk_audio = true;
@ -375,7 +372,7 @@ void Mixer::StartLogDSPAudio(const std::string& filename)
{ {
if (!m_log_dsp_audio) if (!m_log_dsp_audio)
{ {
bool const success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor()); bool success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor());
if (success) if (success)
{ {
m_log_dsp_audio = true; m_log_dsp_audio = true;
@ -497,10 +494,10 @@ void Mixer::MixerFifo::Enqueue()
0.0002984010f, 0.0002102045f, 0.0001443499f, 0.0000961509f, 0.0000616906f, 0.0000377350f, 0.0002984010f, 0.0002102045f, 0.0001443499f, 0.0000961509f, 0.0000616906f, 0.0000377350f,
0.0000216492f, 0.0000113187f, 0.0000050749f, 0.0000016272f}; 0.0000216492f, 0.0000113187f, 0.0000050749f, 0.0000016272f};
std::size_t const head = m_queue_head.load(std::memory_order_acquire); const std::size_t head = m_queue_head.load(std::memory_order_acquire);
// Check if we run out of space in the circular queue. (rare) // Check if we run out of space in the circular queue. (rare)
std::size_t const next_head = (head + 1) & GRANULE_QUEUE_MASK; std::size_t next_head = (head + 1) & GRANULE_QUEUE_MASK;
if (next_head == m_queue_tail.load(std::memory_order_acquire)) if (next_head == m_queue_tail.load(std::memory_order_acquire))
{ {
WARN_LOG_FMT(AUDIO, WARN_LOG_FMT(AUDIO,

View File

@ -3,9 +3,11 @@
#pragma once #pragma once
#include <algorithm>
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <bit> #include <bit>
#include <cmath>
#include "AudioCommon/SurroundDecoder.h" #include "AudioCommon/SurroundDecoder.h"
#include "AudioCommon/WaveFile.h" #include "AudioCommon/WaveFile.h"

View File

@ -76,7 +76,7 @@ static bool InitLibrary()
if (!InitFunctions()) if (!InitFunctions())
{ {
FreeLibrary(s_openal_dll); ::FreeLibrary(s_openal_dll);
s_openal_dll = nullptr; s_openal_dll = nullptr;
return false; return false;
} }
@ -168,7 +168,7 @@ bool OpenALStream::SetRunning(bool running)
static ALenum CheckALError(const char* desc) static ALenum CheckALError(const char* desc)
{ {
ALenum const err = palGetError(); ALenum err = palGetError();
if (err != AL_NO_ERROR) if (err != AL_NO_ERROR)
{ {
@ -211,16 +211,16 @@ void OpenALStream::SoundLoop()
{ {
Common::SetCurrentThreadName("Audio thread - openal"); Common::SetCurrentThreadName("Audio thread - openal");
bool const float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0; bool float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0;
bool const surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi(); bool surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi();
bool use_surround = Config::ShouldUseDPL2Decoder() && surround_capable; bool use_surround = Config::ShouldUseDPL2Decoder() && surround_capable;
// As there is no extension to check for 32-bit fixed point support // As there is no extension to check for 32-bit fixed point support
// and we know that only a X-Fi with hardware OpenAL supports it, // and we know that only a X-Fi with hardware OpenAL supports it,
// we just check if one is being used. // we just check if one is being used.
bool const fixed32_capable = IsCreativeXFi(); bool fixed32_capable = IsCreativeXFi();
u32 const frequency = m_mixer->GetSampleRate(); u32 frequency = m_mixer->GetSampleRate();
u32 frames_per_buffer; u32 frames_per_buffer;
// Can't have zero samples per buffer // Can't have zero samples per buffer
@ -288,12 +288,12 @@ void OpenALStream::SoundLoop()
num_buffers_queued -= num_buffers_processed; num_buffers_queued -= num_buffers_processed;
} }
unsigned int const min_frames = frames_per_buffer; unsigned int min_frames = frames_per_buffer;
if (use_surround) if (use_surround)
{ {
std::array<float, OAL_MAX_FRAMES * SURROUND_CHANNELS> dpl2; std::array<float, OAL_MAX_FRAMES * SURROUND_CHANNELS> dpl2;
u32 const rendered_frames = static_cast<u32>(m_mixer->MixSurround(dpl2.data(), min_frames)); u32 rendered_frames = static_cast<u32>(m_mixer->MixSurround(dpl2.data(), min_frames));
if (rendered_frames < min_frames) if (rendered_frames < min_frames)
continue; continue;
@ -351,8 +351,7 @@ void OpenALStream::SoundLoop()
} }
else else
{ {
u32 const rendered_frames = u32 rendered_frames = static_cast<u32>(m_mixer->Mix(m_realtime_buffer.data(), min_frames));
static_cast<u32>(m_mixer->Mix(m_realtime_buffer.data(), min_frames));
if (!rendered_frames) if (!rendered_frames)
continue; continue;

View File

@ -7,6 +7,9 @@
#include "AudioCommon/SoundStream.h" #include "AudioCommon/SoundStream.h"
#include "Common/Event.h" #include "Common/Event.h"
#include "Core/Core.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/SystemTimers.h"
#ifdef _WIN32 #ifdef _WIN32
#include <al.h> #include <al.h>

View File

@ -8,27 +8,40 @@
#include <SLES/OpenSLES.h> #include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h> #include <SLES/OpenSLES_Android.h>
#include <jni.h>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "jni/AndroidCommon/IDCache.h"
void OpenSLESStream::BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context) // engine interfaces
{ static SLObjectItf engineObject;
reinterpret_cast<OpenSLESStream*>(context)->PushSamples(bq); static SLEngineItf engineEngine;
} static SLObjectItf outputMixObject;
void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq) // buffer queue player interfaces
static SLObjectItf bqPlayerObject = nullptr;
static SLPlayItf bqPlayerPlay;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
static SLVolumeItf bqPlayerVolume;
static Mixer* g_mixer;
#define BUFFER_SIZE 512
#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
// Double buffering.
static short buffer[2][BUFFER_SIZE];
static int curBuffer = 0;
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
{ {
ASSERT(bq == m_bq_player_buffer_queue); ASSERT(bq == bqPlayerBufferQueue);
ASSERT(nullptr == context);
// Render to the fresh buffer // Render to the fresh buffer
m_mixer->Mix(m_buffer[m_current_buffer].data(), m_frames_per_buffer); g_mixer->Mix(reinterpret_cast<short*>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES);
SLresult result = (*bq)->Enqueue(bq, m_buffer[m_current_buffer].data(), m_bytes_per_buffer); SLresult result =
m_current_buffer ^= 1; // Switch buffer (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0]));
curBuffer ^= 1; // Switch buffer
// Comment from sample code: // Comment from sample code:
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
@ -38,78 +51,61 @@ void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq)
bool OpenSLESStream::Init() bool OpenSLESStream::Init()
{ {
JNIEnv* env = IDCache::GetEnvForThread();
jclass audio_utils = IDCache::GetAudioUtilsClass();
const SLuint32 sample_rate =
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetSampleRate());
m_frames_per_buffer =
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetFramesPerBuffer());
INFO_LOG_FMT(AUDIO, "OpenSLES configuration: {} Hz, {} frames per buffer", sample_rate,
m_frames_per_buffer);
constexpr SLuint32 channels = 2;
const SLuint32 samples_per_buffer = m_frames_per_buffer * channels;
m_bytes_per_buffer = m_frames_per_buffer * channels * sizeof(m_buffer[0][0]);
for (std::vector<short>& buffer : m_buffer)
buffer.resize(samples_per_buffer);
SLresult result; SLresult result;
// create engine // create engine
result = slCreateEngine(&m_engine_object, 0, nullptr, 0, nullptr, nullptr); result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_object)->Realize(m_engine_object, SL_BOOLEAN_FALSE); result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_object)->GetInterface(m_engine_object, SL_IID_ENGINE, &m_engine_engine); result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_engine)->CreateOutputMix(m_engine_engine, &m_output_mix_object, 0, 0, 0); result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_output_mix_object)->Realize(m_output_mix_object, SL_BOOLEAN_FALSE); result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = { SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,
SL_DATAFORMAT_PCM, channels, 2,
sample_rate * 1000, SL_PCMSAMPLEFORMAT_FIXED_16, m_mixer->GetSampleRate() * 1000,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_BYTEORDER_LITTLEENDIAN}; SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm}; SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink // configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, m_output_mix_object}; SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, nullptr}; SLDataSink audioSnk = {&loc_outmix, nullptr};
// create audio player // create audio player
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*m_engine_engine) result =
->CreateAudioPlayer(m_engine_engine, &m_bq_player_object, &audioSrc, &audioSnk, 2, (*engineEngine)
ids, req); ->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)->Realize(m_bq_player_object, SL_BOOLEAN_FALSE); result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_PLAY, &m_bq_player_play); result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)
->GetInterface(m_bq_player_object, SL_IID_BUFFERQUEUE, &m_bq_player_buffer_queue);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = result =
(*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_VOLUME, &m_bq_player_volume); (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_buffer_queue) result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
->RegisterCallback(m_bq_player_buffer_queue, BQPlayerCallback, this);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_play)->SetPlayState(m_bq_player_play, SL_PLAYSTATE_PLAYING); result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
ASSERT(SL_RESULT_SUCCESS == result);
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
// Render and enqueue a first buffer. // Render and enqueue a first buffer.
m_current_buffer ^= 1; curBuffer ^= 1;
g_mixer = m_mixer.get();
result = (*m_bq_player_buffer_queue) result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0]));
->Enqueue(m_bq_player_buffer_queue, m_buffer[0].data(), m_bytes_per_buffer);
if (SL_RESULT_SUCCESS != result) if (SL_RESULT_SUCCESS != result)
return false; return false;
@ -118,39 +114,39 @@ bool OpenSLESStream::Init()
OpenSLESStream::~OpenSLESStream() OpenSLESStream::~OpenSLESStream()
{ {
if (m_bq_player_object != nullptr) if (bqPlayerObject != nullptr)
{ {
(*m_bq_player_object)->Destroy(m_bq_player_object); (*bqPlayerObject)->Destroy(bqPlayerObject);
m_bq_player_object = nullptr; bqPlayerObject = nullptr;
m_bq_player_play = nullptr; bqPlayerPlay = nullptr;
m_bq_player_buffer_queue = nullptr; bqPlayerBufferQueue = nullptr;
m_bq_player_volume = nullptr; bqPlayerVolume = nullptr;
} }
if (m_output_mix_object != nullptr) if (outputMixObject != nullptr)
{ {
(*m_output_mix_object)->Destroy(m_output_mix_object); (*outputMixObject)->Destroy(outputMixObject);
m_output_mix_object = nullptr; outputMixObject = nullptr;
} }
if (m_engine_object != nullptr) if (engineObject != nullptr)
{ {
(*m_engine_object)->Destroy(m_engine_object); (*engineObject)->Destroy(engineObject);
m_engine_object = nullptr; engineObject = nullptr;
m_engine_engine = nullptr; engineEngine = nullptr;
} }
} }
bool OpenSLESStream::SetRunning(bool running) bool OpenSLESStream::SetRunning(bool running)
{ {
SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED; SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED;
return (*m_bq_player_play)->SetPlayState(m_bq_player_play, new_state) == SL_RESULT_SUCCESS; return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, new_state) == SL_RESULT_SUCCESS;
} }
void OpenSLESStream::SetVolume(int volume) void OpenSLESStream::SetVolume(int volume)
{ {
const SLmillibel attenuation = const SLmillibel attenuation =
volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f)); volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f));
(*m_bq_player_volume)->SetVolumeLevel(m_bq_player_volume, attenuation); (*bqPlayerVolume)->SetVolumeLevel(bqPlayerVolume, attenuation);
} }
#endif // HAVE_OPENSL_ES #endif // HAVE_OPENSL_ES

View File

@ -3,15 +3,10 @@
#pragma once #pragma once
#ifdef HAVE_OPENSL_ES #include <thread>
#include <array>
#include <vector>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#endif // HAVE_OPENSL_ES
#include "AudioCommon/SoundStream.h" #include "AudioCommon/SoundStream.h"
#include "Common/Event.h"
class OpenSLESStream final : public SoundStream class OpenSLESStream final : public SoundStream
{ {
@ -24,25 +19,7 @@ public:
static bool IsValid() { return true; } static bool IsValid() { return true; }
private: private:
static void BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context); std::thread thread;
void PushSamples(SLAndroidSimpleBufferQueueItf bq); Common::Event soundSyncEvent;
// engine interfaces
SLObjectItf m_engine_object;
SLEngineItf m_engine_engine;
SLObjectItf m_output_mix_object;
// buffer queue player interfaces
SLObjectItf m_bq_player_object = nullptr;
SLPlayItf m_bq_player_play;
SLAndroidSimpleBufferQueueItf m_bq_player_buffer_queue;
SLVolumeItf m_bq_player_volume;
SLuint32 m_frames_per_buffer;
SLuint32 m_bytes_per_buffer;
// Double buffering.
std::array<std::vector<short>, 2> m_buffer;
int m_current_buffer = 0;
#endif // HAVE_OPENSL_ES #endif // HAVE_OPENSL_ES
}; };

View File

@ -8,6 +8,7 @@
#endif #endif
#include "AudioCommon/SoundStream.h" #include "AudioCommon/SoundStream.h"
#include "Common/CommonTypes.h"
#include "Common/Flag.h" #include "Common/Flag.h"
#include "Common/Thread.h" #include "Common/Thread.h"

View File

@ -32,7 +32,7 @@ size_t SurroundDecoder::QueryFramesNeededForSurroundOutput(const size_t output_f
if (m_decoded_fifo.size() < output_frames * SURROUND_CHANNELS) if (m_decoded_fifo.size() < output_frames * SURROUND_CHANNELS)
{ {
// Output stereo frames needed to have at least the desired number of surround frames // Output stereo frames needed to have at least the desired number of surround frames
size_t const frames_needed = output_frames - m_decoded_fifo.size() / SURROUND_CHANNELS; size_t frames_needed = output_frames - m_decoded_fifo.size() / SURROUND_CHANNELS;
return frames_needed + m_frame_block_size - frames_needed % m_frame_block_size; return frames_needed + m_frame_block_size - frames_needed % m_frame_block_size;
} }

View File

@ -8,6 +8,7 @@
// clang-format off // clang-format off
#include <Audioclient.h> #include <Audioclient.h>
#include <mmdeviceapi.h> #include <mmdeviceapi.h>
#include <devpkey.h>
#include <functiondiscoverykeys_devpkey.h> #include <functiondiscoverykeys_devpkey.h>
#include <wil/resource.h> #include <wil/resource.h>
// clang-format on // clang-format on
@ -158,9 +159,8 @@ ComPtr<IMMDevice> WASAPIStream::GetDeviceByName(std::string_view name)
bool WASAPIStream::Init() bool WASAPIStream::Init()
{ {
ASSERT(m_enumerator == nullptr); ASSERT(m_enumerator == nullptr);
HRESULT const result = HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(m_enumerator.GetAddressOf()));
IID_PPV_ARGS(m_enumerator.GetAddressOf()));
if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result)) if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result))
return false; return false;

View File

@ -32,7 +32,7 @@ class WASAPIStream final : public SoundStream
#ifdef _WIN32 #ifdef _WIN32
public: public:
explicit WASAPIStream(); explicit WASAPIStream();
~WASAPIStream() override; ~WASAPIStream();
bool Init() override; bool Init() override;
bool SetRunning(bool running) override; bool SetRunning(bool running) override;

View File

@ -31,7 +31,7 @@ public:
{ {
m_active_block = &m_output_result.blocks.emplace_back(base_addr); m_active_block = &m_output_result.blocks.emplace_back(base_addr);
} }
~GekkoIRPlugin() override = default; virtual ~GekkoIRPlugin() = default;
void OnDirectivePre(GekkoDirective directive) override; void OnDirectivePre(GekkoDirective directive) override;
void OnDirectivePost(GekkoDirective directive) override; void OnDirectivePost(GekkoDirective directive) override;

View File

@ -64,8 +64,6 @@ add_library(common
FatFsUtil.h FatFsUtil.h
FileSearch.cpp FileSearch.cpp
FileSearch.h FileSearch.h
FilesystemWatcher.cpp
FilesystemWatcher.h
FileUtil.cpp FileUtil.cpp
FileUtil.h FileUtil.h
FixedSizeQueue.h FixedSizeQueue.h
@ -178,7 +176,7 @@ PUBLIC
enet::enet enet::enet
fmt::fmt fmt::fmt
MbedTLS::mbedtls MbedTLS::mbedtls
minizip-ng::minizip-ng minizip::minizip
sfml-network sfml-network
PRIVATE PRIVATE
@ -186,7 +184,6 @@ PRIVATE
FatFs FatFs
Iconv::Iconv Iconv::Iconv
spng::spng spng::spng
watcher
${VTUNE_LIBRARIES} ${VTUNE_LIBRARIES}
) )

View File

@ -46,7 +46,8 @@ public:
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128)); ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
} }
bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t len) const override virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
size_t len) const override
{ {
std::array<u8, BLOCK_SIZE> iv_tmp{}; std::array<u8, BLOCK_SIZE> iv_tmp{};
if (iv) if (iv)
@ -205,7 +206,8 @@ public:
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]); _mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
} }
bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t len) const override virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
size_t len) const override
{ {
if (len % BLOCK_SIZE) if (len % BLOCK_SIZE)
return false; return false;

View File

@ -41,18 +41,18 @@ public:
mbedtls_sha1_init(&ctx); mbedtls_sha1_init(&ctx);
ASSERT(!mbedtls_sha1_starts_ret(&ctx)); ASSERT(!mbedtls_sha1_starts_ret(&ctx));
} }
~ContextMbed() override { mbedtls_sha1_free(&ctx); } ~ContextMbed() { mbedtls_sha1_free(&ctx); }
void Update(const u8* msg, size_t len) override virtual void Update(const u8* msg, size_t len) override
{ {
ASSERT(!mbedtls_sha1_update_ret(&ctx, msg, len)); ASSERT(!mbedtls_sha1_update_ret(&ctx, msg, len));
} }
Digest Finish() override virtual Digest Finish() override
{ {
Digest digest; Digest digest;
ASSERT(!mbedtls_sha1_finish_ret(&ctx, digest.data())); ASSERT(!mbedtls_sha1_finish_ret(&ctx, digest.data()));
return digest; return digest;
} }
bool HwAccelerated() const override { return false; } virtual bool HwAccelerated() const override { return false; }
private: private:
mbedtls_sha1_context ctx{}; mbedtls_sha1_context ctx{};
@ -204,7 +204,7 @@ private:
} }
ATTRIBUTE_TARGET("sha") ATTRIBUTE_TARGET("sha")
void ProcessBlock(const u8* msg) override virtual void ProcessBlock(const u8* msg) override
{ {
// There are 80 rounds with 4 bytes per round, giving 0x140 byte work space, but we can keep // There are 80 rounds with 4 bytes per round, giving 0x140 byte work space, but we can keep
// active state in just 0x40 bytes. // active state in just 0x40 bytes.
@ -248,7 +248,7 @@ private:
// clang-format on // clang-format on
} }
Digest GetDigest() override virtual Digest GetDigest() override
{ {
Digest digest; Digest digest;
_mm_storeu_si128((__m128i*)&digest[0], byterev_16B(state[0])); _mm_storeu_si128((__m128i*)&digest[0], byterev_16B(state[0]));
@ -257,7 +257,7 @@ private:
return digest; return digest;
} }
bool HwAccelerated() const override { return true; } virtual bool HwAccelerated() const override { return true; }
std::array<XmmReg, 2> state{}; std::array<XmmReg, 2> state{};
}; };

View File

@ -25,7 +25,6 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/TimeUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
@ -96,7 +95,12 @@ int SDCardDiskIOCtl(File::IOFile* image, u8 pdrv, u8 cmd, void* buff)
u32 GetSystemTimeFAT() u32 GetSystemTimeFAT()
{ {
const std::time_t time = std::time(nullptr); const std::time_t time = std::time(nullptr);
std::tm tm = *Common::LocalTime(time); std::tm tm;
#ifdef _WIN32
localtime_s(&tm, &time);
#else
localtime_r(&time, &tm);
#endif
DWORD fattime = 0; DWORD fattime = 0;
fattime |= (tm.tm_year - 80) << 25; fattime |= (tm.tm_year - 80) << 25;

View File

@ -1,67 +0,0 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/FilesystemWatcher.h"
#include <wtr/watcher.hpp>
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
namespace Common
{
FilesystemWatcher::FilesystemWatcher() = default;
FilesystemWatcher::~FilesystemWatcher() = default;
void FilesystemWatcher::Watch(const std::string& path)
{
const auto [iter, inserted] = m_watched_paths.try_emplace(path, nullptr);
if (inserted)
{
iter->second = std::make_unique<wtr::watch>(path, [this](wtr::event e) {
const auto watched_path = PathToString(e.path_name);
if (e.path_type == wtr::event::path_type::watcher)
{
if (watched_path.starts_with('e'))
ERROR_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path);
else if (watched_path.starts_with('w'))
WARN_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path);
return;
}
if (e.effect_type == wtr::event::effect_type::create)
{
const auto path = WithUnifiedPathSeparators(watched_path);
PathAdded(path);
}
else if (e.effect_type == wtr::event::effect_type::modify)
{
const auto path = WithUnifiedPathSeparators(watched_path);
PathModified(path);
}
else if (e.effect_type == wtr::event::effect_type::rename)
{
if (!e.associated)
{
WARN_LOG_FMT(COMMON, "Rename on path '{}' seen without association!", watched_path);
return;
}
const auto old_path = WithUnifiedPathSeparators(watched_path);
const auto new_path = WithUnifiedPathSeparators(PathToString(e.associated->path_name));
PathRenamed(old_path, new_path);
}
else if (e.effect_type == wtr::event::effect_type::destroy)
{
const auto path = WithUnifiedPathSeparators(watched_path);
PathDeleted(path);
}
});
}
}
void FilesystemWatcher::Unwatch(const std::string& path)
{
m_watched_paths.erase(path);
}
} // namespace Common

View File

@ -1,47 +0,0 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <memory>
#include <string>
#include <string_view>
namespace wtr
{
inline namespace watcher
{
class watch;
}
} // namespace wtr
namespace Common
{
// A class that can watch a path and receive callbacks
// when files or directories underneath that path receive events
class FilesystemWatcher
{
public:
FilesystemWatcher();
virtual ~FilesystemWatcher();
void Watch(const std::string& path);
void Unwatch(const std::string& path);
private:
// A new file or folder was added to one of the watched paths
virtual void PathAdded(std::string_view path) {}
// A file or folder was modified in one of the watched paths
virtual void PathModified(std::string_view path) {}
// A file or folder was renamed in one of the watched paths
virtual void PathRenamed(std::string_view old_path, std::string_view new_path) {}
// A file or folder was deleted in one of the watched paths
virtual void PathDeleted(std::string_view path) {}
std::map<std::string, std::unique_ptr<wtr::watch>> m_watched_paths;
};
} // namespace Common

View File

@ -10,9 +10,9 @@
class GLContextWGL final : public GLContext class GLContextWGL final : public GLContext
{ {
public: public:
~GLContextWGL() override; ~GLContextWGL();
bool IsHeadless() const override; bool IsHeadless() const;
std::unique_ptr<GLContext> CreateSharedContext() override; std::unique_ptr<GLContext> CreateSharedContext() override;

View File

@ -101,7 +101,7 @@ class HostDisassemblerBochs final : public HostDisassembler
{ {
public: public:
explicit HostDisassemblerBochs(); explicit HostDisassemblerBochs();
~HostDisassemblerBochs() override = default; ~HostDisassemblerBochs() = default;
private: private:
disassembler m_disasm; disassembler m_disasm;

View File

@ -9,7 +9,7 @@ class ConsoleListener : public Common::Log::LogListener
{ {
public: public:
ConsoleListener(); ConsoleListener();
~ConsoleListener() override; ~ConsoleListener();
void Log(Common::Log::LogLevel level, const char* text) override; void Log(Common::Log::LogLevel level, const char* text) override;

View File

@ -5,9 +5,7 @@
#include <algorithm> #include <algorithm>
#include <mz.h> #include <unzip.h>
#include <mz_zip.h>
#include <mz_zip_rw.h>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
@ -15,14 +13,14 @@
namespace Common namespace Common
{ {
// Reads all of the current file. destination must be big enough to fit the whole file. // Reads all of the current file. destination must be big enough to fit the whole file.
inline bool ReadFileFromZip(void* zip_reader, u8* destination, u64 len) inline bool ReadFileFromZip(unzFile file, u8* destination, u64 len)
{ {
const u64 MAX_BUFFER_SIZE = 65535; const u64 MAX_BUFFER_SIZE = 65535;
if (mz_zip_reader_entry_open(zip_reader) != MZ_OK) if (unzOpenCurrentFile(file) != UNZ_OK)
return false; return false;
Common::ScopeGuard guard{[&] { mz_zip_reader_entry_close(zip_reader); }}; Common::ScopeGuard guard{[&] { unzCloseCurrentFile(file); }};
u64 bytes_to_go = len; u64 bytes_to_go = len;
while (bytes_to_go > 0) while (bytes_to_go > 0)
@ -30,7 +28,7 @@ inline bool ReadFileFromZip(void* zip_reader, u8* destination, u64 len)
// NOTE: multiples of 4G can't cause read_len == 0 && bytes_to_go > 0, as MAX_BUFFER_SIZE is // NOTE: multiples of 4G can't cause read_len == 0 && bytes_to_go > 0, as MAX_BUFFER_SIZE is
// small. // small.
const u32 read_len = static_cast<u32>(std::min(bytes_to_go, MAX_BUFFER_SIZE)); const u32 read_len = static_cast<u32>(std::min(bytes_to_go, MAX_BUFFER_SIZE));
const int rv = mz_zip_reader_entry_read(zip_reader, destination, read_len); const int rv = unzReadCurrentFile(file, destination, read_len);
if (rv < 0) if (rv < 0)
return false; return false;
@ -39,11 +37,11 @@ inline bool ReadFileFromZip(void* zip_reader, u8* destination, u64 len)
destination += bytes_read; destination += bytes_read;
} }
return bytes_to_go == 0; return unzEndOfFile(file) == 1;
} }
template <typename ContiguousContainer> template <typename ContiguousContainer>
bool ReadFileFromZip(void* file, ContiguousContainer* destination) bool ReadFileFromZip(unzFile file, ContiguousContainer* destination)
{ {
return ReadFileFromZip(file, reinterpret_cast<u8*>(destination->data()), destination->size()); return ReadFileFromZip(file, reinterpret_cast<u8*>(destination->data()), destination->size());
} }

View File

@ -122,6 +122,7 @@ std::string SettingsWriter::GenerateSerialNumber()
// Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries, // Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries,
// as there is a check to ensure the string length is strictly lower than 10. // as there is a check to ensure the string length is strictly lower than 10.
return fmt::format("{:09}", t % 1000000000); // 3 for %j, 2 for %H, 2 for %M, 2 for %S.
return fmt::format("{:%j%H%M%S}", fmt::localtime(t));
} }
} // namespace Common } // namespace Common

View File

@ -2,25 +2,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/TimeUtil.h" #include "Common/TimeUtil.h"
#include "Common/Logging/Log.h"
#include <ctime> #include <ctime>
#include <optional> #include <optional>
namespace Common namespace Common
{ {
std::optional<std::tm> LocalTime(std::time_t time) std::optional<std::tm> Localtime(std::time_t time)
{ {
std::tm local_time; std::tm local_time;
#ifdef _MSC_VER #ifdef _MSC_VER
if (localtime_s(&local_time, &time) != 0) if (localtime_s(&local_time, &time) != 0)
#else
if (localtime_r(&time, &local_time) == NULL)
#endif
{
ERROR_LOG_FMT(COMMON, "Failed to convert time to local time: {}", std::strerror(errno));
return std::nullopt; return std::nullopt;
} #else
std::tm* result = localtime_r(&time, &local_time);
if (result != &local_time)
return std::nullopt;
#endif
return local_time; return local_time;
} }
} // Namespace Common } // Namespace Common

View File

@ -9,5 +9,5 @@
namespace Common namespace Common
{ {
// Threadsafe and error-checking variant of std::localtime() // Threadsafe and error-checking variant of std::localtime()
std::optional<std::tm> LocalTime(std::time_t time); std::optional<std::tm> Localtime(std::time_t time);
} // Namespace Common } // Namespace Common

View File

@ -165,26 +165,17 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume)
{ {
return; return;
} }
if (volume == nullptr)
{
WARN_LOG_FMT(ACHIEVEMENTS, "Called Load Game without a game.");
return;
}
if (!m_client) if (!m_client)
{ {
ERROR_LOG_FMT(ACHIEVEMENTS, ERROR_LOG_FMT(ACHIEVEMENTS,
"Attempted to load game achievements without achievement client initialized."); "Attempted to load game achievements without achievement client initialized.");
return; return;
} }
if (volume == nullptr)
{
WARN_LOG_FMT(ACHIEVEMENTS, "Software format unsupported by AchievementManager.");
if (rc_client_get_game_info(m_client))
{
rc_client_begin_change_media_from_hash(m_client, "", ChangeMediaCallback, NULL);
}
else
{
rc_client_set_read_memory_function(m_client, MemoryVerifier);
rc_client_begin_load_game(m_client, "", LoadGameCallback, NULL);
}
return;
}
rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED)); rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED));
rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED)); rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED));
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED)); rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
@ -338,12 +329,11 @@ void AchievementManager::DoFrame()
if (!system) if (!system)
return; return;
Core::CPUThreadGuard thread_guard(*system); Core::CPUThreadGuard thread_guard(*system);
u32 mem2_size = (system->IsWii()) ? system->GetMemory().GetExRamSizeReal() : 0; u32 mem2_size = system->GetMemory().GetExRamSizeReal();
if (m_cloned_memory.size() != MEM1_SIZE + mem2_size) if (m_cloned_memory.size() != MEM1_SIZE + mem2_size)
m_cloned_memory.resize(MEM1_SIZE + mem2_size); m_cloned_memory.resize(MEM1_SIZE + mem2_size);
system->GetMemory().CopyFromEmu(m_cloned_memory.data(), 0, MEM1_SIZE); system->GetMemory().CopyFromEmu(m_cloned_memory.data(), 0, MEM1_SIZE);
if (mem2_size > 0) system->GetMemory().CopyFromEmu(m_cloned_memory.data() + MEM1_SIZE, MEM2_START, mem2_size);
system->GetMemory().CopyFromEmu(m_cloned_memory.data() + MEM1_SIZE, MEM2_START, mem2_size);
} }
#endif // RC_CLIENT_SUPPORTS_RAINTEGRATION #endif // RC_CLIENT_SUPPORTS_RAINTEGRATION
std::lock_guard lg{m_lock}; std::lock_guard lg{m_lock};
@ -608,6 +598,11 @@ rc_client_t* AchievementManager::GetClient()
return m_client; return m_client;
} }
rc_api_fetch_game_data_response_t* AchievementManager::GetGameData()
{
return &m_game_data;
}
const AchievementManager::Badge& AchievementManager::GetGameBadge() const const AchievementManager::Badge& AchievementManager::GetGameBadge() const
{ {
return m_game_badge.data.empty() ? m_default_game_badge : m_game_badge; return m_game_badge.data.empty() ? m_default_game_badge : m_game_badge;
@ -741,8 +736,12 @@ void AchievementManager::CloseGame()
if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)) if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED))
Discord::UpdateDiscordPresence(); Discord::UpdateDiscordPresence();
if (rc_client_get_game_info(m_client)) if (rc_client_get_game_info(m_client))
{
rc_api_destroy_fetch_game_data_response(&m_game_data);
rc_client_unload_game(m_client); rc_client_unload_game(m_client);
}
INFO_LOG_FMT(ACHIEVEMENTS, "Game closed."); INFO_LOG_FMT(ACHIEVEMENTS, "Game closed.");
m_game_data = {};
} }
m_update_callback(UpdatedItems{.all = true}); m_update_callback(UpdatedItems{.all = true});
@ -996,30 +995,36 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
OSD::Color::RED); OSD::Color::RED);
return; return;
} }
if (result == RC_NO_GAME_LOADED && instance.m_dll_found)
auto* game = rc_client_get_game_info(client);
if (result == RC_OK)
{ {
if (!game) // Allow developer tools for unidentified games
{ rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client."); instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG, WARN_LOG_FMT(ACHIEVEMENTS, "Unrecognized title ready for development.");
OSD::Color::RED); OSD::AddMessage("Unrecognized title loaded for development.", OSD::Duration::VERY_LONG,
} OSD::Color::YELLOW);
else
{
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
instance.m_display_welcome_message = true;
}
} }
else if (result != RC_OK)
{ {
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game."); WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game.");
OSD::AddMessage("Achievements are not supported for this title.", OSD::Duration::VERY_LONG, OSD::AddMessage("Achievements are not supported for this title.", OSD::Duration::VERY_LONG,
OSD::Color::RED); OSD::Color::RED);
return;
} }
auto* game = rc_client_get_game_info(client);
if (!game)
{
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client.");
OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG,
OSD::Color::RED);
instance.CloseGame();
return;
}
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker); rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
instance.m_display_welcome_message = true;
instance.FetchGameBadges(); instance.FetchGameBadges();
instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release); instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
instance.m_update_callback({.all = true}); instance.m_update_callback({.all = true});

View File

@ -89,8 +89,8 @@ public:
static constexpr std::string_view BLUE = "#0B71C1"; static constexpr std::string_view BLUE = "#0B71C1";
static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json"; static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json";
static const inline Common::SHA1::Digest APPROVED_LIST_HASH = { static const inline Common::SHA1::Digest APPROVED_LIST_HASH = {
0x6D, 0x91, 0xF5, 0xC1, 0xE2, 0x4C, 0xC3, 0x39, 0xF5, 0x7F, 0xE1, 0x29, 0xD1, 0x33, 0x4D, 0xF2, 0xF8, 0xA8, 0x4E, 0xCA,
0xEC, 0xA9, 0x8C, 0xA9, 0xBD, 0x61, 0x28, 0x54, 0x11, 0x62}; 0xF6, 0x87, 0xE6, 0xEC, 0xEC, 0xB3, 0x18, 0x69, 0x34, 0x45};
struct LeaderboardEntry struct LeaderboardEntry
{ {
@ -160,6 +160,7 @@ public:
const Badge& GetPlayerBadge() const; const Badge& GetPlayerBadge() const;
std::string_view GetGameDisplayName() const; std::string_view GetGameDisplayName() const;
rc_client_t* GetClient(); rc_client_t* GetClient();
rc_api_fetch_game_data_response_t* GetGameData();
const Badge& GetGameBadge() const; const Badge& GetGameBadge() const;
const Badge& GetAchievementBadge(AchievementId id, bool locked) const; const Badge& GetAchievementBadge(AchievementId id, bool locked) const;
const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id); const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id);
@ -277,6 +278,9 @@ private:
std::atomic_bool m_background_execution_allowed = true; std::atomic_bool m_background_execution_allowed = true;
Badge m_player_badge; Badge m_player_badge;
Hash m_game_hash{}; Hash m_game_hash{};
u32 m_game_id = 0;
rc_api_fetch_game_data_response_t m_game_data{};
bool m_is_game_loaded = false;
Badge m_game_badge; Badge m_game_badge;
bool m_display_welcome_message = false; bool m_display_welcome_message = false;
std::unordered_map<AchievementId, Badge> m_unlocked_badges; std::unordered_map<AchievementId, Badge> m_unlocked_badges;

View File

@ -603,8 +603,6 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
return false; return false;
} }
AchievementManager::GetInstance().LoadGame(nullptr);
SConfig::OnTitleDirectlyBooted(guard); SConfig::OnTitleDirectlyBooted(guard);
ppc_state.pc = executable.reader->GetEntryPoint(); ppc_state.pc = executable.reader->GetEntryPoint();
@ -637,8 +635,6 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
if (!BootNANDTitle(system, nand_title.id)) if (!BootNANDTitle(system, nand_title.id))
return false; return false;
AchievementManager::GetInstance().LoadGame(nullptr);
SConfig::OnTitleDirectlyBooted(guard); SConfig::OnTitleDirectlyBooted(guard);
return true; return true;
} }
@ -665,8 +661,6 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
ipl.disc->auto_disc_change_paths); ipl.disc->auto_disc_change_paths);
} }
AchievementManager::GetInstance().LoadGame(nullptr);
SConfig::OnTitleDirectlyBooted(guard); SConfig::OnTitleDirectlyBooted(guard);
return true; return true;
} }
@ -674,7 +668,6 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
bool operator()(const BootParameters::DFF& dff) const bool operator()(const BootParameters::DFF& dff) const
{ {
NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path); NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path);
AchievementManager::GetInstance().LoadGame(nullptr);
return system.GetFifoPlayer().Open(dff.dff_path); return system.GetFifoPlayer().Open(dff.dff_path);
} }

View File

@ -20,7 +20,7 @@ public:
explicit DolReader(const std::string& filename); explicit DolReader(const std::string& filename);
explicit DolReader(File::IOFile file); explicit DolReader(File::IOFile file);
explicit DolReader(std::vector<u8> buffer); explicit DolReader(std::vector<u8> buffer);
~DolReader() override; ~DolReader();
bool IsValid() const override { return m_is_valid; } bool IsValid() const override { return m_is_valid; }
bool IsWii() const override { return m_is_wii; } bool IsWii() const override { return m_is_wii; }

View File

@ -28,7 +28,7 @@ public:
explicit ElfReader(const std::string& filename); explicit ElfReader(const std::string& filename);
explicit ElfReader(File::IOFile file); explicit ElfReader(File::IOFile file);
explicit ElfReader(std::vector<u8> buffer); explicit ElfReader(std::vector<u8> buffer);
~ElfReader() override; ~ElfReader();
u32 Read32(int off) const { return base32[off >> 2]; } u32 Read32(int off) const { return base32[off >> 2]; }
// Quick accessors // Quick accessors
ElfType GetType() const { return (ElfType)(header->e_type); } ElfType GetType() const { return (ElfType)(header->e_type); }

View File

@ -45,7 +45,6 @@ const Info<bool> MAIN_ACCURATE_CPU_CACHE{{System::Main, "Core", "AccurateCPUCach
const Info<bool> MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true}; const Info<bool> MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true};
const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100}; const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100};
const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40}; const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40};
const Info<bool> MAIN_CORRECT_TIME_DRIFT{{System::Main, "Core", "CorrectTimeDrift"}, false};
const Info<bool> MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, true}; const Info<bool> MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, true};
const Info<bool> MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true}; const Info<bool> MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true};
const Info<std::string> MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""}; const Info<std::string> MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""};

View File

@ -63,7 +63,6 @@ extern const Info<bool> MAIN_ACCURATE_CPU_CACHE;
extern const Info<bool> MAIN_DSP_HLE; extern const Info<bool> MAIN_DSP_HLE;
extern const Info<int> MAIN_MAX_FALLBACK; extern const Info<int> MAIN_MAX_FALLBACK;
extern const Info<int> MAIN_TIMING_VARIANCE; extern const Info<int> MAIN_TIMING_VARIANCE;
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
extern const Info<bool> MAIN_CPU_THREAD; extern const Info<bool> MAIN_CPU_THREAD;
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE; extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
extern const Info<std::string> MAIN_DEFAULT_ISO; extern const Info<std::string> MAIN_DEFAULT_ISO;

View File

@ -8,7 +8,6 @@
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <optional>
#include <queue> #include <queue>
#include <utility> #include <utility>
#include <variant> #include <variant>
@ -35,7 +34,6 @@
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Thread.h" #include "Common/Thread.h"
#include "Common/TimeUtil.h"
#include "Common/Version.h" #include "Common/Version.h"
#include "Core/AchievementManager.h" #include "Core/AchievementManager.h"
@ -84,6 +82,7 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
#include "VideoCommon/Assets/CustomAssetLoader.h"
#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/AsyncRequests.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/FrameDumper.h" #include "VideoCommon/FrameDumper.h"
@ -529,6 +528,9 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
FreeLook::LoadInputConfig(); FreeLook::LoadInputConfig();
system.GetCustomAssetLoader().Init();
Common::ScopeGuard asset_loader_guard([&system] { system.GetCustomAssetLoader().Shutdown(); });
system.GetMovie().Init(*boot); system.GetMovie().Init(*boot);
Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); }); Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); });
@ -735,17 +737,15 @@ static std::string GenerateScreenshotFolderPath()
return path; return path;
} }
static std::optional<std::string> GenerateScreenshotName() static std::string GenerateScreenshotName()
{ {
// append gameId, path only contains the folder here. // append gameId, path only contains the folder here.
const std::string path_prefix = const std::string path_prefix =
GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID(); GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID();
const std::time_t cur_time = std::time(nullptr); const std::time_t cur_time = std::time(nullptr);
const auto local_time = Common::LocalTime(cur_time); const std::string base_name =
if (!local_time) fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(cur_time));
return std::nullopt;
const std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
// First try a filename without any suffixes, if already exists then append increasing numbers // First try a filename without any suffixes, if already exists then append increasing numbers
std::string name = fmt::format("{}.png", base_name); std::string name = fmt::format("{}.png", base_name);
@ -761,9 +761,7 @@ static std::optional<std::string> GenerateScreenshotName()
void SaveScreenShot() void SaveScreenShot()
{ {
const Core::CPUThreadGuard guard(Core::System::GetInstance()); const Core::CPUThreadGuard guard(Core::System::GetInstance());
std::optional<std::string> name = GenerateScreenshotName(); g_frame_dumper->SaveScreenshot(GenerateScreenshotName());
if (name)
g_frame_dumper->SaveScreenshot(*name);
} }
void SaveScreenShot(std::string_view name) void SaveScreenShot(std::string_view name)

View File

@ -105,20 +105,10 @@ void CoreTimingManager::Init()
m_last_oc_factor = m_config_oc_factor; m_last_oc_factor = m_config_oc_factor;
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor; m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
m_on_state_changed_handle = Core::AddOnStateChangedCallback([this](Core::State state) {
if (state == Core::State::Running)
{
// We don't want Throttle to attempt catch-up for all the time lost while paused.
ResetThrottle(GetTicks());
}
});
} }
void CoreTimingManager::Shutdown() void CoreTimingManager::Shutdown()
{ {
Core::RemoveOnStateChangedCallback(&m_on_state_changed_handle);
std::lock_guard lk(m_ts_write_lock); std::lock_guard lk(m_ts_write_lock);
MoveEvents(); MoveEvents();
ClearPendingEvents(); ClearPendingEvents();
@ -141,8 +131,6 @@ void CoreTimingManager::RefreshConfig()
m_max_variance = std::chrono::duration_cast<DT>(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE))); m_max_variance = std::chrono::duration_cast<DT>(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE)));
m_correct_time_drift = Config::Get(Config::MAIN_CORRECT_TIME_DRIFT);
if (AchievementManager::GetInstance().IsHardcoreModeActive() && if (AchievementManager::GetInstance().IsHardcoreModeActive() &&
Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f && Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f &&
Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f) Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f)
@ -440,9 +428,7 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
const TimePoint time = Clock::now(); const TimePoint time = Clock::now();
const TimePoint min_target = time - m_max_fallback; const TimePoint min_target = time - m_max_fallback;
if (target_time < min_target)
// "Correct Time Drift" setting prevents timing relaxing.
if (!m_correct_time_drift && target_time < min_target)
{ {
// Core is running too slow.. i.e. CPU bottleneck. // Core is running too slow.. i.e. CPU bottleneck.
const DT adjustment = min_target - target_time; const DT adjustment = min_target - target_time;

View File

@ -211,7 +211,6 @@ private:
DT m_max_fallback = {}; DT m_max_fallback = {};
DT m_max_variance = {}; DT m_max_variance = {};
bool m_correct_time_drift = false;
double m_emulation_speed = 1.0; double m_emulation_speed = 1.0;
bool IsSpeedUnlimited() const; bool IsSpeedUnlimited() const;
@ -226,8 +225,6 @@ private:
std::atomic_bool m_use_precision_timer = false; std::atomic_bool m_use_precision_timer = false;
Common::PrecisionTimer m_precision_cpu_timer; Common::PrecisionTimer m_precision_cpu_timer;
Common::PrecisionTimer m_precision_gpu_timer; Common::PrecisionTimer m_precision_gpu_timer;
int m_on_state_changed_handle;
}; };
} // namespace CoreTiming } // namespace CoreTiming

View File

@ -135,11 +135,9 @@ void Analyzer::FindInstructionStarts(const SDSP& dsp, u16 start_addr, u16 end_ad
// If an instruction potentially raises exceptions, mark the following // If an instruction potentially raises exceptions, mark the following
// instruction as needing to check for exceptions // instruction as needing to check for exceptions
if (opcode->opcode == 0x00c0 || opcode->opcode == 0x00e0 || opcode->opcode == 0x1600 || if (opcode->opcode == 0x00c0 || opcode->opcode == 0x1800 || opcode->opcode == 0x1880 ||
opcode->opcode == 0x1800 || opcode->opcode == 0x1880 || opcode->opcode == 0x1900 || opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 ||
opcode->opcode == 0x1980 || opcode->opcode == 0x1a00 || opcode->opcode == 0x1a80 || opcode->extended)
opcode->opcode == 0x1b00 || opcode->opcode == 0x1b80 || opcode->opcode == 0x2000 ||
opcode->opcode == 0x2800 || opcode->opcode == 0x2c00 || opcode->extended)
{ {
m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_EXC; m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_EXC;
} }

View File

@ -224,11 +224,11 @@ void SDSP::CheckExternalInterrupt()
control_reg &= ~CR_EXTERNAL_INT; control_reg &= ~CR_EXTERNAL_INT;
} }
bool SDSP::CheckExceptions() void SDSP::CheckExceptions()
{ {
// Early out to skip the loop in the common case. // Early out to skip the loop in the common case.
if (exceptions == 0) if (exceptions == 0)
return false; return;
for (int i = 7; i > 0; i--) for (int i = 7; i > 0; i--)
{ {
@ -247,7 +247,7 @@ bool SDSP::CheckExceptions()
r.sr &= ~SR_EXT_INT_ENABLE; r.sr &= ~SR_EXT_INT_ENABLE;
else else
r.sr &= ~SR_INT_ENABLE; r.sr &= ~SR_INT_ENABLE;
return true; break;
} }
else else
{ {
@ -257,8 +257,6 @@ bool SDSP::CheckExceptions()
} }
} }
} }
return false;
} }
u16 SDSP::ReadRegister(size_t reg) const u16 SDSP::ReadRegister(size_t reg) const
@ -543,9 +541,9 @@ void DSPCore::CheckExternalInterrupt()
m_dsp.CheckExternalInterrupt(); m_dsp.CheckExternalInterrupt();
} }
bool DSPCore::CheckExceptions() void DSPCore::CheckExceptions()
{ {
return m_dsp.CheckExceptions(); m_dsp.CheckExceptions();
} }
u16 DSPCore::ReadRegister(size_t reg) const u16 DSPCore::ReadRegister(size_t reg) const

View File

@ -383,7 +383,7 @@ struct SDSP
void SetException(ExceptionType exception); void SetException(ExceptionType exception);
// Checks if any exceptions occurred an updates the DSP state as appropriate. // Checks if any exceptions occurred an updates the DSP state as appropriate.
bool CheckExceptions(); void CheckExceptions();
// Notify that an external interrupt is pending (used by thread mode) // Notify that an external interrupt is pending (used by thread mode)
void SetExternalInterrupt(bool val); void SetExternalInterrupt(bool val);
@ -530,7 +530,7 @@ public:
void CheckExternalInterrupt(); void CheckExternalInterrupt();
// Checks if any exceptions occurred an updates the DSP state as appropriate. // Checks if any exceptions occurred an updates the DSP state as appropriate.
bool CheckExceptions(); void CheckExceptions();
// Reads the current value from a particular register. // Reads the current value from a particular register.
u16 ReadRegister(size_t reg) const; u16 ReadRegister(size_t reg) const;

View File

@ -99,9 +99,9 @@ void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
m_dsp_core.DSPState().reset_dspjit_codespace = false; m_dsp_core.DSPState().reset_dspjit_codespace = false;
} }
static u32 CheckExceptionsThunk(DSPCore& dsp) static void CheckExceptionsThunk(DSPCore& dsp)
{ {
return dsp.CheckExceptions() ? 1u : 0u; dsp.CheckExceptions();
} }
// Must go out of block if exception is detected // Must go out of block if exception is detected
@ -116,11 +116,8 @@ void DSPEmitter::checkExceptions(u32 retval)
DSPJitRegCache c(m_gpr); DSPJitRegCache c(m_gpr);
m_gpr.SaveRegs(); m_gpr.SaveRegs();
ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core); ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core);
TEST(32, R(ABI_RETURN), R(ABI_RETURN));
FixupBranch skip_return = J_CC(CC_Z, Jump::Short);
MOV(32, R(EAX), Imm32(retval)); MOV(32, R(EAX), Imm32(retval));
JMP(m_return_dispatcher, Jump::Near); JMP(m_return_dispatcher, Jump::Near);
SetJumpTarget(skip_return);
m_gpr.LoadRegs(false); m_gpr.LoadRegs(false);
m_gpr.FlushRegs(c, false); m_gpr.FlushRegs(c, false);

View File

@ -132,7 +132,7 @@ class OSThreadView : public Common::Debug::ThreadView
{ {
public: public:
explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr); explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr);
~OSThreadView() override = default; ~OSThreadView() = default;
const OSThread& Data() const; const OSThread& Data() const;

View File

@ -220,7 +220,7 @@ class FifoPlayer::CPUCore final : public CPUCoreBase
public: public:
explicit CPUCore(FifoPlayer* parent) : m_parent(parent) {} explicit CPUCore(FifoPlayer* parent) : m_parent(parent) {}
CPUCore(const CPUCore&) = delete; CPUCore(const CPUCore&) = delete;
~CPUCore() override {} ~CPUCore() {}
CPUCore& operator=(const CPUCore&) = delete; CPUCore& operator=(const CPUCore&) = delete;
void Init() override void Init() override

View File

@ -157,7 +157,7 @@ class VAListStruct : public VAList
{ {
public: public:
explicit VAListStruct(const Core::CPUThreadGuard& guard, u32 address); explicit VAListStruct(const Core::CPUThreadGuard& guard, u32 address);
~VAListStruct() override = default; ~VAListStruct() = default;
private: private:
struct svr4_va_list struct svr4_va_list

View File

@ -28,7 +28,7 @@ public:
DSPHLE(DSPHLE&& other) = delete; DSPHLE(DSPHLE&& other) = delete;
DSPHLE& operator=(const DSPHLE& other) = delete; DSPHLE& operator=(const DSPHLE& other) = delete;
DSPHLE& operator=(DSPHLE&& other) = delete; DSPHLE& operator=(DSPHLE&& other) = delete;
~DSPHLE() override; ~DSPHLE();
bool Initialize(bool wii, bool dsp_thread) override; bool Initialize(bool wii, bool dsp_thread) override;
void Shutdown() override; void Shutdown() override;

View File

@ -27,7 +27,7 @@ public:
AESndAccelerator(AESndAccelerator&&) = delete; AESndAccelerator(AESndAccelerator&&) = delete;
AESndAccelerator& operator=(const AESndAccelerator&) = delete; AESndAccelerator& operator=(const AESndAccelerator&) = delete;
AESndAccelerator& operator=(AESndAccelerator&&) = delete; AESndAccelerator& operator=(AESndAccelerator&&) = delete;
~AESndAccelerator() override; ~AESndAccelerator();
protected: protected:
void OnRawReadEndException() override {} void OnRawReadEndException() override {}

View File

@ -129,7 +129,7 @@ public:
HLEAccelerator(HLEAccelerator&&) = delete; HLEAccelerator(HLEAccelerator&&) = delete;
HLEAccelerator& operator=(const HLEAccelerator&) = delete; HLEAccelerator& operator=(const HLEAccelerator&) = delete;
HLEAccelerator& operator=(HLEAccelerator&&) = delete; HLEAccelerator& operator=(HLEAccelerator&&) = delete;
~HLEAccelerator() override = default; ~HLEAccelerator() = default;
PB_TYPE* acc_pb = nullptr; PB_TYPE* acc_pb = nullptr;

View File

@ -20,7 +20,7 @@ class DSPLLE : public DSPEmulator
{ {
public: public:
DSPLLE(); DSPLLE();
~DSPLLE() override; ~DSPLLE();
bool Initialize(bool wii, bool dsp_thread) override; bool Initialize(bool wii, bool dsp_thread) override;
void Shutdown() override; void Shutdown() override;

View File

@ -18,7 +18,7 @@ class CEXIAgp : public IEXIDevice
{ {
public: public:
CEXIAgp(Core::System& system, const Slot slot); CEXIAgp(Core::System& system, const Slot slot);
~CEXIAgp() override; virtual ~CEXIAgp() override;
bool IsPresent() const override { return true; } bool IsPresent() const override { return true; }
void ImmWrite(u32 _uData, u32 _uSize) override; void ImmWrite(u32 _uData, u32 _uSize) override;
u32 ImmRead(u32 _uSize) override; u32 ImmRead(u32 _uSize) override;

View File

@ -216,7 +216,7 @@ class CEXIETHERNET : public IEXIDevice
{ {
public: public:
CEXIETHERNET(Core::System& system, BBADeviceType type); CEXIETHERNET(Core::System& system, BBADeviceType type);
~CEXIETHERNET() override; virtual ~CEXIETHERNET();
void SetCS(int cs) override; void SetCS(int cs) override;
bool IsPresent() const override; bool IsPresent() const override;
bool IsInterruptSet() override; bool IsInterruptSet() override;

View File

@ -18,7 +18,7 @@ class CEXIMic : public IEXIDevice
{ {
public: public:
CEXIMic(Core::System& system, const int index); CEXIMic(Core::System& system, const int index);
~CEXIMic() override; virtual ~CEXIMic();
void SetCS(int cs) override; void SetCS(int cs) override;
bool IsInterruptSet() override; bool IsInterruptSet() override;
bool IsPresent() const override; bool IsPresent() const override;

View File

@ -33,7 +33,7 @@ class CEXIModem : public IEXIDevice
{ {
public: public:
CEXIModem(Core::System& system, ModemDeviceType type); CEXIModem(Core::System& system, ModemDeviceType type);
~CEXIModem() override; virtual ~CEXIModem();
void SetCS(int cs) override; void SetCS(int cs) override;
bool IsPresent() const override; bool IsPresent() const override;
bool IsInterruptSet() override; bool IsInterruptSet() override;
@ -136,13 +136,13 @@ private:
TAPServerNetworkInterface(CEXIModem* modem_ref, const std::string& destination); TAPServerNetworkInterface(CEXIModem* modem_ref, const std::string& destination);
public: public:
bool Activate() override; virtual bool Activate() override;
void Deactivate() override; virtual void Deactivate() override;
bool IsActivated() override; virtual bool IsActivated() override;
bool SendAndRemoveAllHDLCFrames(std::string* send_buffer) override; virtual bool SendAndRemoveAllHDLCFrames(std::string* send_buffer) override;
bool RecvInit() override; virtual bool RecvInit() override;
void RecvStart() override; virtual void RecvStart() override;
void RecvStop() override; virtual void RecvStop() override;
private: private:
TAPServerConnection m_tapserver_if; TAPServerConnection m_tapserver_if;

View File

@ -12,10 +12,6 @@
#include <mgba/core/timing.h> #include <mgba/core/timing.h>
#include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/gb.h>
#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/gba.h>
#include <mz.h>
#include <mz_strm.h>
#include <mz_zip.h>
#include <mz_zip_rw.h>
#include "AudioCommon/AudioCommon.h" #include "AudioCommon/AudioCommon.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
@ -92,26 +88,21 @@ static VFile* OpenROM_Archive(const char* path)
static VFile* OpenROM_Zip(const char* path) static VFile* OpenROM_Zip(const char* path)
{ {
VFile* vf{}; VFile* vf{};
void* zip_reader = mz_zip_reader_create(); unzFile zip = unzOpen(path);
if (!zip_reader) if (!zip)
return {};
Common::ScopeGuard file_guard{[&] { mz_zip_reader_delete(&zip_reader); }};
if (mz_zip_reader_open_file(zip_reader, path) != MZ_OK)
return nullptr; return nullptr;
do do
{ {
mz_zip_file* info; unz_file_info info{};
if (mz_zip_reader_entry_get_info(zip_reader, &info) != MZ_OK || !info->uncompressed_size) if (unzGetCurrentFileInfo(zip, &info, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK ||
!info.uncompressed_size)
continue; continue;
std::vector<u8> buffer(info->uncompressed_size); std::vector<u8> buffer(info.uncompressed_size);
if (!Common::ReadFileFromZip(zip_reader, &buffer)) if (!Common::ReadFileFromZip(zip, &buffer))
continue; continue;
vf = VFileMemChunk(buffer.data(), info->uncompressed_size); vf = VFileMemChunk(buffer.data(), info.uncompressed_size);
if (mCoreIsCompatible(vf) == mPLATFORM_GBA) if (mCoreIsCompatible(vf) == mPLATFORM_GBA)
{ {
vf->seek(vf, 0, SEEK_SET); vf->seek(vf, 0, SEEK_SET);
@ -120,7 +111,8 @@ static VFile* OpenROM_Zip(const char* path)
vf->close(vf); vf->close(vf);
vf = nullptr; vf = nullptr;
} while (mz_zip_reader_goto_next_entry(zip_reader) != MZ_END_OF_LIST); } while (unzGoToNextFile(zip) == UNZ_OK);
unzClose(zip);
return vf; return vf;
} }

View File

@ -24,7 +24,7 @@ class GCMemcardDirectory : public MemoryCardBase
public: public:
GCMemcardDirectory(const std::string& directory, ExpansionInterface::Slot slot, GCMemcardDirectory(const std::string& directory, ExpansionInterface::Slot slot,
const Memcard::HeaderData& header_data, u32 game_id); const Memcard::HeaderData& header_data, u32 game_id);
~GCMemcardDirectory() override; ~GCMemcardDirectory();
GCMemcardDirectory(const GCMemcardDirectory&) = delete; GCMemcardDirectory(const GCMemcardDirectory&) = delete;
GCMemcardDirectory& operator=(const GCMemcardDirectory&) = delete; GCMemcardDirectory& operator=(const GCMemcardDirectory&) = delete;

View File

@ -19,7 +19,7 @@ class MemoryCard : public MemoryCardBase
public: public:
MemoryCard(const std::string& filename, ExpansionInterface::Slot card_slot, MemoryCard(const std::string& filename, ExpansionInterface::Slot card_slot,
u16 size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_2043); u16 size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_2043);
~MemoryCard() override; ~MemoryCard();
void FlushThread(); void FlushThread();
void MakeDirty(); void MakeDirty();

View File

@ -39,7 +39,7 @@ class ConstantHandlingMethod : public ReadHandlingMethod<T>
{ {
public: public:
explicit ConstantHandlingMethod(T value) : value_(value) {} explicit ConstantHandlingMethod(T value) : value_(value) {}
~ConstantHandlingMethod() override = default; virtual ~ConstantHandlingMethod() = default;
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
{ {
v.VisitConstant(value_); v.VisitConstant(value_);
@ -62,7 +62,7 @@ class NopHandlingMethod : public WriteHandlingMethod<T>
{ {
public: public:
NopHandlingMethod() {} NopHandlingMethod() {}
~NopHandlingMethod() override = default; virtual ~NopHandlingMethod() = default;
void AcceptWriteVisitor(WriteHandlingMethodVisitor<T>& v) const override { v.VisitNop(); } void AcceptWriteVisitor(WriteHandlingMethodVisitor<T>& v) const override { v.VisitNop(); }
}; };
template <typename T> template <typename T>
@ -79,7 +79,7 @@ class DirectHandlingMethod : public ReadHandlingMethod<T>, public WriteHandlingM
{ {
public: public:
DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {} DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {}
~DirectHandlingMethod() override = default; virtual ~DirectHandlingMethod() = default;
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
{ {
v.VisitDirect(addr_, mask_); v.VisitDirect(addr_, mask_);
@ -122,7 +122,7 @@ public:
{ {
} }
~ComplexHandlingMethod() override = default; virtual ~ComplexHandlingMethod() = default;
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
{ {
v.VisitComplex(&read_lambda_); v.VisitComplex(&read_lambda_);

View File

@ -21,7 +21,7 @@ class CSIDevice_GBAEmu final : public ISIDevice
{ {
public: public:
CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number); CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number);
~CSIDevice_GBAEmu() override; ~CSIDevice_GBAEmu();
int RunBuffer(u8* buffer, int request_length) override; int RunBuffer(u8* buffer, int request_length) override;
int TransferInterval() override; int TransferInterval() override;

View File

@ -311,7 +311,7 @@ void EmulateIMUCursor(IMUCursorState* state, ControllerEmu::IMUCursor* imu_ir_gr
const auto ang_vel = imu_gyroscope_group->GetState(); const auto ang_vel = imu_gyroscope_group->GetState();
// Reset if pointing is disabled or we have no gyro data. // Reset if pointing is disabled or we have no gyro data.
if (!imu_ir_group->enabled.GetValue() || !ang_vel.has_value()) if (!imu_ir_group->enabled || !ang_vel.has_value())
{ {
*state = {}; *state = {};
return; return;

View File

@ -120,7 +120,7 @@ protected:
using EncryptedExtension::EncryptedExtension; using EncryptedExtension::EncryptedExtension;
private: private:
void UpdateEncryptionKey() final; void UpdateEncryptionKey() final override;
}; };
class Extension3rdParty : public EncryptedExtension class Extension3rdParty : public EncryptedExtension
@ -129,7 +129,7 @@ protected:
using EncryptedExtension::EncryptedExtension; using EncryptedExtension::EncryptedExtension;
private: private:
void UpdateEncryptionKey() final; void UpdateEncryptionKey() final override;
}; };
} // namespace WiimoteEmu } // namespace WiimoteEmu

View File

@ -497,7 +497,7 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
// Calculate IR camera state. // Calculate IR camera state.
if (m_ir_passthrough->enabled.GetValue()) if (m_ir_passthrough->enabled)
{ {
target_state->camera_points = GetPassthroughCameraPoints(m_ir_passthrough); target_state->camera_points = GetPassthroughCameraPoints(m_ir_passthrough);
} }

View File

@ -137,7 +137,7 @@ public:
static constexpr const char* SIDEWAYS_OPTION = "Sideways Wiimote"; static constexpr const char* SIDEWAYS_OPTION = "Sideways Wiimote";
explicit Wiimote(unsigned int index); explicit Wiimote(unsigned int index);
~Wiimote() override; ~Wiimote();
std::string GetName() const override; std::string GetName() const override;

View File

@ -34,7 +34,7 @@ class WiimoteScannerHidapi final : public WiimoteScannerBackend
{ {
public: public:
WiimoteScannerHidapi(); WiimoteScannerHidapi();
~WiimoteScannerHidapi() override; ~WiimoteScannerHidapi();
bool IsReady() const override; bool IsReady() const override;
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override; void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
void Update() override {} // not needed for hidapi void Update() override {} // not needed for hidapi

View File

@ -233,7 +233,7 @@ class HotkeyManager : public ControllerEmu::EmulatedController
{ {
public: public:
HotkeyManager(); HotkeyManager();
~HotkeyManager() override; ~HotkeyManager();
void GetInput(HotkeyStatus* hk, bool ignore_focus); void GetInput(HotkeyStatus* hk, bool ignore_focus);
std::string GetName() const override; std::string GetName() const override;

View File

@ -479,7 +479,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
if (!Core::IsRunning(system)) if (!Core::IsRunning(system))
return BootstrapPPC(); return BootstrapPPC();
AchievementManager::GetInstance().LoadGame(nullptr); INFO_LOG_FMT(ACHIEVEMENTS,
"WAD and NAND formats not currently supported by Achievement Manager.");
AchievementManager::GetInstance().CloseGame();
core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event); core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event);
core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event); core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);

View File

@ -234,7 +234,7 @@ public:
ESDevice(ESDevice&& other) = delete; ESDevice(ESDevice&& other) = delete;
ESDevice& operator=(const ESDevice& other) = delete; ESDevice& operator=(const ESDevice& other) = delete;
ESDevice& operator=(ESDevice&& other) = delete; ESDevice& operator=(ESDevice&& other) = delete;
~ESDevice() override; ~ESDevice();
static void InitializeEmulationState(CoreTiming::CoreTimingManager& core_timing); static void InitializeEmulationState(CoreTiming::CoreTimingManager& core_timing);
static void FinalizeEmulationState(); static void FinalizeEmulationState();

View File

@ -117,7 +117,7 @@ class FSDevice final : public EmulationDevice
{ {
public: public:
FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name); FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name);
~FSDevice() override; ~FSDevice();
void DoState(PointerWrap& p) override; void DoState(PointerWrap& p) override;

View File

@ -23,7 +23,7 @@ class HostFileSystem final : public FileSystem
{ {
public: public:
HostFileSystem(const std::string& root_path, std::vector<NandRedirect> nand_redirects = {}); HostFileSystem(const std::string& root_path, std::vector<NandRedirect> nand_redirects = {});
~HostFileSystem() override; ~HostFileSystem();
void DoState(PointerWrap& p) override; void DoState(PointerWrap& p) override;

Some files were not shown because too many files have changed in this diff Show More