From 2f466dae11784b710f748845e9a5b955945682f6 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Wed, 4 Sep 2024 23:11:10 +0200 Subject: [PATCH] Work with SDL as subtree --- .github/workflows/build.yml | 6 +- src/backend/core/mmio/Audio.cpp | 56 +++++++++------- src/backend/core/mmio/Audio.hpp | 4 +- src/backend/core/mmio/CMakeLists.txt | 5 +- .../core/registers/cop/cop1instructions.cpp | 10 +-- src/frontend/CMakeLists.txt | 15 +++-- src/frontend/EmuThread.cpp | 65 ++++++++----------- src/frontend/EmuThread.hpp | 4 +- 8 files changed, 78 insertions(+), 87 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1e54cfd0..d465904c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: run: | sudo add-apt-repository universe sudo apt-get update -qq - sudo apt-get install -y clang build-essential libgtk-3-dev libsdl2-dev git ninja-build qt6-base-dev + sudo apt-get install -y clang build-essential libgtk-3-dev git ninja-build qt6-base-dev sudo apt-get install -y vulkan-tools libvulkan1 libvulkan-dev vulkan-utility-libraries-dev spirv-tools - name: Build Kaizen run: | @@ -36,9 +36,6 @@ jobs: - uses: actions/checkout@master with: submodules: recursive - - name: Setup dependencies - run: | - vcpkg install sdl2[vulkan]:x64-windows - name: Setup Qt uses: jurplel/install-qt-action@v3 with: @@ -54,7 +51,6 @@ jobs: cp build/src/frontend/Release/kaizen-qt.exe upload mkdir upload/resources cp resources/* upload/resources - cp build/src/frontend/Release/SDL2.dll upload windeployqt --dir upload upload/kaizen-qt.exe - name: Upload artifacts uses: actions/upload-artifact@master diff --git a/src/backend/core/mmio/Audio.cpp b/src/backend/core/mmio/Audio.cpp index 32a48b76..2eb12a4f 100644 --- a/src/backend/core/mmio/Audio.cpp +++ b/src/backend/core/mmio/Audio.cpp @@ -1,22 +1,23 @@ #include -#include +#include +#include #include namespace n64 { #define AUDIO_SAMPLE_RATE 44100 -#define SYSTEM_SAMPLE_FORMAT AUDIO_F32SYS +#define SYSTEM_SAMPLE_FORMAT SDL_AUDIO_F32 #define SYSTEM_SAMPLE_SIZE 4 #define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE) -void audioCallback(void *user, Uint8 *stream, int length) { - auto audioDevice = (AudioDevice *)user; +void audioCallback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount) { + auto audioDevice = (AudioDevice *)userdata; int gotten = 0, available = 0; if (audioDevice) { audioDevice->LockMutex(); - available = SDL_AudioStreamAvailable(audioDevice->GetStream()); + available = SDL_GetAudioStreamAvailable(audioDevice->GetStream()); if (available > 0) { - gotten = SDL_AudioStreamGet(audioDevice->GetStream(), stream, length); + gotten = SDL_GetAudioStreamData(audioDevice->GetStream(), stream, total_amount); } audioDevice->UnlockMutex(); } @@ -25,7 +26,7 @@ void audioCallback(void *user, Uint8 *stream, int length) { auto *out = (float *)stream; out += gottenSamples; - for (int i = gottenSamples; i < length / sizeof(float); i++) { + for (int i = gottenSamples; i < total_amount / sizeof(float); i++) { float sample = 0; *out++ = sample; } @@ -33,35 +34,33 @@ void audioCallback(void *user, Uint8 *stream, int length) { AudioDevice::~AudioDevice() { LockMutex(); - SDL_FreeAudioStream(GetStream()); + SDL_DestroyAudioStream(GetStream()); UnlockMutex(); SDL_DestroyMutex(audioStreamMutex); } -AudioDevice::AudioDevice() : - audioStream( - SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE)), - audioStreamMutex(SDL_CreateMutex()) { +AudioDevice::AudioDevice() : audioStreamMutex(SDL_CreateMutex()) { + request.freq = AUDIO_SAMPLE_RATE; + request.format = SYSTEM_SAMPLE_FORMAT; + request.channels = 2; + + audioStream = SDL_CreateAudioStream(&request, &request); + SDL_InitSubSystem(SDL_INIT_AUDIO); if (!audioStreamMutex) { Util::panic("Unable to initialize audio mutex: {}", SDL_GetError()); } - request.freq = AUDIO_SAMPLE_RATE; - request.format = SYSTEM_SAMPLE_FORMAT; - request.channels = 2; - request.samples = 1024; - request.callback = audioCallback; - request.userdata = (void *)this; - - handle = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); + handle = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &request); + SDL_BindAudioStream(handle, audioStream); + SDL_SetAudioStreamGetCallback(audioStream, audioCallback, this); if (!handle) { Util::panic("Failed to initialize SDL Audio: {}", SDL_GetError()); } - SDL_PauseAudioDevice(handle, false); + SDL_PauseAudioDevice(handle); } void AudioDevice::PushSample(float left, float volumeL, float right, float volumeR) { @@ -69,16 +68,23 @@ void AudioDevice::PushSample(float left, float volumeL, float right, float volum float adjustedR = right * volumeR; float samples[2]{adjustedL, adjustedR}; - auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream); + auto availableBytes = (float)SDL_GetAudioStreamAvailable(audioStream); if (availableBytes <= BYTES_PER_HALF_SECOND) { - SDL_AudioStreamPut(audioStream, samples, 2 * sizeof(float)); + SDL_PutAudioStreamData(audioStream, samples, 2 * sizeof(float)); } } void AudioDevice::AdjustSampleRate(int sampleRate) { LockMutex(); - SDL_FreeAudioStream(audioStream); - audioStream = SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE); + SDL_DestroyAudioStream(audioStream); + + auto oldReq = request; + + request.freq = sampleRate; + request.format = SYSTEM_SAMPLE_FORMAT; + request.channels = 2; + + audioStream = SDL_CreateAudioStream(&request, &oldReq); UnlockMutex(); } } // namespace n64 diff --git a/src/backend/core/mmio/Audio.hpp b/src/backend/core/mmio/Audio.hpp index 9fdbd6f4..41bb5a40 100644 --- a/src/backend/core/mmio/Audio.hpp +++ b/src/backend/core/mmio/Audio.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace n64 { struct AudioDevice { @@ -22,7 +22,7 @@ struct AudioDevice { private: SDL_AudioStream *audioStream; - SDL_mutex *audioStreamMutex; + SDL_Mutex *audioStreamMutex; SDL_AudioSpec audioSpec{}; SDL_AudioSpec request{}; SDL_AudioDeviceID handle{}; diff --git a/src/backend/core/mmio/CMakeLists.txt b/src/backend/core/mmio/CMakeLists.txt index a5ec7c7e..0a02854f 100644 --- a/src/backend/core/mmio/CMakeLists.txt +++ b/src/backend/core/mmio/CMakeLists.txt @@ -1,7 +1,4 @@ file(GLOB_RECURSE SOURCES *.cpp) file(GLOB_RECURSE HEADERS *.hpp) -find_package(SDL2 CONFIG REQUIRED) - -add_library(mmio ${SOURCES} ${HEADERS} ../../../../external/cic_nus_6105/n64_cic_nus_6105.cpp) -target_link_libraries(mmio PRIVATE SDL2::SDL2) \ No newline at end of file +add_library(mmio ${SOURCES} ${HEADERS} ../../../../external/cic_nus_6105/n64_cic_nus_6105.cpp) \ No newline at end of file diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 5c23c824..dbb4783e 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -144,7 +144,7 @@ bool Cop1::isqnan(double f) { template <> bool Cop1::CheckCVTArg(float &f) { - switch (fpclassify(f)) { + switch (std::fpclassify(f)) { case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: @@ -164,7 +164,7 @@ bool Cop1::CheckCVTArg(float &f) { template <> bool Cop1::CheckCVTArg(double &f) { - switch (fpclassify(f)) { + switch (std::fpclassify(f)) { case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: @@ -184,7 +184,7 @@ bool Cop1::CheckCVTArg(double &f) { template <> bool Cop1::CheckCVTArg(float &f) { - switch (fpclassify(f)) { + switch (std::fpclassify(f)) { case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: @@ -204,7 +204,7 @@ bool Cop1::CheckCVTArg(float &f) { template <> bool Cop1::CheckCVTArg(double &f) { - switch (fpclassify(f)) { + switch (std::fpclassify(f)) { case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: @@ -224,7 +224,7 @@ bool Cop1::CheckCVTArg(double &f) { template bool Cop1::CheckArg(T &f) { - switch (fpclassify(f)) { + switch (std::fpclassify(f)) { case FP_SUBNORMAL: SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt index 56676514..29f6821e 100644 --- a/src/frontend/CMakeLists.txt +++ b/src/frontend/CMakeLists.txt @@ -5,11 +5,10 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) -find_package(SDL2 CONFIG REQUIRED) -if(WIN32) +if (WIN32) add_compile_definitions(NOMINMAX) -endif() +endif () include_directories( . @@ -36,7 +35,7 @@ include_directories( ../../external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include ../../external/parallel-rdp/parallel-rdp-standalone/util ../../external/unarr - ${SDL2_INCLUDE_DIRS} + ../../external/SDL/include ) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF) @@ -51,6 +50,8 @@ add_subdirectory(../../external/mio mio) add_subdirectory(../backend backend) add_subdirectory(../../external/parallel-rdp parallel-rdp) add_subdirectory(../../external/unarr unarr) +add_subdirectory(../../external/SDL SDL) + set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) @@ -86,13 +87,13 @@ if (HAS_SSE4_1) target_compile_options(kaizen-qt PUBLIC -msse3 -msse4.1) endif () -if(${CMAKE_BUILD_TYPE} MATCHES Debug) +if (${CMAKE_BUILD_TYPE} MATCHES Debug) target_compile_definitions(kaizen-qt PUBLIC VULKAN_DEBUG) #target_compile_options(kaizen-qt PUBLIC -fsanitize=address -fsanitize=undefined) #target_link_options(kaizen-qt PUBLIC -fsanitize=address -fsanitize=undefined) -endif() +endif () -target_link_libraries(kaizen-qt PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets discord-rpc fmt mio nlohmann_json parallel-rdp backend) +target_link_libraries(kaizen-qt PUBLIC SDL3::SDL3 SDL3::SDL3-static Qt6::Core Qt6::Gui Qt6::Widgets discord-rpc fmt mio nlohmann_json parallel-rdp backend) target_compile_definitions(kaizen-qt PUBLIC SDL_MAIN_HANDLED) file(COPY ../../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/) diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 552c7669..d13e4bdd 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -1,5 +1,5 @@ #include -#include +#include EmuThread::EmuThread(const std::shared_ptr &instance_, const std::shared_ptr &wsiPlatform_, @@ -8,10 +8,10 @@ EmuThread::EmuThread(const std::shared_ptr &instance_, [[noreturn]] void EmuThread::run() noexcept { parallel.Init(instance, wsiPlatform, windowInfo, core.cpu->GetMem().GetRDRAMPtr()); - SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + SDL_InitSubSystem(SDL_INIT_GAMEPAD); bool controllerConnected = false; - if (SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { + if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { Util::warn("[SDL] Could not load game controller DB"); } @@ -19,24 +19,24 @@ EmuThread::EmuThread(const std::shared_ptr &instance_, SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { - case SDL_CONTROLLERDEVICEADDED: + case SDL_EVENT_GAMEPAD_ADDED: { - const int index = e.cdevice.which; - controller = SDL_GameControllerOpen(index); + const int index = e.gdevice.which; + controller = SDL_OpenGamepad(index); Util::info("Found controller!"); - auto serial = SDL_GameControllerGetSerial(controller); - auto name = SDL_GameControllerName(controller); - auto path = SDL_GameControllerPath(controller); + auto serial = SDL_GetGamepadSerial(controller); + auto name = SDL_GetGamepadName(controller); + auto path = SDL_GetGamepadPath(controller); Util::info("\tName: {}", name ? name : "Not available"); Util::info("\tSerial: {}", serial ? serial : "Not available"); Util::info("\tPath: {}", path ? path : "Not available"); controllerConnected = true; } break; - case SDL_CONTROLLERDEVICEREMOVED: + case SDL_EVENT_GAMEPAD_REMOVED: { controllerConnected = false; - SDL_GameControllerClose(controller); + SDL_CloseGamepad(controller); } break; } @@ -59,43 +59,34 @@ EmuThread::EmuThread(const std::shared_ptr &instance_, if (controllerConnected) { n64::PIF &pif = core.cpu->GetMem().mmio.si.pif; - pif.UpdateButton(0, n64::Controller::Key::A, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)); - pif.UpdateButton(0, n64::Controller::Key::B, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)); + pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_SOUTH)); + pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_WEST)); pif.UpdateButton(0, n64::Controller::Key::Z, - SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX); - pif.UpdateButton(0, n64::Controller::Key::Start, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)); - pif.UpdateButton(0, n64::Controller::Key::DUp, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)); - pif.UpdateButton(0, n64::Controller::Key::DDown, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)); - pif.UpdateButton(0, n64::Controller::Key::DLeft, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)); + SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX); + pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_START)); + pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_UP)); + pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_DOWN)); + pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_LEFT)); pif.UpdateButton(0, n64::Controller::Key::DRight, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)); - pif.UpdateButton(0, n64::Controller::Key::LT, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)); + SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); + pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)); pif.UpdateButton(0, n64::Controller::Key::RT, - SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::CUp, - SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CDown, - SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) >= 127); - pif.UpdateButton(0, n64::Controller::Key::CLeft, - SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CRight, - SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) >= 127); + SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) >= 127); + pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) >= 127); - float xclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); + float xclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX); if (xclamped < 0) { - xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); + xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX)); } else { xclamped /= SDL_JOYSTICK_AXIS_MAX; } xclamped *= 86; - float yclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + float yclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY); if (yclamped < 0) { yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); } else { diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 3e36c98e..982f806f 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -20,7 +20,7 @@ public: [[noreturn]] void run() noexcept override; - SDL_GameController *controller = nullptr; + SDL_Gamepad *controller = nullptr; ParallelRDP parallel; n64::Core core; SettingsWindow &settings;